我在WPF应用程序的单独线程中执行冗长的操作(连接测试,远程数据库表的验证等)。在测试期间,我收集用户的信息,告知哪些测试已通过,哪些测试未通过。信息存储为我自己设计的List<T>
个对象:
public class StatusItem : DependencyObject
{
public string Text { get... set... }
public Status Status { get... set... }
public string Details { get... set... }
}
所有这些属性都是相应DependencyProperty
的前端。当操作完成时(在单独的线程中),我将收集的信息status
设置为Window
上的私有字段。我得到了:
InvalidOperationException:
The calling thread cannot access this object because a different thread owns it.
我有没有办法将status
(一个List<StatusItem>
)从TestThread转移到我的主线程,而无需诉诸代理和Dispatcher
调用?
PS:我可以Invoke
,但我宁愿避免创建CopyStatusItemsDelegate
代表。
答案 0 :(得分:3)
我不认为有一个很好的解决方案。上述情况是我为什么不从DependencyObject
派生Item-ViewModel而是实现INotifiyPropertyChanged
的原因。
答案 1 :(得分:1)
关于msdn的DependencyObject:
只能从它所在的线程访问此对象 创建。试图从其他线程访问它会抛出一个 InvalidOperationException异常。 Invoke或BeginInvoke提供支持 编组工作到正确的线程。
如果您的案例中必须有DependencyObject,那么请使用Invoke。否则,我建议你使用INotifyPropertyChanged接口实现。
答案 2 :(得分:0)
如果您完全信任,可以使用以下黑客攻击:
public static class DispatcherExtenstions {
public static void SetAccess(this DispatcherObject d) {
if(d.CheckAccess()) return;
Dispatcher dispatcher = d.Dispatcher;
FieldInfo dispatcherThreadField = typeof(Dispatcher).GetField("_dispatcherThread", BindingFlags.Instance | BindingFlags.NonPublic);
dispatcherThreadField.SetValue(dispatcher, Thread.CurrentThread);
}
}
样品:
public partial class MainWindow : Window {
Button b;
public MainWindow() {
InitializeComponent();
Thread t = new Thread(CreateButton);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
void CreateButton() {
b = new Button() { Padding = new Thickness(20.0) };
b.Content = new Button { Content = "Button" };
Dispatcher.BeginInvoke((Action)ShowButton);
}
void ShowButton() {
b.SetAccess();
Content = b;
}
}