Заявленная причина сохранения локальной копии EventHandler
заключается в том, что командная подсистема WPF внутренне использует слабые ссылки, и поэтому нам нужно сохранить ссылку на конкретный объект делегата, который добавляется к событию CanExecuteChanged
. Если это так, то всякий раз, когда мы добавляем к любому командному событию подсистемы, мы также должны соблюдать эту практику, как вы делаете для SecurityTypeChanged
.
Краткий ответ на ваш вопрос: canExecuteChangedHandler
может быть статичным, но вы должны быть осторожны, чтобы инициализировать его только один раз . Причина, по которой он может быть статическим, заключается в том, что все new EventHandler(CanExecuteChanged)
будут делать то же самое, если CanExecuteChanged
статичен. Причина, по которой он инициализируется один раз, состоит в том, что разные экземпляры различны.
Частная собственность, которая имеет правильную семантику только для чтения:
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
уборка мусора "из-под него". Это спроектировано так, как работают слабые ссылки, и объяснение для вас необходимо сохранить ссылку на него самостоятельно.