Search code examples
wpfcaliburn.microwindow-management

reactivate exiting window using WindowManager


I am using WPF with the currently latest and greatest version of Caliburn.Micro (1.4.1). I use IWindowManager.ShowWindow(...) to open an new modeless window:

private void OpenOrReactivateInfoView()
{
    if(this.infoViewModel == null)
    {
        this.infoViewModel = new InfoViewModel();
    }

    this.windowManager.ShowWindow(this.infoViewModel);
}

Instead of opening a new window each time when OpenOrReactivateInfoView() is called, I would like to check whether the window ist still open and if it is, the existing window should just regain focus.

What would we be a good Calibrun.Micro-way to solve this? I sure would like to avoid keeping a reference to the window (or any UIElement for that matter) itself in the viewmodel. Also note that this is a common behavior for a lot of modeless dialogs, so it is preferred solve this in a generic reusable way.

Does Caliburn.Micro already have means for this built in?


Solution

  • A fairly straightforward way to keep track of your windows without actually having to implement IViewAware would be to keep a dictionary of weak references to your ViewModels and Views that go together and then checking if you already have an existing Window or not. Could be implemented either as a decorator to the WindowManager, subclass or extension.

    Something as simple as the following should do the trick assuming you don't actually plan on opening enough windows that even the dead WeakReferences would impact performance. If it is going to be long running it shouldn't be that hard to implement some sort of cleanup.

    public class MyFancyWindowManager : WindowManager
    {
        IDictionary<WeakReference, WeakReference> windows = new Dictionary<WeakReference, WeakReference>();
    
        public override void ShowWindow(object rootModel, object context = null, IDictionary<string, object> settings = null)
        {
            NavigationWindow navWindow = null;
    
            if (Application.Current != null && Application.Current.MainWindow != null)
            {
                navWindow = Application.Current.MainWindow as NavigationWindow;
            }
    
            if (navWindow != null)
            {
                var window = CreatePage(rootModel, context, settings);
                navWindow.Navigate(window);
            }
            else
            {
                var window = GetExistingWindow(rootModel);
                if (window == null)
                {
                    window = CreateWindow(rootModel, false, context, settings);
                    windows.Add(new WeakReference(rootModel), new WeakReference(window));
                    window.Show();
                }
                else
                {
                    window.Focus();
                }
            }
    
        }
    
        protected virtual Window GetExistingWindow(object model)
        {
            if(!windows.Any(d => d.Key.IsAlive && d.Key.Target == model))
                return null;
    
            var existingWindow = windows.Single(d => d.Key.Target == model).Value;
            return existingWindow.IsAlive ? existingWindow.Target as Window : null;
        }
    }