C #: Как заставить "вызывать" метод из основного потока, сигнализируя каким-либо образом из другого потока - PullRequest
2 голосов
/ 05 января 2011

Извините за длинное название, я даже не знаю, как выразить вопрос

Я использую библиотеку, которая запускает обратный вызов из контекста, отличного от основного потока (это библиотека C), я создала обратный вызов в C #, и когда меня вызывают, я бы просто хотел вызвать событие.

Однако, поскольку я не знаю, что будет внутри события, я хотел бы найти способ вызвать метод без проблем блокировок и т. Д. (В противном случае сторонний пользователь должен будет обработать это внутри события очень некрасиво)

Есть ли способ сделать это? Я могу быть совершенно не прав, но я думаю о том, как winforms обрабатывают разные потоки (вещь .Invoke)

В противном случае я могу отправить сообщение в цикл сообщений окна, но я мало что знаю о передаче сообщений и могу ли я отправлять "пользовательские" сообщения, подобные этому

Пример:

private uint lgLcdOnConfigureCB(int connection, System.IntPtr pContext)
{
    OnConfigure(EventArgs.Empty);
    return 0U;
}

этот обратный вызов вызывается из другой программы, которой я не могу управлять, я хотел бы запустить метод OnConfigure в основном потоке (который обрабатывает мою winform), как это сделать? Или, другими словами, я хотел бы запустить OnConfigure без необходимости думать о блокировках

Редактировать 1:

У меня проблема с этим исключением:

CallbackOnCollectedDelegate Retrived Сообщение: обратный вызов запущен для делегата 'G19dotNet! G19dotNet.LgLcd + lgLcdOnSoftButtonsCB :: Invoke', собранного в GarbageCollector. Во время неуправляемого кода необходимо гарантировать, что делегаты никогда не будут удалены, пока вы не уверены, что они никогда не будут вызваны

Редактировать 2:

Проблема решена мной, благодаря Stackoverflow, который всегда помогает мне! Для дальнейшего использования: Определение делегата в качестве указателя на функцию

Ответы [ 3 ]

6 голосов
/ 05 января 2011

Если вы используете WinForms и хотите выполнить что-то в потоке пользовательского интерфейса, вам нужно вызвать либо Invoke, либо BeginInvoke на каком-либо элементе управления (будь то Button или Form или что-то еще) который был создан в этой теме. Вам понадобится ссылка на него, чтобы сделать это.

Например, с вашим кодом и предположением, что у вас есть ссылка на форму с именем form:

private uint lgLcdOnConfigureCB(int connection, System.IntPtr pContext)
{
    form.Invoke(new MethodInvoker(() => OnConfigure(EventArgs.Empty)));
    return 0U;
}
3 голосов
/ 05 января 2011

Существует шаблон для этого, называемый Асинхронный шаблон на основе событий .Ссылка на статью - отличный обзор того, как ее использовать.Класс AsyncOperation является ключом к этому шаблону.

Этот шаблон может не полностью соответствовать вашей проблеме, которую вы пытаетесь решить, но он может дать вам некоторое представление о проблеме.1007 *

3 голосов
/ 05 января 2011

Перед вызовом сторонней функции получите ссылку на Dispatcher.CurrentDispatcher.В функции обратного вызова используйте dispatcher.Invoke.

То, что вы в итоге получите, будет выглядеть примерно так:

class MyClass
{
    private Dispatcher dispatcher;
    public void runThirdParty()
    {
        this.dispatcher = Dispatcher.CurrentDispatcher;
        callThirdPartyFunction(myCallBack);
    }

    public void myCallBack()
    {
        this.dispatcher.Invoke(new Action(() =>
        {
            //code to run here.
        }));
    }
 }
...