WPF INotifyPropertyChanged двухстороннее связывание странное действие - PullRequest
0 голосов
/ 28 марта 2019

Я реализовал 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";
    }
}

Затем виртуальная машина связывается с представлением.

<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); }
    }
}

Что пропущено в первом методе?

Ответы [ 2 ]

3 голосов
/ 28 марта 2019

Основная проблема с Реализация 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));
    }
}

Тогда вы можете просто позвонить 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)); }
    }
} 
0 голосов
/ 28 марта 2019

Пожалуйста, добавьте название недвижимости, как это.

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

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