Как вернуть код 2factor из делегата внутри потока, отличного от пользовательского интерфейса?

Я работал только с WinForms и решил перейти на WPF, но столкнулся с проблемой, которую не могу решить:

Я хочу авторизоваться на vk.com через vkApi, а для этого мне нужно передать делегат, возвращающий string с кодом для 2factor auth

p.TwoFactorAuthorization = () =>
                {                 
                        var two = new TwoFactor();
                        two.ShowDialog();
                        return two.Data;
                };

Я решил^ сделать диалоговое окно, но получил "Вызывающий поток должен быть STA, потому что многие компоненты пользовательского интерфейса требуют этого"

vk.Authorize(p);

Итак, это означает, что метод this^ создает новый поток внутри, и мне нужно показать мой диалог из потока пользовательского интерфейса, я прав?

Я обнаружил, что Dispatcher.Invoke может мне помочь (не BeginInvoke, потому что мне нужно вернуть string), и написал это

return Dispatcher.Invoke(() =>
                        {                    
                            var two = new TwoFactor();
                            two.ShowDialog();
                            return two.Data;
                        }));

Но теперь мое приложение просто зависает, и диалоги не появляются! Что я делаю не так?


person strelok 372    schedule 27.10.2019    source источник
comment
Взгляните на (docs.microsoft.com/en-us/dotnet/api/), то вы увидите, что возврат Invoke() равен void, что означает, что вы не можете ничего вернуть просто с помощью return myVar. Вы должны передавать данные непосредственно в модель, которая в них нуждается.   -  person k1ll3r8e    schedule 28.10.2019
comment
как насчет Invoke‹TResult›(Func‹TResult›)?   -  person strelok 372    schedule 28.10.2019
comment
попробуйте использовать обработчик событий: вызовите событие в своей функции и обработайте его в основном потоке   -  person Leonid Malyshev    schedule 28.10.2019
comment
У вас также есть проблема с другим модальным диалогом, например. MessageBox? С MessageBox я не могу воспроизвести вашу проблему. Отправьте больше кода, чтобы увидеть, где вы вызываете/используете свои фрагменты кода. Также, пожалуйста, найдите минутку и прочитайте MCVE.   -  person Rekshino    schedule 28.10.2019


Ответы (1)


Я обнаружил, что API заблокировал основной поток, поэтому я вызвал AuthorizeAsync(), и основной поток стал доступен для отображения диалога с помощью Dispatcher.Invoke().

Это выглядит так:

public void Func()
{
    vkParams.TwoFactor = () =>
    {
        return Dispatcher.Invoke(() =>
        {                    
            var two = new TwoFactor();
            two.ShowDialog();
            return two.Data;
        }));
    }
} 

private async void Auth()
{
    vkParams.Login = t_login.Text;
    vkParams.Password = t_pass.Text;
    await vkApi.AuthorizeAsync(vkParams);
}
person strelok 372    schedule 29.10.2019