gpt4 book ai didi

c# - 在 WPF 控件中将事件处理程序声明为静态或非静态

转载 作者:太空宇宙 更新时间:2023-11-03 14:23:54 24 4
gpt4 key购买 nike

我正致力于创建具有命令行为的自定义控件,并遇到了一些奇怪的事情。我发现的一些文章将 CanExecuteChangedHandler EventHandler 声明为静态的,而其他文章则声明为非静态的。 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 事件。事实上,无论何时我们添加到任何命令子系统事件,我们也应该遵守这种做法,就像您对 SecurityTypeChanged 所做的那样。

对您的问题的简短回答是 canExecuteChangedHandler 可以 是静态的,但您必须注意只初始化一次。它可以是静态的原因是如果 CanExecuteChanged 是静态的,所有 new EventHandler(CanExecuteChanged) 都会做同样的事情。之所以只初始化一次,是因为不同的实例不一样。

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

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

}
static EventHandler internalCanExecuteChangedHandler;

但这只有在 CanExecuteChanged 是静态的情况下才有效。如果不是,则删除 static 限定符。在任何一种情况下,您都必须小心地实际使用该属性。

在此特定示例中,第二次调用 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 垃圾回收“从其下方”进行。这是设计使弱引用的工作方式以及您需要自己保留对它的引用的解释。

关于c# - 在 WPF 控件中将事件处理程序声明为静态或非静态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4617272/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com