Nov 302009
 

I didn’t know this was possible until a few days back when a user asked about it on one of the MSDN forums. The query was on how to integrate Winforms and WPF i.e. how to display WPF user controls in Winform application. This feature can be extremely useful because some elements and effects which are easy in WPF can make you sweat a lot in Winforms.

Also this might be useful when you are eventually looking to migrate your application GUI to WPF. So when you are able to create resuable user controls and reuse them in Winforms, it will allow you to port all your winform user controls to WPF one at a time.

The control in Winforms which can do this is the ElementHost which resides in the WindowsFormsIntegration assembly. The ElementHost is responsible for loading the WPF control and painting it. Lets see how to do it. First we will create a user control in WPF. The markup is

<UserControl x:Class="WpfApplication1.SampleWPF"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <Grid>
        <StackPanel Margin="12,91,12,30">

            <TextBlock HorizontalAlignment="Center" Text="Sample WPF Control"
                       FontSize="20"
                       FontFamily="Verdana"
                       />

            <Button Name="btnClick" Click="btnClick_Click" Content="Click ME" HorizontalAlignment="Stretch" />
        </StackPanel>
    </Grid>
</UserControl>

Nothing really, just a StackPanel inside the grid with a TextBlock and a Button. Just to see a WPF Event we hookup an event handler to the Button.

public partial class SampleWPF : UserControl
{
    public SampleWPF()
    {
        InitializeComponent();
    }

    private void btnClick_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("WPF says Hello");
    }
}

Now that the WPF part is done, all we need to do is create a Winform Host for this user control. Create a new Winform project and add a reference to the following dlls:-

  • PresentationCore.dll
  • PresentationFramework.dll
  • WindowsBase.dll
  • WindowsFormsIntegration.dll
  • Your WPF DLL which you just created.

Now just to show interoperability between WPF and Winforms, drag a Winforms label and button and hook an event handler to it. In the Form Load handler we create an ElementHost. Since we added the WPF control’s assembly reference, we can create an object of the WPF user control. Of course we cant add the control to the Form’s control collection since the Form object has no idea how to draw the WPF control. This is where the ElementHost control comes in. The ElementHost takes in the usercontrol as its child control and is added to the Winfrom. The code is:-

private void Form1_Load(object sender, EventArgs e)
{
    ElementHost _host = new ElementHost();
    _host.Dock = DockStyle.Fill;
    WpfApplication1.SampleWPF _wpfUserControl = new WpfApplication1.SampleWPF();
    _host.Child = _wpfUserControl;
    this.Controls.Add(_host);
}

private void btnWinClick_Click(object sender, EventArgs e)
{
    MessageBox.Show("Windows Says Hello");
}

And this works great. Both the events for the WPF user control and the Winform controls work here. Some screenshots below:-


WinForm

wpfclick

winclick

The magic here is done by ElementHost and another class AvalonAdapter. Avalon as you would recall was WPF’s code name in its early stages of development. The Avalon Adapter is responsible for drawing the WPF application to the Windows form. The hWndSource object is responsible for creating the hWnd for the window. Using this you can actually make WPF interop with Win32 applications as well.

This method is not without its limitations though, you cant pretty much do anything which is possible with WPF, for e.g transparency