Tại nhiều blog, hướng dẫn và MSDN tôi có thể đọc rằng truy cập các phần tử giao diện người dùng từ chuỗi không phải giao diện người dùng là không thể - ok, tôi sẽ nhận được ngoại lệ trái phép. Để kiểm tra nó, tôi đã viết một ví dụ rất đơn giản:Nâng cao thuộc tính trong tác vụ không đồng bộ và giao diện người dùng
// simple text to which TextBlock.Text is bound
private string sample = "Starting text";
public string Sample
{
get { return sample; }
set { sample = value; RaiseProperty("Sample"); }
}
private async void firstButton_Click(object sender, RoutedEventArgs e)
{
await Job(); // asynchronous heavy job
commands.Add("Element"); // back on UI thread so this should be ok?
}
private async Task Job()
{
// I'm not on UI Thread ?
await Task.Delay(2000); // some other job
Sample = "Changed"; // not ok as not UI thread?
commands.Add("Element from async"); // also not ok?
}
Tôi đã một nhiệm vụ mà đang được chạy không đồng bộ, trong Task mà tôi muốn: thay đổi thuộc tính của tôi (mà sẽ nâng PropertyChanged) và thêm yếu tố để ObservableCollection. Vì nó chạy async, tôi không thể làm điều đó, nhưng tôi không có ngoại lệ và mã đang hoạt động tốt. Do đó, những nghi ngờ và sự hiểu lầm của tôi:
- tại sao tôi không bị ngoại lệ?
- bạn có thể nâng cao PropertyChanged trong Công việc không đồng bộ không?
- bạn có thể sửa đổi ObservableCollecition trong Công việc không đồng bộ hay tôi nên trả lại Tác vụ và sau khi có được kết quả sửa đổi Quan sát - Xóa nó và Điền vào nó?
- khi tôi đang ở trong Công việc trên chuỗi giao diện người dùng và khi nào thì không?
- trong mã ở trên trong
firstButton_Click
là ok để quản lý các phần tử giao diện người dùng sau khi đợi tác vụ? Tôi có luôn quay lại chuỗi giao diện người dùng không?
Để kiểm tra nó nhiều hơn tôi đã đặt thay đổi sở hữu của tôi và thay đổi bộ sưu tập trong chủ đề khác:
System.Threading.Timer newThreadTimer = new System.Threading.Timer((x) =>
{
Sample = "Changed"; // not UI thread - exception
commands.Add("Element from async"); // not UI thread - exception
}, null, 1000, Timeout.Infinite);
Trong đoạn code trên suy nghĩ của tôi là ok - ngay sau khi dòng đầu tiên hoặc thứ hai tôi nhận được một ngoại lệ . Nhưng những gì với mã đầu tiên? Nó chỉ là một may mắn mà nhiệm vụ của tôi đã được chạy trên thread UI?
Tôi nghi ngờ rằng điều này là rất cơ bản và sự hiểu lầm của tôi, nhưng tôi cần một số làm rõ và do đó câu hỏi này.
Tôi muốn +1 điều này nếu không tuyên bố này: * "Thư viện công việc song song sử dụng' TaskScheduler' để ngầm (hoặc rõ ràng ...) nắm bắt hiện tại 'SynchronizationContext' ..." * Điều này không hoàn toàn chính xác đối với việc tiếp tục 'await': http://stackoverflow.com/q/23071609/1768303 – Noseratio
Câu trả lời dài (cảm ơn bạn vì điều đó), nhưng tôi đã một số nghi ngờ: 1. Hãy nhìn rằng công việc của tôi được chạy như không đồng bộ 'chờ đợi công việc();' từ Click - vì vậy bối cảnh giao diện người dùng bị bắt là trước và sau khi không ở bên trong? 2. Tôi đang bối rối với trở về từ chờ đợi trên cùng một chủ đề - cho Ví dụ [Tôi không thể chờ đợi bên trong Mutex] (http://stackoverflow.com/q/23153155/2681948), do đó sau khi trở về 'bối cảnh bị bắt cũng có thể có nghĩa là bất kỳ thread thread-pool nào cả'. tăng tài sản thay đổi từ async Task (trên thread khác nhau), sau đó tại sao không phải là Timer? – Romasz
@Romasz bạn đang bối rối liên quan bởi các khái niệm khác nhau của 'không đồng bộ' /' đồng bộ' và 'đồng thời'. Tất cả các mã bạn đã viết là Điều đó có nghĩa là bạn không có vấn đề gì. Lỗi mới bắt đầu với 'async'/'await' là suy nghĩ, đúng ... chúng ta là tái không đồng bộ, có nghĩa là chủ đề phải không? Các luồng có nghĩa là 'đồng thời', và trong quá khứ đó là cách duy nhất để đạt được 'không đồng bộ'. – Aron