自定义对象中属性的显式 setter

Explicit setter for properties within custom object

我想为我的自定义对象提供明确的 setter:

字符class

public class CharacterModel
{
  public int HP { get; set; }
  public int MP { get; set; }
}

Main.razor

<input type="text" @bind-value="Character.HP" />
<input type="text" @bind-value="Character.MP" />

@code {
  private CharacterModel character;
  public CharacterModel Character
  {
    get => character;
    set 
    {
      character = value;
      // Do something else
    }
  }
}

我的问题是目前代码中的 setter 没有 运行,因为它正在调用 HP 和 MP setter。当我更改 HP 和 MP 时,有没有办法在代码中调用 setter?

简而言之:不。由于您绑定到 Character.HPCharacter.MP,因此您没有更改 属性 Character,而是模型绑定仅更改该对象的值直接。如果你做这样的事情也是如此:

// setter is called for this:
this.Character = new CharacterModel();

// setter is not called for this:
this.Character.HP = 100;
this.Character.MP = 50;

这样做的原因是因为它在功能上等同于以下内容:

// getter is used to retrieve object:
var character = this.Character;

// only operates on a local reference:
character.HP = 100;
character.MP = 50;

如果您需要找出角色模型的 属性 何时更改,那么您可以按照通常在 MVVM 设置中使用的方法进行操作。您可以让 CharacterModel 实现 INotifyPropertyChanged interface,让它通知相关方 属性 更改:

public class CharacterModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private int _hp;
    public int HP
    {
        get => _hp;
        set
        {
            _hp = value;
            RaisePropertyChanged();
        }
    }

    private int _mp;
    public int MP
    {
        get => _mp;
        set
        {
            _mp = value;
            RaisePropertyChanged();
        }
    }

    private void RaisePropertyChanged([CallerMemberName] string propertyName = "")  
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

是的,不幸的是,这给您的模型类型增加了很多膨胀,但从好的方面来说,它现在是完全反应式的。因此您可以订阅对其属性的更改:

private CharacterModel character;
public CharacterModel Character
{
    get => character;
    set 
    {
        // nothing to do if the value hasn’t changed
        if (character == value)
            return;

        // remove existing event handler
        if (character != null)
            character.PropertyChanged -= HandlePropertyChanged;

        // store new value
        character = value;

        // add event handler
        if (character != null)
            character.PropertyChanged += HandlePropertyChanged;
    }
}

private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == nameof(CharacterModel.HP))
    {
        // HP has changed, do something
        InvokeAsync(async () =>
        {
            highlightHealthPotion = Character.HP < 20;
            StateHasChanged()
        }
    }
}