在Wpf中界面显示数据的修改,都是通过UI线程完成,如果尝试从其他线程中直接修改控件的值回抛出异常,“调用线程无法访问此对象,因为另一个线程拥有该对象”。
例如:http://www.cnblogs.com/tianma3798/p/5762016.html
解决方案1:通过Invoke或者BeginInvoke将操作发送给Dispatcher 对象,委托Dispatcher去执行UI操作,每个UI控件都有Dispatcher 对象
代码实例:
Xaml代码
<ProgressBar x:Name="progressOne" Minimum="0" Maximum="1" Height="30" Margin="10,85,10,0" VerticalAlignment="Top"/> <!--绑定 进度条的值,并格式化为百分数--> <Label x:Name="label" Content="{Binding ElementName=progressOne,Path=Value}" ContentStringFormat="{}{0:P2}" HorizontalAlignment="Left" Margin="110,120,0,0" FontWeight="Bold" Foreground="Red" VerticalAlignment="Top"/>
C#代码
//启动前程修改UI数据 Task.Run(() => { int i = 0; while (true) { i++; if (i == 100) i = 0; //定义修改UI委托 Action<int> action1 = (q) => { progressOne.Value = q/100.0; }; progressOne.Dispatcher.BeginInvoke(action1, i); Thread.Sleep(100); } });
显示:
解决方案2:使用Wpf的双向绑定,在自定义线程中修改源数据,自动通知到UI线程修改界面显示
这种方式有个好处,只关心数据的修改,界面多出使用该数据的界面自动修改
更多双向绑定:http://www.cnblogs.com/tianma3798/p/5765464.html
代码实例:
Xaml代码
<Grid> <Slider x:Name="slider" Height="30" Value="{Binding Path=Result,Mode=TwoWay}" Minimum="0" Maximum="100" Margin="35,120,25,0" VerticalAlignment="Top"/> <Label x:Name="label" Content="{Binding Path=Result,Mode=TwoWay}" ContentStringFormat="当前值:{0}" HorizontalAlignment="Left" FontWeight="Bold" Foreground="Red" Margin="95,165,0,0" VerticalAlignment="Top"/> </Grid>
C#代码
//双向绑定数据 NumberData data = new NumberData(); slider.DataContext = data; label.DataContext = data; //启动线程修改绑定数据,界面内容会同步修改 Task.Run(() => { int i = 0; while (true) { i++; if (i == 100) i = 0; //修改双向绑定属性 data.Result = i; Thread.Sleep(100); } });
/// <summary> /// 实现INotifyPropertyChanged接口,通知 /// </summary> public class NumberData : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private int _Result; public int Result { get { return _Result; } set { _Result = value; if (this.PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Result")); } } }