CodeProject, WPF

Winforms / WPF Interop

In this blog entry I will discuss what you need to do to successfully interop Winforms with a WPF application and vice versa

In order to evaluate these 2 different interop methods, 2 demo projects have been created which carry out the functionality shown below :

  • .NET Winforms userControl within a .NET3.0/3.5 WPF application
  • .NET3.0/3.5 WPF userControl within a .NET Winforms application

A UserControl was chosen for its ease of development coupled with the fact that the Interop item will always be hosted in a Window of the interop hosts choosing.

As such the interop test item had to either be a UserControl or CustomControl. UserControl was picked for the reason stated above.

By using these 2 demos project the .NET 2.0 <-> .NET3.0/3.5 Interop is able to be tested for suitability for use on a commercial product.

Just What Is Interop

Interoperability is a property referring to the ability of diverse systems and organizations to work together (inter-operate). The term is often used in a technical systems engineering sense, or alternatively in a broad sense, taking into account social, political, and organizational factors that impact system to system performance.

With respect to software, the term interoperability is used to describe the capability of different programs to exchange data via a common set of exchange formats, to read and write the same file formats, and to use the same protocols.

http://en.wikipedia.org/wiki/Interoperability, up on date 26/02/2008

How to get a Winform control working within a WPF application

In order use a Winforms UserControl/CustomControl within a WPF application host, the following steps must be taken:

1. Reference the WindowsFormsIntegration.dll (should be in the GAC)

2. Reference the actual Winforms UserControl/CustomControl projects

3. Add the following using statement to the code behind for the Window/Page that is hosting the Winforms UserControl/CustomControl

using System.Windows.Forms.Integration;

4. Within the Window/Page that is hosting the Winforms UserControl/CustomControl add an xmlns declaration which declares the actual Winforms UserControl/CustomControl dll, an example is as follows:

xmlns:winforms="clr-namespace:WinformsUserControl;
assembly=WinformsUserControl"  

5. Within the Window/Page that is hosting the Winforms UserControl/CustomControl add a Winforms interop container to host the actual UserControl/CustomControl, and also add and name the UserControl/CustomControl, and example is as follows:

<!-- Winforms User Control -->
<WindowsFormsHost  Height="auto" Width="auto">
    <winforms:WinformsUserControl x:Name="winformsUserControl" 
CustomEvent="WinformsUserControl_CustomEvent" />
</WindowsFormsHost>

I tested out the following features, and this is what the results were

Feature Did It Work
Displayed the same as Winforms version No
Property set Yes
Property get Yes
Method call Yes
Custom Event Subscription Yes
Custom EventArgs Yes

How to get a WPF control working within a Winforms application

In order use a WPF UserControl/CustomControl within a Winforms application host, the following steps must be taken:

1. Reference the WindowsFormsIntegration.dll (should be in the GAC)

2. Reference the actual WPF UserControl/CustomControl projects

3. Add the following using statement to the code behind for the Form that is hosting the WPF UserControl/CustomControl

using System.Windows.Forms.Integration;

4. Within the Window/Page that is hosting the WPF UserControl/CustomControl add a WPF interop container to host the actual UserControl/CustomControl, and also add and name the UserControl/CustomControl, and example is as follows:

// Create the Instance Fields

private System.Windows.Forms.Integration.ElementHost elhostUserControl11;
private WPFUserControl.WPFUserControl wpfUserControl;

// Within InitializeComponent

this.elhostUserControl11 = new System.Windows.Forms.Integration.ElementHost();
this.wpfUserControl = new WPFUserControl.WPFUserControl();
....
....

this.elhostUserControl11.Location = new System.Drawing.Point(14, 54);
this.elhostUserControl11.Name = "elhostUserControl11";
this.elhostUserControl11.Size = new System.Drawing.Size(270, 27);
this.elhostUserControl11.TabIndex = 0;
this.elhostUserControl11.Text = "elementHost1";
this.elhostUserControl11.Child = this.wpfUserControl;
....
....

this.Controls.Add(this.elhostUserControl11);

I tested out the following features, and this is what the results were

Feature Did It Work
Displayed the same as WPF version Yes
Normal Property set Yes
Normal Property get Yes
Dependency Property set Yes
Dependency Property get Yes
Method call Yes
Pre-Built Routed Event subscription Yes
Custom Routed event subscription Yes

To illustrate this further please find attached a small demo solution, which is available here

Advertisements
C#

Nice LINQ Debugger Visualizers

I dont know about you lot but I quite like LINQ and have just been digging around in the LINQ samples directory that comes with the .NET 3.5 install. So for me thats

C:Program FilesMicrosoft Visual Studio 9.0Samples1033CSharpSamples.zipLinqSamples

and I noticed 2 interesting projects there.

  1. QueryVisualizer
  2. ExpressionTreeVisualizer

Now I did some research and these are 2 nice Visualizers written by the nice folk at Microsoft to aid in the debugging of LINQ expression/queries.

Scott Guthrie (the man) has a nice blog entry about how to use the QueryVisualizer. Its even has some pretty pictures.

Anyways the idea is to open these 2 projects build them to Dlls and then copy them to your Visualizer directory. For me thats

Program FilesMicrosoft Visual Studio 9.0Common7PackagesDebuggerVisualizers

These 2 debuggers sure help when doing LINQ work.

Have fun

WPF

Consistent Window Look & Feel

As part of a beginners WPF series (Beginners WPF series) that I am writing at codeproject, I just start to write an article on DependancyProperties. As part of that, I started to write a bunch of demo projects to illustrate the joy of DependancyProperties to people. As a side effect, I had to think up good uses for the demos that were not to involved.

I started to write one for Attached DependancyProperties, and realised that it was actually a fairly good idea. The idea being that you may want all your applications windows to have the same look and feel. Maybe a top banner, some content, and bottom status bar. So I had a think about this, and decided this could be easily achieved through the use of a single Attached DependancyProperty.

Using my solution is really easy, if you want to use the “Common” look and feel just set a DP in the Window declaration within the XAML or code behind, and that’s it. Shall we have a look at the code.

<Window x:Class="Attached_Properties_DPs.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Attached_Properties_DPs"
    local:AttachedPropertyChildAdder.IsMasterHeaderApplied="true"
    WindowStartupLocation="CenterScreen"
    Title="Attached_Properties_DPs" Height="400" Width="600">
        <!-- Extra content will be added here at runtime if the
             local:AttachedPropertyChildAdder.
             IsMasterHeaderApplied="true" is set to true
             try changing the value of this in the top of this
             file, set it false and run me.
             See that there is no header applied if its false,
             and there is if its true -->
        <Button x:Name="btn1" Content="click me"
                Margin="10,10,10,10" Click="btn1_Click"/>
</Window>

As you can see this example has the DP IsMasterHeaderApplied set to true, which means this Window will use the Common look and feel. So hows this work. Well its all down to the IsMasterHeaderApplied DP, which is as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Imaging; 

namespace Attached_Properties_DPs
{
    /// <summary>
    /// A simply show case, to demonstrate a usage of an attached
    /// DP property.
    /// This example lets Windows add a header portion to the their
    /// default content with some new Contents. Kind of like using
    /// Master Pages in ASP .NET
    /// </summary>
    public class AttachedPropertyChildAdder
    {
        #region Register IsMasterHeaderApplied DP
        public static readonly DependencyProperty
            IsMasterHeaderAppliedProperty =
            DependencyProperty.RegisterAttached(
                "IsMasterHeaderApplied",
                typeof(Boolean),
                typeof(AttachedPropertyChildAdder),
                new FrameworkPropertyMetadata(
                    IsMasterHeaderAppliedChanged)); 

        public static void SetIsMasterHeaderApplied(
            DependencyObject element, Boolean value)
        {
            element.SetValue(IsMasterHeaderAppliedProperty, value);
        }
        public static Boolean GetIsMasterHeaderApplied(
            DependencyObject element)
        {
            return (Boolean)element.GetValue(
                IsMasterHeaderAppliedProperty);
        }
        #endregion 

        #region PropertyChanged callback 

        /// <summary>
        /// Is called whenever a user of the
        /// IsMasterHeaderApplied Attached DP changes
        /// the IsMasterHeaderApplied DP value
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="args"></param>
        public static void IsMasterHeaderAppliedChanged(DependencyObject obj,
            DependencyPropertyChangedEventArgs args)
        {
            if ((bool)args.NewValue)
            {
                if (obj is Window)
                {
                    Window wnd = (Window)obj;
                    wnd.Loaded += new RoutedEventHandler(wnd_Loaded);
                }
            }
        } 

        /// <summary>
        /// Hook into the Window load event to replace the Content of the Window
        /// with some custom Content, to show case exactly how cool DPs are.
        ///
        /// In this example we are going to create a header for the Window.
        ///
        /// So setting the IsMasterHeaderApplied will make sure the Window
        /// gets a header applied.
        ///
        /// Kind of like Master Pages in ASP .NET
        /// </summary>
        public static void wnd_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                DockPanel dp = new DockPanel();
                dp.LastChildFill = true;
                StackPanel sp = new StackPanel();
                dp.Children.Add(sp);
                sp.Background = new SolidColorBrush(Colors.CornflowerBlue);
                sp.Orientation = Orientation.Vertical;
                sp.SetValue(DockPanel.DockProperty, Dock.Top);
                BitmapImage bitmap = new BitmapImage(
                    new Uri("Images/Header.png", UriKind.Relative));
                Image image = new Image();
                image.Source = bitmap;
                sp.Children.Add(image);
                UIElement el =
                    ((DependencyObject)sender as Window).Content as UIElement;
                el.SetValue(DockPanel.DockProperty, Dock.Bottom);
                ((DependencyObject)sender as Window).Content = null;
                dp.Children.Add(el);
               ((DependencyObject)sender as Window).Content = dp;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(
                    string.Format("Exception : {0}",ex.Message));
            }
        }
        #endregion
    }
}

As can be seen, we simply use the Window.Loaded event, and keep the original Window content safe, and then create the “Common” layout, and then re-add the original content.

This maintains all the wiring of RoutedEvents that the original content had in place.

This example simply shows an image banner at the top of any Window that sets the IsMasterHeaderApplied DP to true. And when run it looks like this.

logo

Have a look at the original XAML, you see it declares the Button, but doesn’t declare the top banner, that is added by the IsMasterHeaderApplied DP.

Ok this is a very simple example, but lets say the “Common” content contained all the menus wired up to RoutedCommands and all the footer/status area etc etc.

I think it would work well.