2011-01-06 3 views
2

Я работал над созданием настраиваемого элемента управления с поведением команд и натолкнулся на что-то нечетное. Некоторые статьи, которые я нашел, объявили CanExecuteChangedHandler EventHandler статическими, а другие были нестационарными. Документация Microsoft SDK показывает статическую информацию, но когда я объявляю ее статичной, я получаю странное поведение при использовании нескольких элементов управления.Объявлять EventHandlers как статические или нестатические элементы управления WPF

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 не работает?

ответ

1

Указанная причина сохранения локальной копии 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 сборку мусора «из-под него». Это по дизайну способ, которым работают слабые ссылки, и объяснение для вас должно содержать ссылку на него самостоятельно.

+0

Я понимаю причину сбора мусора, и я знаю, что должен быть объявлен EventHandler на уровне класса. Проблема, с которой я сталкиваюсь, - это когда я создаю экземпляр класса несколько раз, я получаю нечетное поведение, когда оно статично. – Brady

+0

Я хотел добавить новую строку, и она представила комментарий. Я попытался отредактировать вышеупомянутый комментарий, но, видимо, мне осталось всего 5 минут, чтобы обновить его. Чтобы выработать выше ... Проблема, с которой я сталкиваюсь, - это когда я создаю экземпляр класса (или управления) несколько раз, когда получаю нечетное поведение, когда оно статично. Проведя немного больше исследований, я вижу, что цель делегата EventHandler специфична для экземпляра. В моем случае использование статического события EventHandler вызывает проблемы. Я могу видеть, как могут быть моменты, когда статический EventHandler можно использовать, но я думаю, что это не сработает в моем случае. – Brady

+0

Подводя итог вашей точке: ссылка на обработчик событий может быть статичной, только если статический метод. Вы все равно должны быть осторожны, чтобы не изменять его после того, как вы добавили его в командные события.Я обновлю ответ. –

Смежные вопросы