Явный установщик свойств внутри пользовательского объекта - PullRequest
0 голосов
/ 08 марта 2020

Я хотел бы иметь явный установщик для моего пользовательского объекта:

Класс символов

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

Моя проблема в том, что в настоящее время сеттер в коде не работает, потому что он вызывает сеттеры HP и MP. Есть ли способ вызвать сеттер в коде, когда я меняю HP и MP?

1 Ответ

2 голосов
/ 08 марта 2020

Короче говоря: Нет. Поскольку вы привязываетесь к Character.HP и Character.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 интерфейс , уведомив заинтересованные стороны об изменениях свойств:

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()
        }
    }
}
...