-1

I have a working program where the view model feed the data to the view. This is done in the constructor and also in a Refresh() method, as shown below. I usually put a private property referring to the view model because I want to omit casting when communicating with it.

public class TheView
{
  private ViewModel TheViewModel { get; set; }

  public TheView()
  {
    TheViewModel = new ViewModel();
    DataContext = TheViewModel;
  }

  public Refresh()
  {
    TheViewModel = new ViewModel();
    DataContext = TheViewModel;
  }
}

Then, I got gready and started chasing lines. Since the constructor connects DataContext to the property TheViewModel, I figured I could just assign to the latter and the former would get it's stuff updated by itself. To my disappointment, I discovered that it wasn't so. The following get me the correct list of objects but the DataContext stays unaffected.

public class TheView
{
  private ViewModel TheViewModel { get; set; }

  public TheView()
  {
    TheViewModel = new ViewModel();
    DataContext = TheViewModel;
  }

  public Refresh() { TheViewModel = new ViewModel(); }
}

The question is why it is so. Or rather, if it's supposed to be so. I'm thinking, in case it isn't supposed to behave like this, perhaps I have issues elsewhere in the code that poofs the flow...

Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438

2 Answers2

2

I think you do need understand that DataContext is a dependency property.

Its definition looks like this:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Localizability(LocalizationCategory.NeverLocalize)]
public object DataContext
{
  get
  {
    return this.GetValue(FrameworkElement.DataContextProperty);
  }
  set
  {
    this.SetValue(FrameworkElement.DataContextProperty, value);
  }
}

...

    public static readonly DependencyProperty DataContextProperty = 
DependencyProperty.Register("DataContext", typeof (object...

Dependency properties are more than normal .NET properties because they support

  • change notification
  • property value inheritance
  • providers which determine the value

In your case it is the "change notification" topic which is important.

When you (re-) assign a value to a property which is a dependency property (like DataContext) then WPF will pick up this change automatically. In this case the change notifcation is done inside the setter of the dependency property so to speak.

If you assign to a "normal" property or even a private field this is not the case (the setter of the DataContext property is not invoked) even if it points to a DataContext.

Martin
  • 5,165
  • 1
  • 37
  • 50
  • Oh, right! I'm using *OnPropertyChanged* for the properties that are **inside** the view model instance. I didn't think of the view model **itself** as changeable thingy that needed notifying. Now I can sleep well again. Thanks! – Konrad Viltersten Sep 30 '15 at 14:15
  • Just a side note - any idea what could be improved in the question? I got two downvotes and can't really see why... – Konrad Viltersten Sep 30 '15 at 14:16
  • It's a good point, Martin, but it is perhaps worth noting it is the source of the problem _only_ if he made his binding to `TheViewModel` instead of using the implicit source of `DataContext`. Apparently it's the case :) – Fabio Salvalai Sep 30 '15 at 14:19
  • @Konrad: my guess is the people who downvoted your question thought it was a very basic OOP question, where in fact it was more about DependencyProperty / NotifyPropertyChanged. If you had put the part of your XAML with the binding, they wouldn't have drawn that conclusion. In any case, downvoting the question was pretty harsh IMO, especially without bothering to comment. don't worry. – Fabio Salvalai Sep 30 '15 at 14:25
  • 1
    @Konrad: I not sure whether the downvoters really understood your problem. I guess they simply thought "One does not assign the DataContext in that way", but did not know the exact reason for this. – Martin Sep 30 '15 at 15:48
1

You are basically re-assigning a private property, not the DataContext.

  1. you create instance A of TheViewModel
  2. you make the DataContext point to instance A
  3. you create instance B of TheViewModel
  4. you make the TheViewModel private property point to instance B
  5. DataContext is still pointing to instance A

--> there is no reason why the DataContext should be refreshed. you didn't touch it. it's still pointing to the initial instance A, which is still in memory.

EDIT:

That answer was assuming the binding was using DataContext as a source, and not TheViewModel. DataContext is a DependencyProperty, whereas TheViewModel isn't. Replacing the whole view model with TheViewModel as a binding source needs to notify the view either with a dependency property or NotifyPropertyChanged

Community
  • 1
  • 1
Fabio Salvalai
  • 2,479
  • 17
  • 30
  • But those are objects, so we're talking about references, not values. SO I figured, if *DataContext* points to the same memory part as *TheViewModel*, it shouldn't matter... What am I missing? – Konrad Viltersten Sep 30 '15 at 13:32
  • Precisely. You overwrite the reference pointing to instance A with the reference to instance B, in the property, but *not* on the data context. It's still pointing to the same place as before.I – Fabio Salvalai Sep 30 '15 at 13:34