我下面的代码创建一个mdi窗体中的窗口。这个想法是创建一个特定类型的窗口,如果它存在的话,或者如果已经存在一个实例就把它放在前面。Wpf创建窗口锁
public static object CreateWindow(Type windowType, params object[] args)
{
try
{
lock (_definitionToWindow)
{
var def = new WindowDefinition {ControlType = windowType, Args = args};
System.Windows.Forms.Form win = null;
if (_definitionToWindow.TryGetValue(def, out win))
{
win.Activate();
return win;
}
System.Windows.Controls.Control uiElement =
(System.Windows.Controls.Control) Activator.CreateInstance(windowType, args);
object result = null;
if (uiElement is Window)
result = WpfMdiHelper.ShowWpfWindowInMdi((Window) uiElement);
else
result = WpfMdiHelper.ShowWpfControlInMdi((System.Windows.Controls.Control) uiElement);
if (result is System.Windows.Forms.Form)
{
_definitionToWindow.Add(def, result as System.Windows.Forms.Form);
lock (_windowslock)
{
_windows.Add((System.Windows.Forms.Form) result, uiElement as IHasViewModel);
}
((System.Windows.Forms.Form) result).Disposed += new EventHandler(WindowsFactory_Disposed);
}
return result;
}
}
catch (Exception ex)
{
Logger.WriteError("Window creation exception", ex.ToString(), LogEntryCodes.UIException);
}
return null;
}
代码或多或少的作品,但是当你点击它打开了多个窗口,快速连续打开了一扇窗几种类型的按钮。
运行调试跟踪之后,我发现lock (_definitionToWindow)
被所有的点击绕过(看起来像是所有的调用都在同一个线程上)并且方法块在Activator.CreateInstance
上。所以当第二次调用到达字典时,检查它没有找到任何以前的实例并继续重新创建窗口。
任何人都知道为什么会发生这种情况?以及处理这种情况的正确方法?
为了给出更多的信息,它看起来像是同一个线程(这解释了为什么锁不起作用)是由同一个线程在该代码中执行两次? – 2012-02-22 12:22:44
在STA线程上使用* lock *是非法的。 CLR通过抽取消息循环来补偿它。这将导致Windows消息触发的任何事件(如点击)的重入执行。只有在必要时才在UI线程上运行与UI相关的代码Dispatcher.BeginInvoke()。所以你永远不需要使用* lock *。 – 2012-02-22 13:28:15
感谢那些信息,我所做的大多数Windows编程都在ASP.NET中,所以我不知道这一点。在这种情况下,它实际上是在线程中运行的与UI相关的代码,它创建并返回一个表单,但指向其他地方。 – 2012-02-22 15:29:31