此问题已在此处有答案:
The calling thread cannot access this object because a different thread owns it(15个回答)
上个月关门了。
在我开始之前,我需要先声明这些代码和机制是一个巨大软件产品中的遗留代码,该软件产品处于从WinForms到WPF的完整迁移的最后阶段。代码和实践是过时的,但是,由于资源和进度的限制,有必要使用这些过时的实践,并使它们以某种方式工作。
在我们的WPF应用程序中,我有一个“action”类对象,它有一个 Execute() 方法,每次都在一个单独的线程上调用。这个特殊的“action”对象只是根据对象的 IsModal 属性的值显示一个模态或非模态窗口。这个应用程序代码是我从一个遗留的WinForms应用程序中迁移过来的。
我的问题是,第一次创建窗口时,当创建窗口后调用Show()或ShowDialog()方法时,会抛出经典的“调用线程无法访问此对象,因为另一个线程拥有它”异常。我甚至在窗口关闭后添加了一个GC.Collect()调用,
下面是Execute()方法的代码:
/// <summary>
/// Executes the sequence. Shows the given string in to the user.
/// </summary>
/// <returns></returns>
public override bool Execute()
{
bool bActionResult = true;
string sMessageString;
if (!GetStringFromParm("CmiActionMessageBox", m_StringToShow, out sMessageString))
{
return false;
}
if (this.ConvertEscapeSequences)
{
sMessageString = this.GetStringConvertEscapeSequences(sMessageString);
}
#region Show Message Box
// Create the form
UserPromptWindow frm = new UserPromptWindow(sMessageString);
frm.SetOKButtonText(m_sOkButtonName);
frm.SetCancelButtonText(m_sCancelButtonName);
frm.WindowStartupLocation = WindowStartupLocation.CenterOwner;
#region Adjust Dialog based upon action properties
bool? dr;
if (m_bDialogIsModal)
{
dr = frm.ShowDialog();
}
else
{
frm.Show();
// Wait until it goes away
while (frm.ModelessResult == null)
{
Thread.Sleep(50);
System.Windows.Forms.Application.DoEvents();
if (SequenceMgr.Mgr.BgSequenceDone)
{
ModelessDialogResult = false;
// Close the window, if it is still open
if (frm.IsLoaded)
{
frm.Close();
}
break;
}
}
dr = ModelessDialogResult;
}
// Make sure the window goes completely away
GC.Collect();
#endregion
#region Save the result to variable (if needful)
if (m_bDialogSavesResult)
{
if (dr == true)
{
SequenceMgr.Mgr.SetVariableValue(m_sDialogResultVar, "True");
}
else
{
SequenceMgr.Mgr.SetVariableValue(m_sDialogResultVar, "False");
}
}
#endregion
#region Set the action result to false if configured to stop the sequence upon hitting the cancel button
if (m_bDialogCanStopSequence)
{
if (dr == false)
{
bActionResult = false;
}
}
#endregion
return bActionResult;
}
我试图生成另一个线程来创建和显示窗口,但同样的事情发生了。
1条答案
按热度按时间xvw2m8pv1#
首先,感谢那些提供反馈的人。
经过多次尝试,例如。创建并在任务中显示用户提示窗口,我发现使其工作的方法是在应用程序调度器上下文中运行代码。同样,使用线程的整个解决方案是过时的,将来某个时候将更新为使用Tasks,但目前有效的解决方案使用 Application.Current.Dispatcher. Dispatcher() 和 System.Windows.Application.Current. Dispatcher. Dispatcher(DispatcherPriority.Background,new Action(delegate { }))的组合来确保窗口在UI线程中创建和显示; 允许窗口的UI在等待用户关闭窗口时运行,或者确定用户已经取消(停止)当前正在执行的操作序列。
下面是生成的代码: