订阅只读属性到 PropertyChanged 事件 mvvm

huangapple go评论82阅读模式
英文:

subscribe a read only property to the PropertyChanged event mvvm

问题

在视图模型中,有一个属性依赖于另一个属性的值:

private int _property;
public int Property
{
    get
    {
        return _property;
    }
    set
    {
        SetProperty(ref _property, value, () => Property);
    }
}
public int DependentProperty => Property + SomeLogic;

以及视图:

<TextBlock Text="{Binding DependentProperty}" />

_property 更改时,我希望更新视图。

我找到了这个问题,它说你需要订阅 PropertyPropertyChanged 事件,但我不知道如何做。

英文:

In the view model there is a property that is dependent to another property value:

        private int _property;
        public int Property
        {
            get
            {
                return _property;
            }
            set
            {
                SetProperty(ref _property, value, () =&gt; Property);
            }
        }
        public int DependentProperty =&gt; Property + SomeLogic;

and the view:

&lt;TextBlock Text=&quot;{Binding DependentProperty}&quot; /&gt;

I want to update the view when the _property changes

I found :this question
that says you have to subscribe to the PropertyChanged event of Property, but I don't know how.

答案1

得分: 1

DependentProperty 被称为计算属性。在您的情况下,通过调用 SetProperty 方法隐式触发了 INotifyPropertyChanged.PropertyChanged 事件。您所需做的就是显式为计算属性触发事件。

通常,您可能已经有一个事件激发方法的实现,该方法也在 SetProperty 方法内部使用。
例如,如果您使用 .NET Community Toolkit,您已经继承了一个 protected virtual ObservableObject.OnPropertyChanged(propertyName: string): void 方法,您可以调用该方法。

private int _property;
public int Property
{
  get => _property;
  set
  {
    // 隐式为此属性触发 PropertyChanged 事件
    // 因为 SetProperty 内部调用了 OnPropertyChanged(事件激发方法)。
    SetProperty(ref _property, value, () => Property);

    // 显式为计算属性触发 PropertyChanged 事件
    OnPropertyChanged(nameof(DependentProperty));
  }
}

public int DependentProperty => Property + SomeLogic;

当然,如果您希望避免从每个计算属性依赖的每个属性显式触发 PropertyChanged 事件,您可以观察所需的属性以进行更改:

private int _property;
public int Property
{
  get => _property;
  set => SetProperty(ref _property, value, () => Property);
}

public int DependentProperty => Property + SomeLogic;

public ViewModel()
{
  TrackDependentPropertySourceProperties();
}

private void TrackDependentPropertySourceProperties()
{
  this.PropertyChanged += OnDependentPropertySourcePropertiesChanged;
}

// 假设 DependentProperty 依赖于另外三个属性
// (使用三个来突出显示这种模式)
private void OnDependentPropertySourcePropertiesChanged(object sender, PropertyChangedEventArgs e)
{
  switch (e.PropertyName)
  {
    case nameof(Property):
    case nameof(SomeOtherProperty):
    case nameof(AThirdProperty):
      OnPropertyChanged(nameof(DependentProperty));
  }
}
英文:

The DependentProperty is called computed property. In your case the INotifyPropertyChanged.PropertyChanged event is raised implicitly by calling the SetProperty method. All you have to do is to raise the event for the computed property explicitly.

Usually you already have an event invocator method implementation that is also used internally by the SetProperty method.
For example, if you use the .NET Community Toolkit you already inherit a protected virtual ObservableObject.OnPropertyChanged(propertyName: string):void method that you can call.

private int _property;
public int Property
{
  get =&gt; _property;
  set
  {
    // Implicitly raises the PropertyChanged event for this property
    // because SetProperty is calling OnPropertyChanged (event invocator method) internally.
    SetProperty(ref _property, value, () =&gt; Property);

    // Raise the PropertyChanged event explicitly for the computed property
    OnPropertyChanged(nameof(DependentProperty));
  }
}

public int DependentProperty =&gt; Property + SomeLogic;

Of course, if you want to avoid the explicit raising of the PropertyChanged event from every property that the computed property depends on, you can observe the required properties for changes:

private int _property;
public int Property
{
  get =&gt; _property;
  set =&gt; SetProperty(ref _property, value, () =&gt; Property);
}

public int DependentProperty =&gt; Property + SomeLogic;

public ViewModel()
{
  TrackDependentPropertySourceProperties();
}

private void TrackDependentPropertySourceProperties()
{
  this.PropertyChanged += OnDependentPropertySourcePropertiesChanged;
}

// Assume that DependentProperty depends on three other properties
// (use three to highlight the pattern)
private void OnDependentPropertySourcePropertiesChanged(object sender, PropertyChangedEventArgs e)
{
  switch (e.PropertyName)
  {
    case nameof(Property):
    case nameof(SomeOtherProperty):
    case nameof(AThirdProperty):
      OnPropertyChanged(nameof(DependentProperty));
  }
}

答案2

得分: 0

你需要实现INotifyPropertyChanged接口到模型中。

然后实现:

protected void OnPropertyChanged(string name)
{
     PropertyChangedEventHandler handler = PropertyChanged;
     if (handler != null)
     {
         handler(this, new PropertyChangedEventArgs(name));
     }
}

当你设置属性时,只需调用OnPropertyChanged(&lt;属性名称&gt;)

建议:不要将业务逻辑放在模型本身中。

英文:

you need to implement INotifyPropertyChanged interface to model.

then implement

protected void OnPropertyChanged(string name)
{
     PropertyChangedEventHandler handler = PropertyChanged;
     if (handler != null)
     {
         handler(this, new PropertyChangedEventArgs(name));
     }
}

and when you set the property just call OnPropertyChanged(&lt;ProperyName&gt;).

Suggestion: Do not put business logic into the model itself.

huangapple
  • 本文由 发表于 2023年7月23日 15:46:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76747139.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定