我以下代码以mdi形式创建窗口。这个想法是创建一个特定类型的窗口,如果它存在,或者如果已经存在实例则将它带到前面。
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
上阻塞。因此,当第二个调用到达字典时,检查它找不到任何先前的实例并继续重新创建窗口。
任何人都知道为什么会这样?以及处理这种情况的正确方法?
答案 0 :(得分:3)
这应该给你一个线程安全锁,只允许一个调用者进入CreateWindowImpl,即使它们在同一个线程上。它不会阻塞任何线程,但与lock()不同。
static long Locked = 0;
static void CreateWindow(...)
{
if(0 == Interlocked.Exchange(ref Locked, 1))
{
try
{
CreateWindowImpl(...);
}
finally
{
Interlocked.Exchange(ref Locked, 0);
}
}
}