Существует ли общепринятая лучшая практика для создания обработчика событий, который сам отписывается?
Например, первое, что я придумал, это что-то вроде:
// Foo.cs
// ...
Bar bar = new Bar(/* add'l req'd state */);
EventHandler handler = new EventHandler(bar.HandlerMethod);
bar.HandlerToUnsubscribe = handler;
eventSource.EventName += handler;
// ...
// Bar.cs
class Bar
{
/* add'l req'd state */
// .ctor
public EventHandler HandlerToUnsubscribe { get; set; }
public void HandlerMethod(object sender, EventArgs args)
{
// Do what must be done w/ add'l req'd state
((EventSourceType)sender).EventName -= this.HandlerToUnsubscribe;
}
}
Сказать, что это кажется хакерским / плохим, - преуменьшение. Он тесно связан с временной зависимостью (HandlerToUnsubscribe
должно быть назначено точное значение в нужное время). Я чувствую, что в этом случае я играю роль соучастника - что-то глупое или простое, что я упускаю?
Контекст:
Я создаю привязку между пользовательским интерфейсом и собственной инфраструктурой команд в Winforms (используя полезную ICommand
в System.Windows.Input). Один из аспектов инфраструктуры привязки заключается в том, что пользователи, которые создают привязку между компонентом команды пользовательского интерфейса (например, кнопкой на панели инструментов или элементом меню), имеют возможность прослушивать событие CanExecuteChanged
команды, а затем обновляют состояние пользовательского интерфейса на основе этого: обычно для свойства Enabled установлено значение true
или false
.
Техника в целом работает довольно хорошо, но есть способы для запуска события до того, как будет создан дескриптор компонента пользовательского интерфейса. Я пытаюсь гарантировать, что предоставленный обработчик не будет запущен, если дескриптор не был создан. В результате я рассматриваю возможность предоставления общего вспомогательного класса ("Bar
"), который поможет реализации. Цель Bar
- проверить, существует ли соответствующий дескриптор. Если так, отлично! Если нет, то он подпишется на соответствующее событие IsHandleCreated
, чтобы поставляемые обработчики запускались при создании дескриптора. (Это важно, потому что клиент может установить свои привязки в .ctor пользовательского интерфейса до того, как дескриптор существует.) Однако я хочу, чтобы эта подписка была полностью прозрачной, и поэтому я также хочу, чтобы каждый обработчик событий автоматически отписывался от IsHandleCreated
как только он закончит работу.
Я все еще пытаюсь выяснить, является ли это хорошей идеей, поэтому я еще не обобщил концепцию - в этом случае я реализовал ее только непосредственно в ToolStripItems, чтобы проверить что идея здорова. Я еще не продан на этом.
Я понимаю, что у меня также есть возможность просто указать, что привязки могут быть созданы только после создания дескриптора пользовательского интерфейса в событии OnLoad формы (например,). Я знаю, что это может работать, я делал это в прошлом. Хотелось бы посмотреть, смогу ли я смягчить это конкретное требование в этом случае. Если это даже практично.