Вызвать события класса в потоке, в котором он был создан C#
От: Павел А.Ануфриков Россия  
Дата: 07.08.10 09:18
Оценка:
Вопрос больше по проектированию, но применительно к C#.

Есть класс логики, который реализует логику приложения. Есть класс формы, который владеет первым классом. Класс логики содержит пул потоков, в которых генерируются события. Он эти события обрабатывает и пересылает форме. В результате в форме вызываются обработчики событий из сторонних потоков, и приходится вызывать .InvokeRequired, .Invoke и т.п.

Мне кажется, в правильной структуре, не должно быть такой ситуации, что форма должна заботиться о том, чтобы вызов был из нужного потока. Если это верно, то тогда вопрос по реализации: как правильно сделать, чтобы класс логики всегда вызывал события из того потока, в котором был создан?

Передавать родительский контрол ему в конструктор, у которого потом зызывать .Invoke — решение очевидное, но классу логики ни к чему связь с System.Windows.Forms.Control.
Re: Вызвать события класса в потоке, в котором он был создан
От: _FRED_ Черногория
Дата: 07.08.10 09:25
Оценка: 3 (1)
Здравствуйте, Павел А.Ануфриков, Вы писали:

ПАА>Передавать родительский контрол ему в конструктор, у которого потом зызывать .Invoke — решение очевидное, но классу логики ни к чему связь с System.Windows.Forms.Control.


Вместо Control логика может знать про более абстрактную и более нужную в данном случае вещь — SynchronizationContext. Используйте его.
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Вызвать события класса в потоке, в котором он был соз
От: Павел А.Ануфриков Россия  
Дата: 07.08.10 09:58
Оценка:
_FR>Вместо Control логика может знать про более абстрактную и более нужную в данном случае вещь — SynchronizationContext. Используйте его.

А я правильно понял, что нельзя вызвать произвольный делегат, а можно только SendOrPostCallback ? Т.е., если мне нужно вызвать собственный делегат формы, нужно сначала вызвать SendOrPostCallback, а из него уже вызывать делегат формы?
Re[3]: Вызвать события класса в потоке, в котором он был соз
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.08.10 10:10
Оценка:
Здравствуйте, Павел А.Ануфриков, Вы писали:

ПАА>А я правильно понял, что нельзя вызвать произвольный делегат, а можно только SendOrPostCallback ? Т.е., если мне нужно вызвать собственный делегат формы, нужно сначала вызвать SendOrPostCallback, а из него уже вызывать делегат формы?


Неясно, что такое собственный делегат формы, но можно делать так:
syncContext.Post(
   _ => form.Foo(...),
   null);
Re[3]: Вызвать события класса в потоке, в котором он был соз
От: _FRED_ Черногория
Дата: 07.08.10 10:10
Оценка: 3 (1)
Здравствуйте, Павел А.Ануфриков, Вы писали:

_FR>>Вместо Control логика может знать про более абстрактную и более нужную в данном случае вещь — SynchronizationContext. Используйте его.


ПАА>А я правильно понял, что нельзя вызвать произвольный делегат, а можно только SendOrPostCallback ? Т.е., если мне нужно вызвать собственный делегат формы, нужно сначала вызвать SendOrPostCallback, а из него уже вызывать делегат формы?


Да. Обычно это никогда не представляет трудностей.
Help will always be given at Hogwarts to those who ask for it.
Re: Вызвать события класса в потоке, в котором он был создан
От: MozgC США http://nightcoder.livejournal.com
Дата: 07.08.10 10:46
Оценка: 4 (2)
Вы можете использовать класс AsyncOperationManager.
В конструкторе вашего класса с бизнес-логикой пишете следующий код:

_asyncOperation = AsyncOperationManager.CreateOperation(null);

объект AsyncOperation захватил текущий контекст, который будет использоваться в последствии для выполнения в нем нужных методов.

А потом в методах класса логики, в которых нужно, чтобы операция происходила в том же потоке, вызываете:
_asyncOperation.Post(sendOrPostCallback, null);


Поток, в котором выполнится операция зависит от контекста, в котором был создан объект AsyncOperation в конструкторе. Если SynchronizationContect.Current был null (т.е. объект был создан не в GUI-потоке), то будет создан новый контекст и делегаты будут выполнятся в каком-то потоке из thread pool'а. Если же объект был создан в GUI-потоке (в котором SynchronizationContext.Current выставлен в WindowsFormsSynchronizationContext, то этот контекст и соответственно GUI-поток и будeт использоваться для выполнения делегатов.

В принципе можно не использовать классы AsyncOperationManager и AsyncOperation, а использовать напрямую SynchronizationContext, но эти классы предоставляют более высокоуровневую оболочку над SynchronizationCotnext. В частности, SynchronizationContext.Current может быть null, и это нужно проверять и в этом случае создавать новый SynchronizationContext, а классы AsyncOperationManager и AsyncOperation делают это за вас.

Чуть подробнее я писал на stackoverflow: When to use AsyncOperation and AsyncOperationManager.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.