Categories
Programming WPF

Using Windows in WPF

On our Manning book forum, I received a question from trifonius regarding the use of multiple windows in WPF:

First of all, I’d like to compliment the authors with the book. It’s a great read, thorough explanations and clear examples.
I’m working on an application that needs to be able to edit data as well as showing reports on data. Since these two interfaces are very different I think I need multiple windows in this app, available from a menu or something.
Since there is no mention in the book of multiple windows, I wonder whether this is the recommended way to go. Is it advisable to use panels with controls and set their visibility (or something like that) instead? Seems like a bit of a hassle to me.
If it is fine to use multiple windows, how can I display them from selecting a menu item?
Thanks

Thank you for the compliments! It’s great to hear that our work is proving to be beneficial. It’s the result of a lot of blood, sweat, and tears, and mostly blood… 🙂
It’s fine to use multiple windows in a WPF application. For various reasons we had to cut some material, including drag and drop and multiple windows, but that should not be interpreted as a recommendation against them. It’s true that some people are very adamant about not having multiple windows, but it really comes down to what problem you are trying to solve, who are your users, and what your application does.
Working in a single window was a limitation of web development for a long time, and it forced web developers to think of new approaches to solve problems typically addressed by windowing operating systems. This resulted in some very nice UI approaches, but also resulted in what I see as an over-correction where a group of those people came to view windowing in general as “evil.” One of the more effective counter arguments comes from multiple monitor configurations.
I have used multiple monitors for years, and found the productivity of having 2 or more screens is unquestionable. An application that does not allow you to open multiple windows is fundamentally incapable of taking advantage of such a configuration, so if you have anything in your application that might be able to make better use of monitor real estate, definitely look here. Think about the XAML Designer itself in Visual Studio. If you have two monitors, wouldn’t it be great to open the XAML window on one monitor, and the full design surface on another? You can’t now, but this strikes me as a major omission. (The poor man’s approach is to split the designer and xaml vertically, then stretch the window across both monitors and you get nearly the right effect).
That’s enough pontificating (for now) so on to your question…
On the context menu of your WPF Application project, you can select “Add/Window…” to create the Window XAML and code. For the sake of this example, I created a new project and left the Window1, and created a new Window called “DataEditWindow”
Add a CommandBinding and a both a Button and MenuItem to demonstrate the call:

    
        
            
        
        
            
                
                    
                
            
            
        
    

In the cs file, a couple special notes apply:
If you want to give the new window a particular DataContext for binding, you can set it here. Also, the Window should know who its parent is, so always set the Owner property to the Window you are launching from. In this example I’m binding to the ApplicationCommands.New command, but you could just as easily bind it to a control event or RoutedEvent (I tend to recommend thinking and binding in terms of commands):

private void new_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = true;
}
private void new_Executed(object sender, ExecutedRoutedEventArgs e)
{
    var window = new DataEditWindow()
        {
            DataContext = DataContext,
            Owner = this,
        };
    bool? result = window.ShowDialog();
    if (result.HasValue && result.Value)
	MessageBox.Show("Ok clicked");
    else if (result.HasValue && !result.Value)
	MessageBox.Show("Cancel clicked");
    //window.Show(); // Show window, but do not wait
}

The next bit is a choice. If you want the window to be model and block all operations in the parent window (a print dialog is a good example where modal makes sense), then use the window.ShowDialog() method. If the window is more of a palette and you want to allow the user to be able to continue using the application, use the window.Show() method. Too many modal windows can be frustrating, but attempting to handle state changes can also hurt.
Since window.Show() is the simple case, this is what you’ll need to add to the child window for handling the DialogResult. In the XAML, we’ll need some buttons to let the user indicate their intent with the dialog:
DataEditWindow.xaml:

    
        
            
            
        
    

Then you will need to set the DialogResult before you close the window so that the caller can decide what to do. This way, the parent window can decide whether to take the action or not. Note that you will get an exception if you try to set DialogResult, but the window was opened with window.Show(), so if you want this window to be dual purpose, you will have to handle both cases.
DataEditWindow.cs:

private void Ok_Click(object sender, RoutedEventArgs e)
{
    DialogResult = true;
    Close();
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
    DialogResult = false;
    Close();
}

In an application I would tend towards the approach of creating a DataTemplate, and I would create a generic WPF Window class that is simple a ContentControl. Set the DataContext of the Window to the object you want to edit, and let the template system pull up the right template for the editor. Something like this:


    
        
        
    
    
    

With this approach, you can choose to show the editor in-place or show it in a window with very few code changes.