Диспетчер. Вызвать блоки навсегда - PullRequest
3 голосов
/ 22 июня 2010

Я пытаюсь вызвать диалоговое окно диспетчера пользовательского интерфейса:

class DialogService : IDialogService
{
    private readonly Dispatcher _dispatcher = Application.Current.Dispatcher;

    public bool? Show(IDialogViewModel viewModel)
    {
        if (_dispatcher.CheckAccess())
        {
            var dialogWindow = new DialogWindow();
            return dialogWindow.Show(viewModel);
        }
        else
        {
            Func<IDialogViewModel, bool?> func = Show;
            return (bool?)_dispatcher.Invoke(func, viewModel);
        }
    }
}

Однако вызов Invoke блокируется навсегда, а Show никогда не вызывается в потоке пользовательского интерфейса ...

Использование BeginInvoke не вариант: мне нужен результат немедленно, потому что я обрабатываю событие из удаленного объекта (используя .NET remoting)

Есть идеи?


ОБНОВЛЕНИЕ

Вот более полное описание проблемы:

У меня есть клиентское приложение, которое взаимодействует со службой Windows с помощью .NET Remoting.В какой-то момент клиент выполняет вызов службы для выполнения операции (этот вызов инициируется действием пользователя, в этом случае нажатием кнопки).Службе могут потребоваться учетные данные для выполнения операции: в этом случае она вызывает событие CredentialsNeeded, обрабатываемое клиентом.Затем клиент показывает диалог, запрашивающий у пользователя учетные данные, и устанавливает соответствующие свойства в аргументах события.Когда обработчик события возвращается, служба использует учетные данные для завершения операции и возвращает управление клиенту.

Итак, когда я получаю событие, поток пользовательского интерфейса ожидает завершения операции в службесторона ... Я предполагаю, что это причина, по которой вызов Invoke не обрабатывается, но как я могу обойти это?Могу ли я создать другой поток пользовательского интерфейса для отображения диалога?В WinForms я знаю, что мог бы запустить еще один насос сообщений с Application.Run, но я не знаю, как сделать то же самое в WPF ...

Ответы [ 3 ]

4 голосов
/ 22 июня 2010

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

Это происходит каждый раз?Это, очевидно, упростит диагностику.

Необычно для меня, я бы предложил пойти к отладчику: просто нажмите перерыв и посмотрите, что делают потоки.

Наконец, я вас знаюнужен результат ... но что произойдет, если вы вместо этого do вызовете BeginInvoke (и вернете фиктивное значение)?Это вызывает метод в диспетчере или нет?Очевидно, это не будет долгосрочным решением, но даст больше диагностической информации.

1 голос
/ 23 июня 2010

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

class DialogService : IDialogService
{
    private readonly Dispatcher _dispatcher = Application.Current.Dispatcher;

    public bool? Show(IDialogViewModel viewModel)
    {
        if (_dispatcher.CheckAccess())
        {
            DoShow(viewModel);
        }
        else
        {
            bool? r = null;
            Thread thread = new Thread(() => r = DoShow(viewModel));
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            thread.Join();
            return r;
        }
    }

    private static bool? DoShow(IDialogViewModel viewModel)
    {
        var dialogWindow = new DialogWindow();
        return dialogWindow.Show(viewModel);
    }
}
1 голос
/ 22 июня 2010

Поток пользовательского интерфейса выполняет блокирующий вызов чего-то другого (возможно, вашего фонового потока) в то время, когда вы пытаетесь использовать Invoke?Если так, то у вас в руках классический тупик.Два потока, каждый из которых ожидает возврата другого.

В Windows Forms они часто закулисно «качают сообщения», когда вы меньше всего этого ожидаете, пытаясь избежать взаимоблокировок, но много раз это создает еще больше.проблемы и трудно найти ошибки из-за неожиданного повторного входа.

Если вы не думаете, что ваш поток пользовательского интерфейса находится в процессе блокирующего вызова, вы должны запустить приложение в отладчике и перейти вотладчик при возникновении тупика.Затем посмотрите в окне Темы для основного потока.Дважды щелкните основной поток, затем посмотрите в окне Call Stack, чтобы увидеть, где находится основной поток.

Вы также можете попробовать явно указать DispatcherPriority of Send, хотя я не думаю, что это будет иметь значение, если есть истинатупиковые.

...