WPF and MDI

by Matthias Broschk April 03, 2009 15:27

I have recently started looking into WPF and have therefore started to update one of my old WinForms applications.

It's GUI consists of a single MDI-container form and about 50 MDI-child forms, which are of course not visible at the same time. Surely I don't to want update all of these forms to WPF at once, but rather step by step. Fortunately you can use the old WinForms technology within a WPF-Project. This way I could develop all new forms with WPF and would still be able to use the old forms and update them incrementally.

So far so good. Unfortunately this is the point where I ran into a major issue: WPF does not support MDI (yet). The reasons can be found here. Since the GUI of old WinForms application is mainly based on MDI this is quite a large obstacle. Neither do I intent to completely redesign the GUI nor would I have any idea how to achieve it in a user-friendly style, therefore traditional MDI is the only choice.

I have found several interesting solutions on the Internet ( #1 and #2 ), but neither of them really suits my purpose. So I started to create my own solution: I will have to use the old MDI-container form, since there is absolutely no equivalent construction in WPF. This would allow me to easily integrate the old MDI-child forms..

But what about the new WPF-based MDI-child forms? One possible option would be to use empty WinForms forms in combination with WPF user controls embedded on an elementhost-control. But this would be quite ugly, since I plan to fully get rid of the old WinForms technology in the long term and don't intend to change all of these ''hybrids" in the future, when WPF will support MDI.

So I tried to figure out, how to get a clean WPF form running as a MDI-child within a WinForms form. After having looked into the Windows API for some time I found the SetParent function. It is part of the user32.dll and changes the parent window of a specified child window. So I wrote the following few lines:

using System.Windows.Interop;
using System.Runtime.InteropServices;    
using System.Windows.Forms;
using System.Windows; 

class MDIHelper {       

[DllImport("user32.dll", EntryPoint = "SetParent")]       
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);       

 public void MakeMDI(Form MDIParentForm, Window childWindow)       
 {           
  IntPtr childHwnd = new WindowInteropHelper(childWindow).Handle;           
  IntPtr parentHwnd = MDIParentForm.Handle;           

  SetParent( childHwnd, parentHwnd );       
 }    
}

The code is simple and self-explanatory: It determines the handles of parent (WinForms) and child (WPF) and calls the API function. The following lines show how to use it (called from the WinForms MDI-parent):

// Window1 is WPF-based
Window1 childWindow = new Window1();
childWindow.Show();

(new MDIHelper()).MakeMDI (this, childWindow);

 


The result: A WPF MDI-child within a WinForms MDI-parent. Well, there are of course some drawbacks: Since this is a rather simple solution, you don't have the full MDI functionality such as menu merging, arranging options, etc. Furthermore I have experienced abnormalities regarding the resizing behavior: The WPF windows' controls are positioned dependent on the parent's size. There should be some elegant way to solve this problem and I will post the solution when I find one. Source code is available here.

Tags: , , , , ,

WPF | Win32 API | C#

Comments

7/19/2009 3:01:01 PM #

запознанства

Thank you, for the source :) Cheers!

запознанства

7/22/2009 9:12:24 AM #

Hoodia

Great post - keep it up man :)

Hoodia

5/19/2010 4:31:17 AM #

Muhammad Adnan

first of all, i must say, very good work (y)

when i click on minimize button on any child winodw, it got disappeared.. any way to fix this issue...??

Muhammad Adnan United States

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen | Modified by Mooglegiant

About the author

Matthias Broschk from Hamburg (Germany) wrote his first goto statements in QuickBasic at the age of fifteen, switched to Visual Studio (i.e. Visual Basic / Visual C++) at version 5.0 and has been an addict of .NET since its early beginnings. There have been many other languages and frameworks (Java, PHP, ... ), but none about which he has been as enthusiastic as .NET. These days you can find more information in blogs rather than anywhere else. Therefore he has decided to share his experiences and start yet another .NET blog.