Difference between setting DataContext=this in constructor and Binding to {RelativeSource Self} in WPF?

andrey_t picture andrey_t · Sep 10, 2013 · Viewed 9.7k times · Source

Next code works as expected:

AskWindow.xaml:

<Window
    x:Class='AskWPF.AskWindow'
    xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
    xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
    >

<DataGrid ItemsSource="{Binding SimpleItems}" />

</Window>

AskWindow.xaml.cs:

namespace AskWPF {

public class SimpleRow {
    private string firstColumn;
    private string secondColumn;

    public SimpleRow(string first, string second) {
        firstColumn = first;
        secondColumn = second;
    }

    public string FirstColumn {
        get { return firstColumn; }
        set { firstColumn = value; }
    }

    public string SecondColumn {
        get { return secondColumn; }
        set { secondColumn = value; }
    }
}

public partial class AskWindow : Window {

    private ObservableCollection<SimpleRow> simpleItems;

    public AskWindow() {
        InitializeComponent();
        DataContext = this;

        simpleItems = new ObservableCollection<SimpleRow>();
        simpleItems.Add(new SimpleRow("row 0, column 0", "row 0, column 1"));
        simpleItems.Add(new SimpleRow("row 1, column 0", "row 1, column 1"));
    }

    public ObservableCollection<SimpleRow> SimpleItems {
        get { return simpleItems; }
    }
}

}

But if set DataContext='{Binding RelativeSource={RelativeSource Self}}' in Window tag and comment line DataContext=this we get an empty window. Why?

AskWindow.xaml:

<Window .... DataContext='{Binding RelativeSource={RelativeSource Self}}'>

    <DataGrid ItemsSource="{Binding SimpleItems}" />

</Window>

AskWindow.xaml.cs:

...
public AskWindow() {
    InitializeComponent();
    // DataContext = this;

    simpleItems = new ObservableCollection<SimpleRow>();
    simpleItems.Add(new SimpleRow("row 0, column 0", "row 0, column 1"));
    simpleItems.Add(new SimpleRow("row 1, column 0", "row 1, column 1"));
}
...

Answer

H.B. picture H.B. · Sep 10, 2013

I suspect it has to do with how and when certain kinds of bindings are evaluated. In the latter case i think that the binding may retrieve the value of the collection property while it still is null, then you change the property (by setting the field) without firing any change notification for the affected property.

Would recommend to move the InitializeComponent call to the end of the constructor or to at least set the field beforehand.

Usually i use a readonly field and just initialize it right away:

private readonly ObservableCollection<Data> collection =
    new ObservableCollection<Data>();
public ObservableCollection<Data> Collection { get { return collection ; } }