Refactoring Silverlight ChildWindow for a non-modal use| Comments
UPDATE: FloatableWindow is now on CodePlex for easier community contributions and management of latest source and builds. FloatableWindow CodePlex Project. If you like this idea VOTE FOR IT in the Silverlight Toolkit!
I’ve seen a few comments/requests incoming lately that people like the ChildWindow control in the Silverlight 3 SDK. This is a great control that creates a modal dialog for you. When you use it, it disables your root layout application and shows the dialog you provide:
This is great for those true modal needs. It responds to normal windows DialogResult type responses if you have buttons, etc. – great for error dialogs, logins, etc. The request I’ve been seeing is for the same functionality, but in a ‘normal’ ChildWindow.
But I’ve been seeing requests that it should act more like the normal Window object in .NET, which has an option for showing a window as a ‘dialog’ (modal) versus a normal one. Well, since the source code is available under Ms-PL license at the Silverlight Toolkit project, I decided to play around and refactor a bit. If you look at the base class implementation of Window, the API shows two methods: Show and ShowDialog. This is what I wanted to emulate. I changed the ChildWindow to FloatableWindow only because I couldn’t think of a better name and it represented a desired behavior. In ChildWindow, the default behavior is a modal dialog and there are a few key areas that drive this behavior. There is a template part called Overlay that is responsible for the faded-out background of your app when the ChildWindow is shown. The other modal semantics are driven by looking at the RootLayout of the parent creating the ChildWindow and changing its properties (IsEnabled=False). Basically I just spelunked these areas and did some changing.
I implemented a property IsModal (_modal for the private accessor) that would be set in my new show methods, which I refactored to Show, ShowDialog and ShowWindow (internal). ShowWindow would accept a boolean whether it was to be a modal or not, setting the private accessor. The calls checking for disabling RootLayout, UpdateOverlaySize, ChangeVisualState and some of the focus event handling (as in a non-modal you may have multiple and you want each to be able to have focus). After doing this I could create non-modal windows easily:
1: FloatableWindow fw = new FloatableWindow();
2: fw.Title = "Testing FloatableWindow";
3: fw.Height = 200;
4: fw.Width = 200;
5: fw.Content = "Created at " + DateTime.Now.ToLongTimeString();
7: fw.Show(); //for non-modal
8: fw.ShowDialog(); //for modal dialog
And I could create multiple:
All the other functions of the ChildWindow are there so there wasn’t a lot of work to do. I kept the template parts, etc. so it is customizable in tools like Expression Blend. There are a few things that I still need to do:
- Better enable a default start position for the FloatableWindow
- On focus events, if there are multiple windows, make sure that the selected window gets brought to the front of the layout when being used (NOTE: the logic for this is working actually, but ZIndex doesn’t appear to be able to be set on Popup, which I’m talking with the team about)
- Whatever other bugs I may have caused by my assumptions :-)
But it was an experiment at least and seems to work so far. Here’s the code: FloatableWindow_1.1.zip. The archive file includes the code I used as well as Visual Studio item templates (C# and Visual Basic) to mirror the same functionality of Add New Item where you can add a new ChildWindow to your project as a user control.
Let me know what you think. Hope this helps!
Please enjoy some of these other recent posts...