2011-12-10 6 views
5

Tôi đã chơi thử với các mẫu CTP và MVVM không đồng bộ mới. Tôi đã chuyển đổi một chương trình cũ của tôi đang sử dụng nhân viên nền và báo cáo tiến trình cập nhật bộ sưu tập trong mô hình của tôi. Tôi đã chuyển đổi nó thành một cái gì đó như vậyTask.Run không đồng bộ với MVVM

TaskEx.Run(async() => 
{ 
    while (true) 
    { 
    // update ObservableCollection here 
    } 
    await TaskEx.Delay(500); 
}); 

Theo quan điểm của tôi, tôi ràng buộc với chế độ xem của tôi hiển thị bộ sưu tập quan sát này. Tuy nhiên, khi bộ sưu tập của tôi cập nhật, tôi nhận được Ngoại lệ

Loại CollectionView này không hỗ trợ các thay đổi đối với SourceCollection của nó từ một chuỗi khác với chuỗi điều phối.

Tôi không chắc chắn cách nào chính xác để kéo quay lại giao diện người dùng khi thực hiện như thế này.

+0

Lưu ý rằng, có phiên bản cập nhật của 'async' trong Visual Studio 11 Developer Preview mà bạn có thể tải xuống. – svick

Trả lời

5

Bạn không phải chạy các phương thức không đồng bộ bằng cách sử dụng Task.Run() hoặc bất kỳ phương tiện đặc biệt nào khác, chỉ cần gọi cho chúng. Và trong trường hợp của bạn, đó là chính xác những gì đang gây ra vấn đề.

chức năng Với như thế này:

Action f = async() => 
{ 
    while (true) 
    { 
     // modify the observable collection here 
     await Task.Delay(500); 
    } 
}; 

Gọi nó như thế này từ một số phương pháp chạy trên thread UI, giống như một xử lý sự kiện:

f(); 

công trình chính xác như mong muốn. Nó thực hiện lần lặp đầu tiên của chu trình và sau đó trả về. Lặp lại tiếp theo được thực hiện sau 500 ms (hoặc nhiều hơn, nếu chuỗi giao diện người dùng bận) trên chuỗi giao diện người dùng.

Mặt khác, nếu bạn gọi nó như thế này:

Task.Run(addNames); 

nó không hoạt động một cách chính xác. Lý do cho điều này là các phương thức async cố gắng tiếp tục trong cùng một ngữ cảnh khi chúng được bắt đầu (trừ khi bạn chỉ định rõ ràng cách khác). Phiên bản đầu tiên đã được bắt đầu trên chuỗi giao diện người dùng, do đó, nó tiếp tục trên chuỗi giao diện người dùng. Phiên bản thứ hai bắt đầu trên một ThreadPool thread (nhờ Task.Run()) và tiếp tục có quá. Đó là lý do tại sao nó gây ra lỗi của bạn.

Tất cả điều này được thực hiện bằng cách sử dụng SynchronizationContext, nếu có.

3

Bạn đã tạo một ObservableCollection trên chuỗi giao diện người dùng chính và đang cố gắng cập nhật nó trên chuỗi nền không đồng bộ mà bạn không thể thực hiện trong WPF.

Cách khác, lấy kết quả từ chuỗi nền, sau đó thêm chúng vào ObservableCollection trên chuỗi giao diện người dùng chính.

Thông thường mã của tôi để cập nhật một ObservableCollection trên một sợi nền sẽ giống như thế này:

private async void LoadItems() 
{ 
    Task<List<MyItem>> getItemsTask = Task.Factory.StartNew(GetItems); 

    foreach(MyItem item in await getItemsTask) 
     MyCollection.Add(item); 
} 

private List<MyItem> GetItems() 
{ 
    // Make database call to get items 
} 
2

Trong khi đó là sự thật rằng bạn không thể cập nhật một ObservableCollection từ một sợi thứ hai, nó có thể để tạo bộ sưu tập quan sát không đồng bộ. Điều này cho phép bạn cập nhật bộ sưu tập từ bên trong các tác vụ hoặc trên các chủ đề mà bộ sưu tập không được tạo.

Tôi sẽ đăng ví dụ, nhưng tôi đã tìm thấy thông tin ở đây. Nó khá trơn, và tôi thấy nó là một ví dụ rất hữu ích.

http://www.thomaslevesque.com/2009/04/17/wpf-binding-to-an-asynchronous-collection/