簡體   English   中英

WPF INotifyPropertyChanged兩種方式綁定奇怪的動作

[英]WPF INotifyPropertyChanged two way binding strange action

我按照許多線程的建議實現了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"); }
    }
}

視圖模型由模型和用於更改模型屬性的命令組成。

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不會更新為新值。
但是,如果我像指令那樣實現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); }
    }
}

第一種方法遺漏了什么?

實現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>) ,這將返回名稱而不會造成任何nameof(<InsertPropertyNameHere>)風險,例如以下示例:

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

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

請添加這樣的屬性名稱。

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM