我下面的代碼創建一個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