WPF INotifyPropertyChanged两种方式绑定奇怪的动作

时间:2019-03-28 04:17:48

标签: c# wpf mvvm data-binding inotifypropertychanged

我按照许多线程的建议实施了INotifyPropertyChanged
实施1

public class Notifier : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string pName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pName));
    }
}

public class Model : Notifier, IDataErrorInfo
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; OnPropertyChanged("name_changed"); }
    }
}

viewmodel由模型和用于更改模型属性的命令组成。

public class ViewModel : Notifier
{
    private Model _model;

    public Model Model
    {
        get { return _model; }
        set { _model = value; OnPropertyChanged("model_changed"); }
    }

    private ICommand _cmd;

    public ICommand Command
    {
        get { return _cmd; }
        set { _cmd = value; }
    }

    public void ExecuteCommand(object para)
    {
        Console.WriteLine("Command executed");
        Model.Name = "new name";
    }
}

然后将VM绑定到视图。

<TextBox HorizontalAlignment="Center" VerticalAlignment="Center"  Width="100">
    <TextBox.Text>
        <Binding Path="Model.Name" Mode="TwoWay" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
            <Binding.ValidationRules>
                <ExceptionValidationRule></ExceptionValidationRule>                
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

执行命令时,TextBox不会更新为新值。
但是,如果我实现this之类的INotifyPropertyChanged指令,则绑定有效。
实施2

public class Notifier : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName]string propertyName = null)
    {
        if (!EqualityComparer<T>.Default.Equals(field, newValue))
        {
            field = newValue;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            return true;
        }
        return false;
    }
}

public class Model : Notifier, IDataErrorInfo
{
    private string name;

    public string Name
    {
        get { return name; }
        set { SetProperty(ref name, value); }
    }
}

第一种方法遗漏了什么?

2 个答案:

答案 0 :(得分:3)

实现1 的主要问题是OnPropertyChanged方法的字符串参数必须是要更改的确切属性名称。对于您的两个示例,应将"model_changed"更改为"Model" 并且"name_changed"应该读为"Name"。这是两种通过键入文字字符串名称来减轻潜在的人为错误的出色技术:

1。使用CallerMemberName属性

如果被允许并有权访问System.Runtime.CompilerServices名称空间,则可以这样编写基类,以使属性名称作为OnPropertyChanged方法的字符串参数自动传递:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class Notifier : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string pName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pName));
    }
}

然后,您只需在属性的getter中调用OnPropertyChanged()

2。使用nameof关键字

或者,您可以简单地将文字类型化的属性名称替换为nameof(<InsertPropertyNameHere>),这样将返回名称而不会产生任何混淆的风险,例如以下示例:

public class Model : Notifier, IDataErrorInfo
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; OnPropertyChanged(nameof(Name)); }
    }
} 

答案 1 :(得分:0)

请添加这样的属性名称。

public class Model : Notifier, IDataErrorInfo
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; OnPropertyChanged("Name"); }
    }
}