2015-10-13 4 views
0

Я пишу программу WPF, где я использую EventToCommand для обработки событий в сторонних элементах управления и подключаю их к ICommands. Мои методы модели просмотра - это все async и проблема, с которой я сталкиваюсь, что события не ждут завершения обработчиков. Проблема немного длинная, чтобы проиллюстрировать в WPF, но я обобщил ее в маленьком консольном приложении ниже.EventToCommand async?

Мой общий вопрос: существует ли реализация EventToCommand, которая позволит мне использовать обработчики async? Да, я сделал google, ничего не нашел. Документация mvvm-light here ничего не говорит об асинхронном режиме.

Я открыт для любых работ, которые выполняют свою работу. Обратите внимание, что в приведенном ниже коде я использую имя «ButtonClick», которое может заставить вас спросить, почему я не просто привязываюсь к команде .... это был плохой выбор именования для примера извините. В моем приложении WPF я обрабатываю события, для которых нет команды.

class Program 
{ 
    public event EventHandler ButtonClickEvent; 

    static void Main(string[] args) 
    { 
     Console.WriteLine("Program"); 
     var p = new Program(); 
    } 

    public Program() 
    { 
     ButtonClickEvent += ButtonClickEventHandler; 
     Console.WriteLine("Start fire event"); 
     ButtonClickEvent(this, new EventArgs()); // In WPF app this event is handled by EventToCommand, which executes an ICommand 
     Console.WriteLine("End fire event"); 
     Console.Write("Press any key..."); 
     Console.ReadKey(); 

     // Output 
     // Start fire event 
     // Start GetStringAsync 
     // End fire event   <-- not waiting 
     // End GetStringAsync 
    } 

    // In WPF app this method is wired up to a DelegateCommand 
    public async void ButtonClickEventHandler(object sender, EventArgs e) 
    { 
     await DownloadStuffAsync(); 
    } 

    public async Task DownloadStuffAsync() 
    { 
     Console.WriteLine("Start GetStringAsync"); 
     string page = await new HttpClient().GetStringAsync("http://www.ibm.com"); 
     Console.WriteLine("End GetStringAsync"); 
    } 
} 

ответ

2

EventHandlers не поддерживает асинхронные методы. Вам понадобится метод возврата Task в качестве обходного пути и ждут Task, где вы вызываете событие.

Вы можете использовать Деферрал, как описано here в статье Стивена Клири по этому вопросу. Существуют и другие решения, такие как переопределение SynchronizationContext, но лучше использовать то, что показано в приведенной выше статье.

0

Я пробовал решение по ссылке, дающей Sriram в моем комментарии в WPF, и это действительно работает.

Мои ViewModel

public class ViewModel 
{ 
    public ICommand DoSomethingCommand { get; set; } 
    public ViewModel() 
    { 
     DoSomethingCommand = new RelayCommand(DoSomething); 
    } 

    private async void DoSomething() 
    { 
     await DownloadStuffAsync(); 
     Debug.WriteLine("Button Call Completed"); 
    } 
    public async Task DownloadStuffAsync() 
    { 
     Debug.WriteLine("Start GetStringAsync"); 
     await Task.Run(() => 
     { 
      Debug.WriteLine("Thread sleeping"); 
      Thread.Sleep(5000); 
     }).ConfigureAwait(false); 
     string page = await new HttpClient().GetStringAsync("http://www.ibm.com").ConfigureAwait(false); 
     Debug.WriteLine("End GetStringAsync"); 
    } 
} 

Мой Посмотреть

<StackPanel> 
    <Button Content="Do Something" Margin="0,2,2,2" Command="{Binding DoSomethingCommand}"/> 
</StackPanel> 

и выход на окно отладки

enter image description here

+1

При выполнении в приложении пользовательского интерфейса [ваш код будет заблокирован] (http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html). –

+0

Он не будет заторможен, но он замерзнет. Что также довольно странно, так это то, что пользователь хочет завершить процесс загрузки до того, как приложение станет пригодным для использования. – Sandesh

+0

Нет, он будет тупик. Вы можете попробовать. Есть много сообщений, которые говорят об этом. Обратитесь к статье в мой комментарий выше для получения дополнительной информации. –

0

Сэм событие не что иное, как спусковой крючок, который сообщает, что что-то есть произошло, например, нажатие кнопки мыши или мыши. Если вы хотите начать что-то делать, сделайте это. Но после этого обработайте ваши асинхронные потребности. Не могли бы вы объяснить точный сценарий, что вам нужно. так что я могу помочь больше?

Благодаря Анкит

1

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

Мой общий вопрос: существует ли реализация EventToCommand, которая позволит мне использовать обработчики async?

Хорошо, посмотрите на проблему с точки зрения стороннего управления. Это поднимает событие, которое выглядит примерно так:

void ControlEvent(object sender, ControlEventArgs args); 

Когда этот делегат возвращается, все сделано. Подпись обработчика события возвращает void, и все аргументы передаются данными от контроль по обработчик события. Нет «обратной связи».Делегат не может сказать стороннему элементу управления «Я на самом деле еще не сделан, я просто возвращаюсь, чтобы освободить поток, потому что я асинхронный, у меня есть больше кода для выполнения позже, а затем я», ll действительно. "

Итак, что бы вы хотели сделать, вероятно, потребуются нетривиальные изменения в стороннем элементе управления. Есть various hacks to try to force the asynchronous code to complete synchronously (как я описал в недавней статье MSDN), но никто из них не работает очень хорошо. Лучшее решение, как сказал Шрирам, - изменить сторонний контроль для использования Отсрочки; Я описываю one possible implementation of Deferrals в своем блоге. Однако это будет нетривиальное изменение для стороннего элемента управления, который они могут не желать делать.

+0

Стивен, в своей статье вы говорите: «Другие фреймворки, такие как (WPF), разрешают асинхронные обработчики событий. Так, например, событие нажатия кнопки может быть асинхронным». Как вы думаете, может быть, что-то вроде отборочного, возможно, что-то вроде «... но они не работают в течение половины времени, и они вводят ошибки», возможно, подходят? Я очень ценю все замечательные записи, которые вы написали, но иногда я чувствую, что мы никогда не получаем реальную историю асинхронной игры. Так много раз я читал ответ, как «его легко! Иди асинкс до конца!» Но там, где резина встречает дорогу, есть горе. – Sam

+0

@Sam: В этом случае это сторонний элемент управления, который вызывает все проблемы, а не WPF. WPF хорошо работает с 'async' /' await'; но если у вас есть библиотека, которая не поддерживает 'async', то (конечно), что библиотека путается, если вы используете' async'. –

+0

Стивен, пожалуйста, прочитайте свои собственные слова «Нет никакого« обратного сообщения ». Делегату нет возможности рассказать стороннему элементу управления ...». Это не вина стороннего контроля! Вы бы сделали гораздо больше, чтобы защитить свое дело, будучи ясными, ясными и полными, когда обсуждаете такие проблемы. Никто не бросает вину - просто скажите нам всю правду, чтобы мы знали, чего ожидать. – Sam

Смежные вопросы