2013-05-31 35 views
6

Tôi muốn sử dụng async/await trên cửa sổ điện thoại của tôi 8 MVVM dự án và tôi đang đấu tranh để tìm một cách tốt để thực hiện ICommands của tôi bằng cách sử dụng api này. Tôi đã đọc một vài bài viết về chủ đề này và tôi đã gặp phải vấn đề này từ MSDN bên dưới, trong đó nêu rõ rằng tôi phải tránh những khoảng trống không đồng bộ vì khó nhận được các ngoại lệ chưa được xử lý: http://msdn.microsoft.com/en-us/magazine/jj991977.aspx Trong một câu hỏi khác tôi đã hỏi về chủ đề, ai đó cũng nói rằng tôi không nên sử dụng các khoảng trống không đồng bộ. Trừ khi có sự kiện.async/await trong MVVM mà không có phương pháp Void

Nhưng vấn đề là tất cả các ví dụ tôi có thể tìm thấy trên internet sử dụng khoảng trống không đồng bộ. này hai bài báo tôi thấy là những ví dụ: http://richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/http://blog.mycupof.net/2012/08/23/mvvm-asyncdelegatecommand-what-asyncawait-can-do-for-uidevelopment/

Người cuối cùng là một thực hiện ICommand sử dụng async/chờ đợi, nhưng nó cũng sử dụng khoảng trống async. Tôi đang cố gắng để tìm ra một giải pháp cho điều này, vì vậy tôi đã viết thực hiện này của ICommand dựa trên RelayCommand:

public delegate Task AsyncAction(); 

public class RelayCommandAsync : ICommand 
{ 
    private AsyncAction _handler; 
    public RelayCommandAsync(AsyncAction handler) 
    { 
     _handler = handler; 
    } 

    private bool _isEnabled; 
    public bool IsEnabled 
    { 
     get { return _isEnabled; } 
     set 
     { 
      if (value != _isEnabled) 
      { 
       _isEnabled = value; 
       if (CanExecuteChanged != null) 
       { 
        CanExecuteChanged(this, EventArgs.Empty); 
       } 
      } 
     } 
    } 

    public bool CanExecute(object parameter) 
    { 
     return IsEnabled; 
    } 

    public event EventHandler CanExecuteChanged; 

    public void Execute(object parameter) 
    { 
     ExecuteAsync(); 
    } 

    private Task ExecuteAsync() 
    { 
     return _handler(); 
    } 
} 

Và tôi đang cố gắng để sử dụng nó như thế này: trong constructor:

saveCommand = new RelayCommandAsync(SaveSourceAsync); 

thì:

private async Task SaveSourceAsync() 
{ 
    await Task.Run(() => { Save(); }); 
} 

private void Save() 
{ 
    // Slow operation 
} 

vấn đề là tôi không cảm thấy thoải mái với điều này và bất kỳ thực hiện khác như tôi không biết đó là tốt nhất và tối ưu.

Bất kỳ ai có thể đưa ra một số ánh sáng về cách tôi nên sử dụng nó, tốt nhất là với MVVM?

Trả lời

21

Trong bài viết tham khảo, tôi đã chỉ ra rằng ICommand.Execute là thực tế một event handler, vì vậy nó sẽ được coi là một ngoại lệ từ "tránh async void" phương châm:

Để tóm tắt phương châm đầu tiên này, bạn nên thích async Task thành async void ... Ngoại lệ cho hướng dẫn này là các trình xử lý sự kiện không đồng bộ, mà phải trả về void. Ngoại lệ này bao gồm các phương thức xử lý sự kiện hợp lý ngay cả khi chúng không phải là trình xử lý sự kiện theo nghĩa đen (ví dụ: triển khai ICommand.Execute).

Về thực hiện ICommand của bạn, nó thực sự giới thiệu một lỗ hổng bằng cách không sử dụng async void: việc thực hiện ICommand.Execute sẽ loại bỏ các Task mà không quan sát trường hợp ngoại lệ của nó. Do đó việc triển khai đó sẽ bỏ qua bất kỳ ngoại lệ nào do đại biểu async nêu ra.

Ngược lại, các bài viết trên blog bạn liên kết với có async void ICommand.Executeawait s các Task, cho phép các ngoại lệ đối với tuyên truyền với bối cảnh đồng bộ hóa giao diện người dùng. Mà - trong trường hợp này - là hành vi mong muốn vì đó là hành vi tương tự bạn nhận được khi một đồng bộ ICommand.Execute đặt ra một ngoại lệ.

Nếu bạn có độ nghiêng, tôi muốn bạn thử một số ICommand hoặc hai mà tôi đã viết để có thể bao gồm trong tương lai trong AsyncEx library của tôi. Các first one là một lệnh đơn giản rất giống với một trong blog bạn đăng.second one là một lệnh "không đồng bộ" hoàn chỉnh hơn bao gồm hủy bỏ, báo cáo tiến độ và quản lý tự động CanExecute. Tôi đánh giá cao bất kỳ phản hồi nào.

+0

Tôi đang xem xét trong thư viện và triển khai của bạn. Vì vậy, hãy cho tôi biết điều gì đó, với việc thực hiện ICommand cho bài đăng trên blog tôi đặt ở đây, nếu một ngoại lệ xảy ra sẽ nếu tăng sự kiện ngoại lệ chưa được giải quyết trong Windows Phone App.xaml? Tôi sẽ kiểm tra sau. –

+0

Tôi đã nhìn vào 'SimpleAsyncCommand', có vẻ như nó hoạt động theo mục đích của tôi, tôi chỉ muốn biết: Nethod của tôi là' ExecuteAsync' sẽ gọi là đang chạy trong ngữ cảnh UI và tôi phải sử dụng 'await Task.Run' trong phương thức này, đúng không? Tôi có bị mất bất kỳ ngoại lệ nào hoạt động như thế này không? Nếu không, tôi nghĩ rằng tôi sẽ sử dụng lib của bạn! –

+0

Các ngoại lệ từ 'ICommand's sẽ được nâng lên trên giao diện người dùng WP, vì vậy chúng sẽ được gửi đến' Application.UnhandledException'. 'ExecuteAsync' sẽ được thực hiện trên luồng giao diện người dùng (do đó ủy nhiệm' async' của bạn sẽ bắt đầu chạy trên chuỗi giao diện người dùng). Bạn có thể sử dụng 'await Task.Run' nếu bạn đã chặn công việc để làm cho lệnh đó; nếu bạn có công việc không đồng bộ để làm, bạn sẽ không cần 'Task.Run' và chỉ có thể sử dụng' await'. Và nó không thực sự là một phần của lib của tôi; bạn sẽ phải sao chép nguồn ngay bây giờ. –

Các vấn đề liên quan