Вызов WPF из собственного приложения C ++ приводит к тому, что асинхронные вызовы теряют контекст - PullRequest
0 голосов
/ 07 февраля 2019

Я вызываю диалог C # WPF из собственного приложения Win32 с помощью оболочки CLI.У нас есть некоторые другие диалоги, которые работают нормально, но этот демонстрирует своеобразное поведение - он также более сложный, чем другие.

Ну, с самого начала, после того, как код CLI C ++ вызывает код C #, мы устанавливаемконтекст, вызвав:

        var currentContext = SynchronizationContext.Current;

        if (currentContext == null && (Thread.CurrentThread.IsThreadPoolThread))
        {
            throw new InvalidOperationException("Can't set a dispatcher sync context on thread pool threads");
        }

        SynchronizationContext context = null;
        // WPF needs to make sure that all GUI actions are done on the main GUI thread.
        // As we are beeing called by Unmanaged C++ there is no SynchronizationContext set.            
        // This check make sure we will be back to the GUI thread after an await

        if (currentContext == null)
        {
            context = new DispatcherSynchronizationContext();
            if (logger != null)
            {
                logger.Trace(string.Format("Applying DispatcherSyncContext on thread: {0}", Thread.CurrentThread.ManagedThreadId));
            }

            SynchronizationContext.SetSynchronizationContext(context);

            Debug.Assert(Dispatcher.FromThread(Thread.CurrentThread) != null);
        }
        else if (!(currentContext is DispatcherSynchronizationContext))
        {
            LogWarning(
                "Current SynchronizationContext is not a DispatcherSynchronizationContext and may cause exceptions. Current context: " + currentContext,
                logger);
            context = currentContext;
        }

Я не уверен, стоит ли проверять Диспетчер, а не контекст, но, насколько я знаю, это должно сработать.

Что ж, так и есть - большую часть времени.

Существует асинхронный вызов для загрузки данных из БД, который выглядит следующим образом:

public async Task<bool> AddStuff(IEnumerable<Stuff> stuffs)
    {

// Материал - это poco - без логики..

        CheckIfOnDispatcher(); // all well

        if (!stuffs.Any())
        {
            return false;
        }

        var failureText = await Task.Run(() =>
        {
            return GetStuffDetails(DataService, stuffs);
        }).ConfigureAwait(true);

        CheckIfOnDispatcher(); // here its not on dispatcher anymore

Был добавлен метод Check для отладки происходящего:

        [Conditional("DEBUG")]
    void CheckIfOnDispatcher()
    {
        if (Dispatcher.FromThread(Thread.CurrentThread) == null)
        {
            UserFeedback.ShowFeedback($"Not on GUI: {Thread.CurrentThread.ManagedThreadId}");
        }
    }

После await Task.Run, только иногда, он не вернется в основной поток, но продолжитна рабочем потоке.

Такое поведение действительно происходит только на клиенте win32, если мы вызываем его из клиента Windows Form или C # WPF, проблем нет.Похоже, что основной поток из приложения win32 MFC имеет какое-то особое поведение, но я не могу найти какую-либо документацию по этому поводу.

Неправильно ли мы устанавливаем контекст?Я также пытался открыть диалоговое окно, свернутое с самого начала, и скрыть его снова, но это также не сработало (вместо настройки контекста)

PS: UserFeedback вызывает MessageBox, который также работает безДиспетчер ...

TIA,

Марко

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...