H.B*_*.B. 18 wpf multithreading
在WPF中使用多个线程时可以获得的常见异常是:
调用线程无法访问此对象,因为另一个线程拥有它
有什么方法可以妥善处理这个问题?
H.B*_*.B. 39
根据具体情况,有多种选择:
从另一个线程访问控件
例如,使用进度信息更新TextBlock.
数据绑定:
在这种情况下,您可以做的最简单的事情是避免与控件直接交互.您可以将要访问或修改的属性绑定到其类实现 的对象,INotifyPropertyChanged然后在该对象上设置该属性.该框架将为您处理其余部分.(通常,您很少需要直接与UI元素交互,您几乎总是可以绑定相应的属性并使用绑定源;可能需要直接控制访问的一种情况是控件创作.)
在某些情况下,单独的数据绑定是不够的,例如在尝试修改绑定时ObservableCollection<T>,您需要...
调度:
您可以发送您的访问代码的线程拥有的对象,这可以通过调用来完成Invoke或BeginInvoke在Dispatcher拥有该对象被访问(这越来越Dispatcher有可能在另一个线程).
例如
new Thread(ThisThreadStart).Start();
void ThisThreadStart()
{
    textBlock.Dispatcher.Invoke(new Action(() => textBlock.Text = "Test"));
}
如果不清楚在哪个线程上执行某个方法,您可以使用Dispatcher.CheckAccess直接调度或执行操作.
例如
void Update()
{
    Action action = () => myTextBlock.Text = "Test";
    var dispatcher = myTextBlock.Dispatcher;
    if (dispatcher.CheckAccess())
        action();
    else
        dispatcher.Invoke(action);
}
如果一个对象不是a DispatcherObject并且您仍然需要关联Dispatcher,则可以在创建该对象的线程中使用(因此在由线程执行的方法中执行此操作对您没有任何帮助).为方便起见,您通常会在应用程序的主UI线程上创建对象; 你可以从任何地方获得该线程.Dispatcher.CurrentDispatcher DispatcherApplication.Current.Dispatcher
特别案例:
移动任何控件访问权限,ProgressChanged因为它发生在创建实例的线程上(当然应该是UI线程)
计时器
在WPF中,您可以使用DispatcherTimer为方便起见,它为您执行调度,因此Tick在关联的调度程序上调用任何代码.如果您可以将调度委托给数据绑定系统,您当然也可以使用普通计时器.
您可以在MSDN上阅读有关Dispatcher队列如何工作以及WPF线程的更多信息.
访问在另一个线程上创建的对象
例如,在后台加载图像.
如果有问题的对象不是,Freezable您通常应该避免在另一个线程上创建它或限制对创建线程的访问.如果是,Freezable您只需要调用Freeze以使其可供其他线程访问.
从另一个线程访问数据对象
也就是说,正在更新其实例的类型是用户代码.如果抛出异常,这种情况可能是由某人使用DependencyObject数据类的基类型引起的.
这种情况与访问控件相同,可以应用相同的方法,但通常应首先避免使用.当然,这允许通过依赖项属性进行简单的属性更改通知,并且这些属性也可以绑定,但通常这不值得放弃线程独立性.您可以从INotifyPropertyChangedWPF 获取更改通知,并且WPF中的绑定系统本质上是不对称的,始终存在绑定(目标)的属性以及此绑定的源.通常,UI是目标,数据是源,这意味着只有UI组件应该需要依赖属性.
| 归档时间: | 
 | 
| 查看次数: | 14105 次 | 
| 最近记录: |