Reputation: 4741
I the following code that creates windows in an mdi form. The idea is to create a window of a certain type if it dosent exist, or bring it to front if there is already an instance.
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;
}
The code more or less works, but when you click a button that opens a window several types in quick succession it opens up several windows.
After running debug traces I found that lock (_definitionToWindow)
is being bypassed by all the clicks (it looks like all calls are being made on the same thread) and the method blocks on Activator.CreateInstance
. So when the 2nd call arrives to the dictionary check it doesn't find any previous instances and proceeds to recreate the window.
Anyone knows why this happens? and the proper way to handle this situation?
Upvotes: 1
Views: 1005
Reputation: 43011
This should give you a thread safe lock that only allows one caller into CreateWindowImpl even if they're on the same thread. It doesn't block any threads though unlike lock().
static long Locked = 0;
static void CreateWindow(...)
{
if(0 == Interlocked.Exchange(ref Locked, 1))
{
try
{
CreateWindowImpl(...);
}
finally
{
Interlocked.Exchange(ref Locked, 0);
}
}
}
Upvotes: 4