如何为属性添加PropertyChanged事件?

时间:2019-06-26 17:52:15

标签: c# .net winforms

我已经在用户控件内创建了各种属性,并且在访问和编辑它们方面都取得了巨大的成功。我现在正在尝试为更改其中一个属性时引发的许多事件设置事件。我已经尝试过使用MSDN示例代码来执行此操作(see here),但在尝试构建解决方案时却出现了此错误:

  

严重性代码描述项目文件行抑制状态   错误CS0079事件'AbilityScoreDisplay.AbilityTitleChanged'仅出现在+ =或-= DnD字符表C:\ Users \ bradley beasley \ Documents \ Visual Studio 2019 \ Projects \ DnD字符表\ DnD字符表\的左侧AbilityScoreDisplay.Designer.cs 199有效

我遇到的另一个问题是我正在努力弄清楚如何使该事件出现在Visual Studio 2019设计器属性窗口中。

这是我添加到设计器文件中的代码:

namespace DnD_Character_Sheet
{
    partial class AbilityScoreDisplay : UserControl
    {
        public string AbilityTitle
        {
            get
            {
                return AbiltyTitleLabel.Text;
            }
            set
            {
                AbiltyTitleLabel.Text = value;
                Invalidate();
            }
        }
        public int AbilityModifier
        {
            get
            {
                return Convert.ToInt32(AbilityModifierTextBox.Text);
            }
            private set
            {
                if (value >= 0) AbilityModifierTextBox.Text = String.Format("+{0}", value);
                else AbilityModifierTextBox.Text = value.ToString();
                Invalidate();
            }
        }
        public int AbilityScore
        {
            get
            {
                return Convert.ToInt32(AbilityScoreLabel.Text);
            }
            set
            {
                AbilityModifier = (int)(Math.Floor((double)(value) / 2)) - 5;
                Invalidate();
            }
        }

        private EventHandler onAbilityTitleChanged { get; set; }
        private EventHandler onAbilityScoreChanged { get; set; }

        public event EventHandler AbilityTitleChanged
        {
            add
            {
                onAbilityTitleChanged += value;
            }
            remove
            {
                onAbilityTitleChanged -= value;
            }
        }
        public event EventHandler AbilityScoreChanged
        {
            add
            {
                onAbilityScoreChanged += value;
            }
            remove
            {
                onAbilityScoreChanged -= value;
            }
        }

        protected virtual void OnAbilityTitleChanged(EventArgs e)
        {
            AbilityTitleChanged?.Invoke(this, e);
        }
        protected virtual void OnAbilityScoreChanged(EventArgs e)
        {
            AbilityScoreChanged?.Invoke(this, e);
        }
    }
}

这样做的目的是使每当属性更改时就引发一个事件,以便它可以以控件将要使用的形式在其他地方做其他事情。还是我的代码根本没有那么有效,但是我是第一次学习这种代码,并且我尝试了许多不同的事情,这些事情都没有用。

任何帮助都将不胜感激:)

2 个答案:

答案 0 :(得分:5)

我认为您在混淆一些概念。让我们一步一步地做吧。

首先,您需要能够跟踪事件处理程序:

private EventHandler _onAbilityTitleChanged; 

您通过公共财产公开此事件:

public event EventHandler AbilityTitleChanged
{
    add
    {
        _onAbilityTitleChanged += value;
    }
    remove
    {
        _onAbilityTitleChanged -= value;
    }
}

最后,您需要触发事件,以便所有订阅的处理程序都可以对此事件做出反应。您可以在标题更改(设置)时这样做:

public string AbilityTitle
{
    get
    {
        return AbiltyTitleLabel.Text;
    }
    set
    {
        AbiltyTitleLabel.Text = value;
        //Raising the event!
        _onAbilityTitleChanged?.Invoke(this, new EventArgs());
    }
}

然后其他班级可以订阅您的活动:

var control = new AbilityScoreDisplay();
control.AbilityTitleChanged += SomeHandlerForWhenTitleChanges;

private void SomeHandlerForWhenTitleChanges(object sender, EventArgs e)
{
    //....
}

您可能还想在INotifyPropertyChanged界面上阅读一些内容。

答案 1 :(得分:2)

通常通过实现INotifyPropertyChanged来实现。这使您可以对所有属性使用一个事件。属性名称在事件参数中传递。

partial class AbilityScoreDisplay : UserControl, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    ...
}

在属性中执行此操作(以AbilityModifier为例)

private int _abilityModifier;
public int AbilityModifier
{
    get { return _abilityModifier; }
    private set {
        if (value != _abilityModifier) {
            _abilityModifier = value;
            AbilityModifierTextBox.Text = value >= 0
                ? String.Format("+{0}", value)
                : value.ToString();
            OnPropertyChanged(nameof(AbilityModifier));
        }
    }
}

假设此事件处理程序

private void ScoreDisplay_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    ...
}

您可以通过以下方式订阅活动

PropertyChanged += ScoreDisplay_PropertyChanged;

仅在极少数情况下需要使用添加/删除语法。通常,在创建自己的事件存储区时,因为您有很多事件,并且不想为未订阅的事件占用空间。


您可以将INotifyPropertyChanged与数据绑定一起使用,以在对数据进行更改时立即更新UI。为此,您将创建一个具有属性和INotifyPropertyChanged实现的类。然后,在表单中将此类的实例分配给DataSource的{​​{1}}。然后将控件绑定到此BindingSource

然后,您可以删除所有用于从文本框或标签中读取或写入文本或标签等的代码,因为绑定机制会自动为您完成代码。