触发事件的事件

3

我有一个对象是我的类中的私有成员。如果该对象触发了一个事件,我想将该事件传递给使用我的类的任何人。目前我是这样做的,在我的构造函数中添加以下代码:

cbName.CheckedChanged += ((sender, args) => this.CheckChanged(this,args));

有没有更好的方法来做这件事,如果类本身具有事件并且需要在处理函数中手动取消订阅,则该类不会被释放,那么有没有什么需要注意的地方?

将发送器从触发对象更改为this是可选的。

测试代码的完整版本

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace placeholder
{
    internal class FilterBase : UserControl, IFilterObject
    {
        public FilterBase(string name)
        {
            InitializeComponent();
            cbName.CheckedChanged += ((sender, args) => this.CheckChanged(this,args));
            cbName.Name = name;
            this.Name = name;
        }

        private CheckBox cbName;
        /// <summary> 
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.cbName = new System.Windows.Forms.CheckBox();
            this.SuspendLayout();
            // 
            // cbName
            // 
            this.cbName.AutoSize = true;
            this.cbName.Location = new System.Drawing.Point(4, 4);
            this.cbName.Name = "cbName";
            this.cbName.Size = new System.Drawing.Size(79, 17);
            this.cbName.TabIndex = 0;
            this.cbName.Text = "Filter Name";
            this.cbName.UseVisualStyleBackColor = true;
            // 
            // UserControl1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.AutoSize = true;
            this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
            this.Controls.Add(this.cbName);
            this.Name = "Filter Name";
            this.Size = new System.Drawing.Size(86, 24);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        public event EventHandler CheckChanged;
        public bool Checked
        {
            get { return cbName.Checked; }
        }
    }
}
2个回答

3

event实际上与自动属性类似。您可以定义自己的addremove方法,直接将委托传递给子控件,从而消除了额外的间接性:

public event EventHandler CheckChanged {
    add { cbName.CheckChanged += value; }
    remove { cbName.CheckChanged -= value; }
}

这将移除你的类中多余的Delegate(因为标准事件背后使用了Delegate字段)。

有没有办法在将发送者从cbName更改为FilterBase的情况下,像这样做到两全其美? - Scott Chamberlain
像往常一样,Jon Skeet在这里有一篇关于事件机制的精彩文章:http://csharpindepth.com/Articles/Chapter2/Events.aspx。如果适用于您的情况,请务必了解线程安全性。 - Jesse C. Slicer

1

好的,这样将防止当前对象在cbName存活期间被垃圾回收,但似乎这不太可能成为问题...并且这是由于您无论如何都有一个对this的引用(因为您想触发此对象的CheckChanged处理程序)所固有的。

这种方法的缺点之一是,即使您想要取消订阅(例如在Dispose方法中),也无法取消订阅。另一种选择是使用实际的方法:

private void CbNameCheckedChangedHandler(object sender, EventArgs e)
{
    CheckedChanged(this, args);
}

...
cbName.CheckedChanged += CbNameCheckedChangedHandler;

// If you ever want to remove the handler
cbName.CheckedChanged -= CbNameCheckedChangedHandler;

请注意,这一切都是基于您的CheckedChanged事件是空安全的,例如它被声明为:
public event EventHandler CheckedChanged = delegate {};

否则,如果没有人订阅事件,当cbName.CheckedChanged触发时,您将会得到一个NullReferenceException。

感谢您的空引用警告! - Scott Chamberlain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接