简体   繁体   中英

WPF MVVM Binding nested property

I'm creating an application where users can edit master data of a child, and I'm trying to create a seamless experience for the user by saving the changes they've made to the child for them.

I have a model called Child.

class Child
{
    [Key]
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string Surname { get; set; }
}

I have a view (ChildMasterDataView) that display's the FirstName and Surname in textboxes that are editable.

<!--First name-->
<Label Content="First name:" />
<TextBox Text="{Binding Path=Child.FirstName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

<!--Surname-->
<Label Content="Surname:" />
<TextBox Text="{Binding Path=Child.Surname, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

I have a class which handles the implementation of the INotifyPropertyChanged interface.

public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChangedEvent(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

I have a ViewModel which is supposed to save the changes made to the Firstname and Surname, when the respective property is changed. The problem is that the Firstname and Surname are nested properties of the Child class, and aren't firing the PropertyChanged event...

class ChildMasterDataViewModel : ObservableObject
{
    private Database db; // Database context

    public ChildViewModel()
    {
        db = new Database();
        Child = db.Children.ToList().Where(e => e.PlbNr == 1).FirstOrDefault(); // Won't be null because child has been chosen earlier

        PropertyChanged += ChildPropertyChanged;
    }

    private Child child;
    public Child Child
    {
        get { return child; }
        set { child = value; RaisePropertyChangedEvent("Child"); }
    }

    private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        db.SaveChanges();
    }
}

I can accomplish what I want by making the following changes to the ViewModel (and ofc changing the view binding):

class ChildMasterDataViewModel : ObservableObject
{
    private Database db; // Database context
    private Child child;

    public ChildViewModel()
    {
        db = new Database();
        child = db.Children.ToList().Where(e => e.PlbNr == 1).FirstOrDefault(); // Won't be null because child has been chosen earlier

        PropertyChanged += ChildPropertyChanged;
    }

    public string FirstName
    {
        get { return child.FirstName; }
        set { child.FirstName= value; RaisePropertyChangedEvent("FirstName"); }
    }

    public string Surname
    {
        get { return child.Surname; }
        set { child.Surname= value; RaisePropertyChangedEvent("Surname"); }
    }

    private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        db.SaveChanges();
    }
}

This can't be right though, there must be a better way?

I have tried implementing ObservableObject in the Child class and then in the ViewModel subscribing the PropertyChanged event of the Child class to the ViewModel's ChildPropertyChanged method. This did not work.

Personally, I see there being no reason not to place a simple INotifyPropertyChanged implementation into your Child model - after all it has properties that are changing. Now you can bind to them directly.

By the same token, why is saving state part of your ViewModel? I would move that into the model or into a separate persistence manager. The VM is supposed to model aspects of the View that are independent of the Model.

When dependency property is starting to use binding, it try convert binding instance to INotifyPropertyChanged, and after by using "weak event" subscribe to event. So dependecy property know nothing about inner property and etc, it just try convert to INotifyPropertyChanged and suscribe to event. Next, when event wil be rise, dependency peroperty, using reflection, will be get new value (it's way to improve it, you can write your own kind of dependency property, which will be use Expression, for getting value from property)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM