2014-09-24 2 views
0

У меня есть класс Worker и класс MainForm/UI. Из класса пользовательского интерфейса я создаю новый экземпляр класса Worker в новом фоновом потоке. Этот поток добавляет несколько обновлений к элементам управления пользовательского интерфейса. Поскольку они находятся в разных классах, я в основном передаю экземпляр MainForm (это) и соответствующий делегат для обновления элементов управления в конструктор рабочего класса. В конструкторе я устанавливаю mainForm на объект ISynchronizeInvoke (назовите его _synch), а затем, далее в рабочем классе, сделайте _synch.Invoke(theDelegate, new object[] { "new value" }).ISynchronizeInvoke vs SynchronizationContext vs mainForm.Invoke

Это все работает нормально, но потом я понял, что также можно сделать просто mainForm.Invoke (не используя объект ISynchronizeInvoke). Какая разница между двумя?

Чтобы усугубить ситуацию, я прочитал в статье, что ISynchronizeInvoke больше не нужен, теперь, когда SynchronizationContext пришел долго. Я понимаю, что я не понимаю, для чего эти два. Любая помощь с пониманием, почему я должен использовать Invoke для этих объектов, а не непосредственно на mainForm, будет с благодарностью оценена.

+0

ISynchronizeInvoke полезна только в другую библиотеку, которая делает * не * есть идея, какая именно нить нить UI или как правильно ссылаться на код, который манипулирует интерфейс. Никогда не проблема с классом Form, это * это * пользовательский интерфейс. И реализует водопровод, который заставляет работать ISynchronizeInvoke.К сожалению, WPF нарушил контракт, поэтому он больше не является интерфейсом общего назначения. –

+0

@ HansPassant Спасибо Хансу. Я попытался переключиться на 'SynchronizationContext', как было предложено Sriram, но Send и Post не принимают пользовательские делегаты. Они принимают делегат SendOrPostCallback, который имеет только один параметр ('object'). У моего текущего пользовательского делегата есть как строка значений (текст, который я хочу взять ярлык), так и строка lbName, так что метод может определить, какой элемент управления меткой обновляется. Что вы мне посоветовали? Должен ли я просто придерживаться Form.Invoke? Благодаря! – Anders

+0

Использование Invoke ошибочно в 99% случаев. Очень подвержен тупиковой ситуации и расам, всегда используйте BeginInvoke. Единственного объекта достаточно для хранения * ничего *, при необходимости используйте небольшие вспомогательные классы. Лямбда - почти всегда удобная альтернатива. –

ответ

4

В Winforms, независимо от того, какой метод вы вызываете Form.Invoke, ISynchronizeInvoke.Invoke, SynchronizationContext.Send вы делаете то же самое.

Фактически все они внутренне идут к тому же методу, который равен Control.Invoke (который реализует элемент интерфейса ISynchronizeInvoke).

В чем разница между двумя (Form.Invoke и ISynchronizeInvoke.Invoke)?

Ничего, они указывают на тот же метод Control.Invoke.

При этом, если вы зависите от ISynchronizeInvoke, вы почувствуете боль, когда переносите приложение на другую технологию (скажем, WPF). ISynchronizeInvoke там не поддерживается. Это особенность Winforms. Вы всегда должны отдавать предпочтение SynchronizationContext над чем угодно.

SynchronizationContext обеспечивает абстракцию, независимо от технологии, вы можете маршировать вызов к потоку пользовательского интерфейса (обычно не всегда) через SynchronizationContext. Если ваш код зависит от SynchronizationContext, вы можете легко переносить его в WPF или Asp.Net, поскольку они обеспечивают их технологию, специфичную реализацию SynchronizationContext. Реализация

  • Winforms - WindowsFormsSynchronizationContext
  • Wpf реализация/Silverlight - DispatcherSynchronizationContext
  • реализация Asp.net - AspNetSynchronizationContext
  • Etc

Одним из недостатков SynchronizationContext является то, что она не дает никакой возможности получить возвращаемое значение, хотя вы можете обойти его через закрытие, члены экземпляра и т. д.

Дальнейшее чтение: It's All About the SynchronizationContext

+0

Спасибо! Так что я забуду об ISynchronizeInvoke. Относительно использования Form.Invoke , недостатком является то, что Form.Invoke не работал бы, если бы я переключился на WPF (даже если элементы управления там имели одинаковое имя)? – Anders

+0

Я получаю эту ошибку в конструкторе, если вместо этого я пытаюсь использовать SynchronizationContext: 'Can not конвертировать тип источника MainForm для целевого типа SynchronizationContext'. Есть идеи? – Anders

+0

@Anders Вы не можете использовать один и тот же элемент управления в wpf. Вы будете использовать специальный эквивалентный элемент управления wpf. Хотя вы можете использовать [Dispatcher.Invoke] (http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke%28v=vs.110%29.aspx) в wpf, это означает, что вам нужно изменить свой код. если использовался «SynchronizationContext», он будет работать так, как есть. –

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