一、 本文將解決什么問題?
本文將解決:在主線程綁定了數據源的前提下,工作線程改變數據源,數據源無法及時更新的問題。
二、問題是如何出現的?
UI控件屬於UI線程。所有的綁定關系,是沒辦法穿透線程的。所以,在子線程中改變數據源的步驟,必須要‘回到UI線程’來進行。
當然,這與要避免在UI線程里進行耗時操作 的理念並不沖突。我們只在改變數據時回UI線程,切記。
三、問題代碼
1. MainWindow.xaml:我在主窗體里存在以下這個控件
1 <telerik:RadGridView x:Name="rgvSendHist" Margin="10,8,10,41" Style="{StaticResource RadGridViewClean}" EnableColumnVirtualization="True" EnableRowVirtualization="True" IsReadOnly="True" Grid.Row="1" SelectionChanged="rgvSendHist_SelectionChanged"> 2 <telerik:RadGridView.Columns> 3 <telerik:GridViewDataColumn DataMemberBinding="{Binding DataSend}" Header="數據包發送內容" Width="3*"/> 4 <telerik:GridViewDataColumn DataMemberBinding="{Binding RecLength,Mode=OneWay}" Header="返回包長度" Width="3*"/> 5 <telerik:GridViewDataColumn DataMemberBinding="{Binding SuccStatus,Mode=OneWay}" Header="是否成功" Width="3*"/> 6 </telerik:RadGridView.Columns> 7 </telerik:RadGridView>
2. MainWindow.xaml.cs: 我在這里進行了綁定。
1 ObservableCollection<TaskOfMany> aMultiTaskList = new ObservableCollection<TaskOfMany>(); 2 3 this.rgvTaskList.ItemsSource = aMultiTaskList;
3.MainWindow.xaml.cs: 我在這里通過線程對aMultiTaskList進行了改變。
1 foreach(TaskOfMany aTaskOfMany in aMultiTaskList) 2 { 3 new Task(() => 4 { 5 aTaskOfMany.StartScan(); 6 }).Start(); 7 }
4.aTaskOfMany.StartScan內部:
1 this.TaskRunningStatus = TaskRunningStatusEnum.檢測中;
此時,這個變化根本無法同步到控件上。
四、解決方案
在aTaskOfMany.StartScan內部改變值時,使用以下語句,回到UI線程:
1 Application.Current.Dispatcher.Invoke((Action)(() => 2 { 3 TaskRunningStatus = TaskRunningStatusEnum.檢測中; 4 }));
根據需要,你也可以使用BeginInvoke。至此,問題解決。
------------------------------------------------------------------------------------------------------------------------
分割線
------------------------------------------------------------------------------------------------------------------------
對於大多數人來說,使用了以上的解決方案,你的問題就已經解決了。但是,對我來說,以上的方案並沒有生效,讓我一度懷疑連‘回到UI線程’這個解決方案也解決不了我的問題。
經過定位,我發現問題出在了我對線程最大數量的控制上:
1 ThreadPool.SetMaxThreads(10, 10);
設置了這句之后,貌似會影響invoke的創建(因為不能發起新線程了),所以就算用dispatcher回UI線程,也不能馬上生效。。。
感謝群里的尚哥、三台等大神。真心感謝。
2017-5-10 10:27