一、 本文将解决什么问题?
本文将解决:在主线程绑定了数据源的前提下,工作线程改变数据源,数据源无法及时更新的问题。
二、问题是如何出现的?
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
|