0
votes

I am trying to understand how the framework's default implementation manages to have the datacontext of an itemssource item. Specifically, when a DataGrid's ItemsSource is set (to for example a collection of Foo objects) and you define your columns within the DataGrid.Columns property, the DataGridTextColumn "Binding" property is expecting a property from a Foo object.

The following code might illustrate the issue better :

public class MainWindowViewModel
{
    public List<Foo> Foos { get; }
}

public class Foo
{
    public string FooDesignation { get; }
}

My very simple viewmodel containing the collection for my DataGrid. I then wish to use my own custom columns to add to the DataGrid's column collection :

public class CustomDataGridTextColumn : DataGridTextColumn
{
    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
        nameof(Text), 
        typeof(string), 
        typeof(CustomDataGridTextColumn), 
        new PropertyMetadata(default(string)));

    public string Text
    {
        get => (string) this.GetValue(TextProperty);
        set => this.SetValue(TextProperty, value);
    }

    private Binding _textBinding;

    public Binding TextBinding
    {
        get => _textBinding;
        set => _textBinding = value;
    }

The resulting XAML looks like this (in MainWindowView the datacontext is set to an instance of MainWindowViewModel)

<d:Window.DataContext>
    <x:Type Type="local:MainWindowViewModel" />
</d:Window.DataContext>
<Grid>
    <DataGrid ItemsSource="{Binding Foos}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding FooDesignation}" />
            <local:CustomDataGridTextColumn Text="{Binding FooDesignation}" TextBinding="{Binding FooDesignation}" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>

The DataGridTextColumn's Binding property can be bound to the property of Foo (FooDesignation) without issue, intellisense also shows this property as an option.

My own CustomDataGridTextColumn's Text and TextBinding properties however, show a designtime and runtime error when bound to the same FooDesignation property. Intellisense shows me my MainWindowViewModel's Foos property as option (which makes sense as apparently it did not inherit the Foo object datacontext).

My assumption is it has something to do with the fact that DataGridTextColumn's Binding property is of type Binding, and is configured in a way to behave the way it does.

I couldn't find/understand how this is achieved. Can anyone shed some light on this? My goal would be to get the Text/*TextBinding properties to behave the same as the Binding property.

1

1 Answers

0
votes

You can set the ItemsSource to any IEnumerable and the DataGrid applies the bindings of the columns to the visual elements (controls) that gets created in the columns' GenerateElement and GenerateEditingElement methods:

    protected abstract FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem);
    protected abstract GenerateElement(DataGridCell cell, object dataItem);

As you see, these methods accept a non-typed object which is retrieved from the IEnumerable. The actual property values are resolved using reflection as with all other bindings. The columns simply apply the binding to the generated element.

If you want to create a custom column, you should inherit from DataGridBoundColumn or any its children and use the existing Binding property as-is.