Keeping track of open windows in WPF
Hopeful by now, everybody has seen the Lawson Smart Client created by Frog Design? If not, have a look here:
Read more about it here
I love the look and feel of this application, the part that looked trick to me thou was the list of open windows at the top. This created the feel of a MDI application but just so much nicer!!!
So, how difficult is it to reproduce this?
I initially had 3 plans to reproduce this:
First I tried binding to Application.Current.Windows but this did not work! Next thing that came to mind for me was to create a new Window class derived from the standard Window. Each window created based on this Window can then register and de-register itself from a ObservableCollection somewhere! This will work but come on, this is WPF... their must be some cool way of doing this!
My Solution #3
If you are not familiar with Attached Properties first read this article
I created a attached property called WindowViewState.IsManaged? Just set this to true and the window will automatically be registered and de-registered! Sounds great but show me the code!
First I needed to create a WindowViewStateInstance, all this does is remember the friendly name of window (to be showed in the ListBox) and a VisualBrush to show a icon of the current window (Similar to vista's bottom preview).
public class WindowViewStateInstance
{
public string Title { get; set; }
public VisualBrush Icon { get; set; }
} |
Next step is to create a WindowViewStateManager that stores all the instances
public class WindowViewStateManager
{
static private WindowViewStateManager instance;
static public WindowViewStateManager Instance
{
get
{
if (instance == null)
instance = new WindowViewStateManager();
return instance;
}
}
ObservableCollection<WindowViewStateInstance> windowViewStates;
public ObservableCollection<WindowViewStateInstance> WindowViewStates
{
get { return windowViewStates ?? (windowViewStates = new ObservableCollection<WindowViewStateInstance>()); }
}
public bool RemoveWindowViewState(string Title)
{
var view = (from v in windowViewStates
where v.Title == Title
select v).First();
if (view != null)
{
windowViewStates.Remove(view);
return true;
}
return false;
}
} |
These two classes are very simple but thy form the backbone of this application!
Disclaimer: I currently use the Window.Title as my key to remove the window from my list... I know this is not great, but it works!
Update: I added a Identifier property that gets set automatically to a unique Guid. This is now used to identify each window!
Next is the Attached Properties... I highly recommend downloading Dr WPF's snippets to create DPs and APs! It makes your live so much simpler! Here is my AP
public class WindowViewState
{
public static readonly DependencyProperty IsManagedProperty =
DependencyProperty.RegisterAttached("IsManaged", typeof(bool), typeof(WindowViewState),
new FrameworkPropertyMetadata((bool)false,
new PropertyChangedCallback(OnIsManagedChanged)));
public static bool GetIsManaged(DependencyObject d)
{
return (bool)d.GetValue(IsManagedProperty);
}
public static void SetIsManaged(DependencyObject d, bool value)
{
d.SetValue(IsManagedProperty, value);
}
private static void OnIsManagedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Window target = (Window)d;
if (target != null)
{
target.Loaded += new RoutedEventHandler(target_Loaded);
target.Closed += new EventHandler(target_Closed);
}
}
static void target_Closed(object sender, EventArgs e)
{
Window target = (Window)sender;
if (target != null)
{
WindowViewStateManager.Instance.RemoveWindowViewState(target.Title);
}
}
static void target_Loaded(object sender, RoutedEventArgs e)
{
Window target = (Window)sender;
if (target != null)
{
WindowViewStateInstance instance = new WindowViewStateInstance();
instance.Title = target.Title;
instance.Icon = new VisualBrush(target);
WindowViewStateManager.Instance.WindowViewStates.Add(instance);
}
}
} |
And that is it! My attached property creates a Loaded and Closed event handler for the window that adds or removes the window instance from my list!
The attached properties makes adding this type of management of windows very easy
local:WindowViewState.IsManaged="true" |
All that is now left to do is restyle my ListBox slightly and here is the result
Disclaimer: My windows that I open is just jpgs downloaded from the net of various WPF applications!
OK, so my design skills suck... but it is functional and it is a great way to keep track of all your windows currently open!
I still have loads of work to make it better but this is at least a very good starting point!