Wpf Bring a Hidden Window Back to Center

The Problem

If you have used the Infragistics xamDialogWindow control in your WPF or Silverlight application, I can probably guess your biggest complaint with the control.  I know what mine is!  Currently, the XamDialogWindow has to be part of the visual tree in order for you to use it in your View.  What do I mean by that?  It means that you have to predefine your XamDialogWindow above the top most element in your View, being sure to add any Grid.RowSpan and Grid.ColumnSpan properties, so that it will be properly displayed when you show the dialog to the user by using the WindowState property or calling the Show method.  If that still isn't clear, let the code do the talking.

This is what I have to do:

< Grid x : Name ="LayoutRoot" Background ="White">
< ig : XamDialogWindow x : Name ="_xamDialogWindow" StartupPosition ="Center" WindowState ="Hidden">
< StackPanel Margin ="25" Orientation ="Horizontal">
< Button Width ="75" Margin ="4" Content ="OK" />
< Button Width ="75" Margin ="4" Content ="Cancel" />
StackPanel >
ig : XamDialogWindow >
< Button Content ="Show xamDialogWindow" VerticalAlignment ="Center" HorizontalAlignment ="Center"
Click ="Button_Click"/>
Grid >

private void Button_Click( object sender, RoutedEventArgs e)
{
_xamDialogWindow.Show();
}

Remember, the xamDialogWindow has to be part of the visual tree, so first I have to declare all instances of the xamDialogWindow that your View will need in XAML.  Once you have declared your xamDialogWindow instances, you must then provide some type of mechanism to display the dialog to your user.  In this example we add a simple button with an event handler.  Now, you could create some reusable derived dialogs that will allow you to encapsulate any dialog logic and help you reuse the dialog throughout your application, but you will still need to add it the visual tree of your View somehow.  This is not what I want to do.  I want it simple.  Very simple.

This is what I want to do:

XamDialogWindow dialog = new XamDialogWindow ();
dialog.StartupPosition = StartupPosition .Center;
dialog.Show();

I want to be able to simply create a xamDialogWindow instance and have it displayed to the user whenever I call the XamDialogWindow.Show method.  It shouldn't matter if I am in the code-behind (which I hope you aren't), or from within my ViewModel (which you still shouldn't be).  I'll explain all that later.  It should be simple.

If you use the ChildWindow control in Silverlight, then you know exactly what I am talking about.  A common scenario is that you create a derived ChildWindow and then you can show it anywhere you feel like it form within your code.  Well, that is what we are going to do with the xamDialogWindow.

The Solution – Silverlight

In order to achieve our desired result, we need to create a derived version of the xamDialogWindow.  Let's start with a new Silverlight application, and then add a new user control to the project.  Yes you heard me correctly, I said SILVERLIGHT!  This is what my derived dialog looks like.

< ig : XamDialogWindow x : Class ="XamDialogWindowWithCode.Dialog"
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns : x ="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns : ig ="http://schemas.infragistics.com/xaml">

< Grid x : Name ="LayoutRoot" Background ="White">
< StackPanel Margin ="25" Orientation ="Horizontal">
< Button Width ="75" Margin ="4" Content ="OK" />
< Button Width ="75" Margin ="4" Content ="Cancel" />
StackPanel >
Grid >

ig : XamDialogWindow >

It's nothing complicated.  Just a couple of buttons.  Now, you may be asking yourself, how are we going to get around this limitation of the control.  Simple!  We are going to place it inside a popup.  Let's add some code to the code-behind to see what I mean.

public partial class Dialog : XamDialogWindow
{
Popup _hostPopup;

public Dialog()
{
InitializeComponent();
WindowStateChanged += Dialog_WindowStateChanged;

_hostPopup = new Popup ();
_hostPopup.Child = this ;
}

void Dialog_WindowStateChanged( object sender, WindowStateChangedEventArgs e)
{
if (e.NewWindowState == Infragistics.Controls.Interactions. WindowState .Hidden)
_hostPopup.IsOpen = false ;
}

public new void Show()
{
base .Show();

_hostPopup.IsOpen = true ;
}
}

All we did was programmatically create a Popup, set it's content to the derived Dialog control, the control displaying the popup by creating a new Show method and making sure we close the Popup when the WindowState changes to Hidden.  Not so complicated now is it?  Now let's look at how we can create an instance of the control in code and display it to our user by calling the Show method.

private void Button_Click( object sender, RoutedEventArgs e)
{
Dialog dialog = new Dialog ();
dialog.Show();
}

xamDialogWindow in code behind for WPF and Silverlight

That's it.  So what about a ViewModel?  Alright, in case you still don't believe me that it will work in code no matter where you are at, let's check out a ViewModel approach.

public class ViewModel
{
public ICommand ShowDialogCommand { get ; private set ; }

public ViewModel()
{
ShowDialogCommand = new ShowDialogCommand ();
}
}

public class ShowDialogCommand : ICommand
{
public bool CanExecute( object parameter)
{
return true ;
}

public event EventHandler CanExecuteChanged;

public void Execute( object parameter)
{
Dialog dialog = new Dialog ();
dialog.Show();
}
}

< Grid x : Name ="LayoutRoot" Background ="White">
< Button Content ="Show xamDialogWindow" VerticalAlignment ="Center" HorizontalAlignment ="Center"
Command ="{ Binding ShowDialogCommand} "/>
Grid >

We just created a simple ViewModel, a simple Command (since we aren't using a DelagateCommand or a Relay Command), and then updated the View's DataContext and set our Button's binding.  Nothing complicated, yet we still get the same result when we click the button.

image

Oh, and don't worry, it will still work as Modal as well.  Just so you know, the gray is the Modal background.

A Modal XamDialogWindow in code behind for WPF and Silverlight

Now this particular sample was done in Silverlight, but the same approach can be taken in WPF.

Solution – WPF

This was really easy to implement for Silverlight, but to get the same type of functionality in WPF, it will take a little extra work to get the Popup to behave like you want it to.  First let's add a new WPF Application project to our Visual Studio Solution and immediately open up the Project Properties.  Now change the default namespace to match that of the Silverlight namespace.  Next, go to the Build tab and add a "Conditional compilation symbol" named WPF.  This will allow us to share all of our code across both WPF and Silverlight.

image

Now, let's add both the Dialog.xaml/cs and the ViewModel.cs files from our Silverlight project to our WPF project as a file link.  Right click the WPF project and selected "Add Existing Item".  Navigate to the Silverlight files and add the files as a link by selecting the drop down arrow in the add button and selecting the "Add as Link" option.

image

Now we will need to modify our Dialog.cs file to accommodate our WPF specifics.  First off, in Silverlight we don't have to worry about multiple Windows like we do in WPF.  We also don't have to worry about the moving of a Window or the resizing of a Window in Silverlight like we do in WPF.  The goal of the WPF version is to keep the Dialog within the bounds of the Window, but still be able to show the Dialog from code.  Also, if it's Modal, we want to cover up the entire Window including the minimize, maximize, and close buttons.  We want it to be truly modal.  We will also need to handle the resizing of a parent Window and the movement of the Window.  Seems WPF introduces a lot of hurdles we must jump over, but it's nothing we can't handle.  I made some modifications to the Dialog.cs file.  Let's look at the file, then talk about it.

public partial class Dialog : XamDialogWindow
{
Popup _hostPopup;

#if WPF
Window _parentWindow;

0 Response to "Wpf Bring a Hidden Window Back to Center"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel