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

The following 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 the 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")); } ... 
+4
source share
3 answers

Here is my hunch. In both cases, at one point, your collection is null. Right after the InitializeComponent. At this point, the original data binding received data, but not datocontext. Now, by setting the DataContext, your property will be raised, and every attachment associated with it becomes invalid and updated. Here is my part of the hunch, the reason it works is because the binding to ItemsSource is delayed, so it works just to set the collection on the next line.

In short: setting the datacontext will re-bind. But in your RelativeSource example, your binding worked from the very beginning, but the collection was zero, and you never told wpf about restoring the binding. If you directly initialize your collection, it should work fine.

+1
source

I suspect this is due to how and when certain types of bindings are evaluated. In the latter case, I believe that the binding can get the value of the collection property while it is still null, then you change the property (by setting the field) without generating any change notification for the affected property.

We recommend moving the call to InitializeComponent to the end of the constructor, or at least setting the field in advance.

Usually I use only the readonly field and immediately initialize it:

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

Actually, the binding is correct, and it also works. To refresh the screen, the binding must receive notifications that something has changed. The binding evaluates and then listens for notifications. In the second version, the binding is first evaluated when the InitializeComponent starts, but at this point there are no values, so you can’t see anything. After that, the values ​​are created, but the binding is not reevaluated, since the items are not sent.

So yes, one solution would be to initialize the collection before InitializeComponent.

 ... private ObservableCollection<SimpleRow> simpleItems = new ObservableCollection<SimpleRow>(); ... 

Another solution would be stupid and redundant to notify the binding that something has changed.

Just notice, probably this is for training purposes, because the user interface should not be mixed with the model.

0
source

Source: https://habr.com/ru/post/1501427/


All Articles