C# 在WPF控件中将EventHandler声明为静态或非静态

C# 在WPF控件中将EventHandler声明为静态或非静态,c#,wpf,wpf-controls,binding,C#,Wpf,Wpf Controls,Binding,我正在创建一个具有命令行为的自定义控件,遇到了一些奇怪的事情。我发现的一些文章将CanExecuteChangedHandler事件处理程序声明为静态,而其他文章则声明为非静态。Microsoft的SDK文档显示静态,但当我将其声明为静态时,在使用多个控件时会出现奇怪的行为 private static EventHandler canExecuteChangedHandler; private void AddSecureCommand(ISecureCommand secureComman

我正在创建一个具有命令行为的自定义控件,遇到了一些奇怪的事情。我发现的一些文章将CanExecuteChangedHandler事件处理程序声明为静态,而其他文章则声明为非静态。Microsoft的SDK文档显示静态,但当我将其声明为静态时,在使用多个控件时会出现奇怪的行为

private static EventHandler canExecuteChangedHandler;

private void AddSecureCommand(ISecureCommand secureCommand)
{
    canExecuteChangedHandler = new EventHandler(CanExecuteChanged);
    securityTypeChangedHandler = new EventHandler(SecurityTypeChanged);

    if (secureCommand != null)
    {
        secureCommand.CanExecuteChanged += canExecuteChangedHandler;
        secureCommand.SecurityTypeChanged += securityTypeChangedHandler;
    }
}

有人知道正确的方法吗?我是否做错了导致静态EventHandler无法工作的事情?

保留
EventHandler
的本地副本的原因是WPF命令子系统在内部使用弱引用,因此我们需要保留对添加到
CanExecuteChanged
事件。如果事实上,任何时候我们添加到任何命令子系统事件中,我们也应该遵守这种做法,就像您对
securitypechanged
所做的那样

对您的问题的简短回答是,
canExecuteChangedHandler
可以是静态的,但是您必须小心地只初始化它一次。它可以是静态的原因是,如果
CanExecuteChanged
是静态的,则所有
new EventHandler(CanExecuteChanged)
都将执行相同的操作。初始化它一次的原因是不同的实例是不同的

具有正确只读语义的私有属性是:

static EventHandler canExecuteChangedHandler
{
    get
    {
        if (internalCanExecuteChangedHandler == null)
            internalCanExecuteChangedHandler = new EventHandler(CanExecuteChanged);
        return internalCanExecuteChangedHandler;
    }

}
static EventHandler internalCanExecuteChangedHandler;
但这仅在
CanExecuteChanged
为静态时有效。如果不是,则删除
静态
限定符。在这两种情况下,您都必须小心地实际使用该属性

在此特定示例中,第二次调用
AddSecureCommand
时,第一次调用的
canExecuteChangedHandler
有被垃圾收集的风险

最后,如果这一切听起来像是黑魔法,这里有一个代码示例来说明发生了什么

public class Container
{
    private WeakReference reference;
    public object Object
    {
        get { return reference.IsAlive ? reference.Target : null; }
        set { reference = new WeakReference(value); }
    }
}

public class DelegateTest
{
    private EventHandler eventHandler;
    private Container container1;
    private Container container2;

    void MyEventHandler(object sender, EventArgs args)
    {
    }

    public DelegateTest()
    {
        this.eventHandler = new EventHandler(MyEventHandler);
        this.container1 = new Container { Object = this.eventHandler };
        this.container2 = new Container { Object = new EventHandler(MyEventHandler) };
        GC.Collect();
        Console.WriteLine("container1: {0}", this.container1.Object == null);
        Console.WriteLine("container2: {0}", this.container2.Object == null);
    }
}
这将产生以下输出:

container1: False
container2: True

这表示在垃圾收集过程中,第二个容器的
EventHandler
垃圾“从下面”收集。这是通过设计弱引用的工作方式,并解释您需要自己保留对它的引用。

我理解垃圾收集的原因,我知道我必须在类级别声明EventHandler。我遇到的问题是,当我多次实例化这个类时,当它是静态的时,我会得到奇怪的行为。我试图编辑上面的评论,但显然我只有5分钟的时间来更新它。要在上面详细说明。。。我遇到的问题是,当我多次实例化类(或控件)时,当它是静态的时,我会得到奇怪的行为。在做了更多的研究之后,我发现EventHandler委托的目标是特定于实例的。在我的例子中,使用静态EventHandler会导致问题。我知道有时可能会使用静态EventHandler,但我猜它在我的情况下不起作用。在将其添加到命令事件后,仍然必须小心不要修改它。我将更新答案。要对垃圾收集进行评论,如果我不将EventHandler创建为静态,那么每个类实例将创建一个实例,这也将阻止垃圾收集。谢谢你提供的所有信息。