开发者

INotifyPropertyChanged in subclass

I want to bind a TextBox in the window to a property contained within a class that is a variable of the viewmodel and ensure that INotifyPropertyChanged's PropertyChanged event propagates from the class to the parent.

Let me illustrate with an example:

(Window's DataContext is set to an instance of ViewModel)

pub开发者_运维问答lic class ViewModel {
    private OtherClass classInstance = new OtherClass();

    public int Attribute {
        get { return classInstance.Attribute; }
    }
}

public class OtherClass : INotifyPropertyChanged {
    private int _attribute;
    public int Attribute {
        get { return _attribute; }
        set { 
            _attribute = value;
            PropertyChanged("Attribute");
        }
    }
    ...
}

The problem in this example is that, when Attribute changes, the bound Textbox does not update the binding since I assume it's listening to the ViewModel's PropertyChanged event and not that of the instance of OtherClass.

Any ideas on how to remedy this situation? I was thinking about chaining OtherClass's INotifyPropertyChanged to that of its parent, but there has to be a better way.


Why not bind directly to the class property instead of using a proxy?

public class ViewModel {
    private OtherClass classInstance = new OtherClass();

    public OtherClass MyOtherClass {
        get { return classInstance; }
    }
}

Then in your binding you can simply reference the property via the SubClass

{Binding MyOtherClass.Attribute}

A drop dead simple example, but it works!

The Code Behind:

public partial class MainWindow : Window {
   private readonly SomeClass _someClass = new SomeClass();

   public MainWindow() {
      InitializeComponent();
      DataContext = _someClass;
   }
}

public class SomeClass: INotifyPropertyChanged {      
   private readonly SomeSubClass _mySubClass = new SomeSubClass();

   public SomeSubClass MySubClass {
      get { return _mySubClass; }
   }

   private String _name;
   public String Name {
      get { return _name; }
      set {
         _name = value;
         OnPropertyChanged("Name");
      }
   }

   //Property Change Stuff
}

public class SomeSubClass : INotifyPropertyChanged {
   private String _name;
   public String Name {
      get {
         return _name;
      }
      set {
         _name = value;
         OnPropertyChanged("Name");
      }
   }

   //Property Change Stuff
}

The XAML:

<Window x:Class="JWC.Examples.WPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow">
    <StackPanel>
        <Label Content="Name" VerticalAlignment="Top" />
        <TextBox Text="{Binding Name}" />
        <Label Content="SubClass.Name" />
        <TextBox Text="{Binding MySubClass.Name}" />
        <Label Content="Bound to Name" />
        <TextBlock Text="{Binding Name}" />
        <Label Content="Bound to MySubClass.Name" />
        <TextBlock Text="{Binding MySubClass.Name}" />
    </StackPanel>
</Window>


You will need to do something like this:

public class ViewModel {
   public ViewModel() {
      classInstance = new OtherClass();
      classInstance.PropertyChanged += HandleAttributeChanged; 
   }

   private void HandleAttributeChanged(object Sender, NotifyPropertyChangedEventArgs args) {
      PropertyChanged("Attribute");
   }
}

I don't show it here, but you should also implement IDisposable and unsubscribe from the PropertyChanged event on your child, otherwise you will leak memory.

Alternatively you can expose the classInstance as a public property and set your binding to: ViewModel.classInstance. Note this needs to be a property and not the field itself.


I think the parent class should subscribe to the child propertyCahnged event..something like:

public class ViewModel
{
    private OtherClass classInstance = new OtherClass();

    public ViewModel()
    {
        classInstance.PropertyChanged += NotifyChildAttributeChanged;
    }
    public int Attribute
    {
        get { return classInstance.Attribute; }
    }
} 

NotifyChildAttributeChanged is basically a method that listens only to the "Attribute" property and fires a PropertyChanged notification of its own..

Of course our parent class must implement INotifyPropertyChanged as well as will all ViewModels (preferably) and your DataContext will detect the change.


To get around this you need to implement INotifyPropertyChanged on your view model as well. Just add the interface and the event and the rest will take care of itself - no need to chain the events / calls together.

Check out this for using reflection to get the property as well.

http://tsells.wordpress.com/2011/02/08/using-reflection-with-wpf-and-the-inotifypropertychanged-interface/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜