我得到了以下例外:InvalidOperationException:调用线程无法访问此对象,因为另一个线程拥有它。
当我试图设置一个窗口的Owner时,该窗口是在Owner之外的另一个线程上构建的。
我知道我只能从正确的线程更新UI对象,但为什么我不能只设置所有者,如果它来自另一个线程?我能用另一种方法做吗?我想使进度窗口成为唯一一个可以输入条目的窗口。
这是发生bug的代码部分:
public partial class DlgProgress : Window
{
// ******************************************************************
private readonly DlgProgressModel _dlgProgressModel;
// ******************************************************************
public static DlgProgress CreateProgressBar(Window owner, DlgProgressModel dlgProgressModel)
{
DlgProgress dlgProgressWithProgressStatus = null;
var listDlgProgressWithProgressStatus = new List<DlgProgress>();
var manualResetEvent = new ManualResetEvent(false);
var workerThread = new ThreadEx(() => StartDlgProgress(owner, dlgProgressModel, manualResetEvent, listDlgProgressWithProgressStatus));
workerThread.Thread.SetApartmentState(ApartmentState.STA);
workerThread.Start();
manualResetEvent.WaitOne(10000);
if (listDlgProgressWithProgressStatus.Count > 0)
{
dlgProgressWithProgressStatus = listDlgProgressWithProgressStatus[0];
}
return dlgProgressWithProgressStatus;
}
// ******************************************************************
private static void StartDlgProgress(Window owner, DlgProgressModel progressModel, ManualResetEvent manualResetEvent, List<DlgProgress> listDlgProgressWithProgressStatus)
{
DlgProgress dlgProgress = new DlgProgress(owner, progressModel);
listDlgProgressWithProgressStatus.Add(dlgProgress);
dlgProgress.ShowDialog();
manualResetEvent.Set();
}
// ******************************************************************
private DlgProgress(Window owner, DlgProgressModel dlgProgressModel)
{
if (owner == null)
{
throw new ArgumentNullException("Owner cannot be null");
}
InitializeComponent();
this.Owner = owner; // Can't another threads owns it exception
4条答案
按热度按时间iklwldmw1#
上面的答案是正确的。但我会试着总结一下:
获取WPF处理程序的代码:
注意窗口应该在设置所有者调用之前初始化!(可在window.Loaded或window.SourceInitialized事件中设置)
也可以使用SetParent。那么你不需要转换处理程序:
请注意,父级和所有者具有不同的含义。Win32 window Owner vs window Parent?
ffx8fchx2#
我主要是根据汉斯·帕桑特的建议做的。重要的是,我怀疑这段代码应该只能在32位上工作,因为我在IntPtr上使用了“ToInt32”。
这就是代码:
WindowHelper函数:
调用函数:
mjqavswn3#
一个问题是,当应用程序关闭时,所拥有的窗口仍然打开,它将尝试执行可能失败的东西,我的猜测是,它试图关闭所有拥有的窗口。
给它自己的线程的一个缺点是,你必须跟踪子窗口,并在应用程序进入关闭的后期阶段之前,在主窗口关闭时关闭它:
拥有这种“多线程和相关”行为的代价。
有时不需要跟踪和/或所有者的View_Closing代码。有时,您只需要跟踪来保持对所拥有的窗口的引用,以便在应用程序关闭之前不会对它们进行垃圾收集。看情况了。看看什么适合你的情况。
m528fe3b4#
这不是设置所有者。如果要从另一个线程操作WPF中的控件,则需要创建一个委托并将其传递给控件的调度程序。
参见this文章。