devxlogo

Enable WPF/Windows Forms Interoperability with WPF Commands

Enable WPF/Windows Forms Interoperability with WPF Commands

uppose you’ve been given the green light to use Windows Presentation Foundation (WPF) in the latest version of your user interface. There’s just one snag?not all the third party controls critical to your application have a WPF version. Fortunately, WPF has excellent support for legacy controls; however, you’ll need to write some glue code to provide the interoperability.

Hosting a Windows Forms Control in WPF
The key element for hosting legacy controls in WPF is a special control called, appropriately enough, WindowsFormsHost. Here’s a walkthrough of the process for adding a Windows Forms TextBox to a WPF window.

First, create a window and, in the XAML, add the following namespaces to the tag:

   xmlns:my="clr-namespace:System.Windows.Forms.Integration;      assembly=WindowsFormsIntegration"     xmlns:Forms="clr-namespace:System.Windows.Forms;      assembly=System.Windows.Forms"

Next, add a WindowsFormsHost element to the window:

   

Now, add a Windows Forms TextBox as a child of the WindowsFormsHost element.

   
?
Figure 1. WPF Hosting Windows Forms Control: This Windows Forms TextBox control is hosted in a WPF window using the WindowsFormsHost control.

When you run the application, you’ll see a window similar to Figure 1.

You could accomplish the same thing in code by setting the Child property of the WindowsFormsHost to a System.Windows.Forms.TextBox, as shown below:

   System.Windows.Forms.TextBox textBox =       new System.Windows.Forms.TextBox();         textBox.Text = "Windows Forms TextBox";         windowsFormsHost1.Child = textBox;   ...

You aren’t limited to hosting Windows Forms controls in WPF applications; it’s just as easy to go the other direction and host WPF controls in your Windows Forms applications.

Hosting WPF Controls in Windows Forms
Microsoft followed a similar pattern to allow Windows Forms to host WPF controls. The Windows Forms counterpart to the WindowsFormsHost is called ElementHost. In Visual Studio 2008, you’ll find it on the WPF Interoperability tab of the Toolbox. Drag this control onto a Windows Form and then write the following code:

   System.Windows.Controls.TextBox textBox = new       System.Windows.Controls.TextBox();         textBox.Text = "WPF TextBox";         elementHost1.Child = textBox;   ...
?
Figure 2. Windows Forms Hosting WPF Control: This Windows Form hosts a WPF TextBox control by adding it as a child of an ElementHost control.

The resulting window at runtime should look something like Figure 2.

As you can see, it’s relatively easy to add controls of either type to a window of either type, but to interact with the hosted controls, you also need to be able to send commands and receive event messages.

Executing WPF Commands from Windows Forms
The key to executing commands is by interacting with the ICommand interface. Note that WPF commands are singleton objects that implement the ICommand interface, shown below:

   public interface ICommand   {       event EventHandler CanExecuteChanged;          bool CanExecute(object parameter);          void Execute(object parameter);   }

The ICommand interface is relatively self explanatory. To execute a command, invoke Execute. You can find out whether a specific command can execute or not via the CanExecute method. Finally, as its name suggests, the CanExecuteChanged event gets fired whenever the value returned by CanExecute changes.

To illustrate these features, hook up a Windows Forms menu to the ApplicationCommands.Paste command. The goal is to associate the Enabled property of the menu with the result from CanExecute; in other words, the menu item should be enabled when CanExecute is true and disabled when it’s false. To cause the paste to occur, invoke the Execute method of the Paste command when a user clicks the menu item.

Here’s a class called MenuCommandBridge that brings all this functionality together. The class has the following properties:

   public ICommand Command { get; private set; }   public ToolStripMenuItem MenuItem { get; private set; }   public Object CommandParameter { get; private set; }

Set the Command property to the command that you want to hook the menu up to (ApplicationCommands.Paste in this case). Set the MenuItem property to the MenuItem that invokes the command. The CommandParameter property is an optional value that you can pass to the ICommand.Execute and ICommand.CanExecute methods.

The following event handler code invokes the command:

   private void MenuItemClicked(object sender, EventArgs e)   {      this.Command.Execute(this.CommandParameter);   }

When the CanExecute state of the command changes, this code updates the UI:

   private void CanExecuteChanged(object sender, EventArgs e)   {      this.MenuItem.Enabled = Command.CanExecute(         this.CommandParameter);   }

To hook up a menu item to the Paste command, this line of code goes into the constructor of the form (after the InitializeComponent call):

   MenuCommandBridge commandBridge =       new MenuCommandBridge(      ApplicationCommands.Paste,       menuPaste, null)   
Author’s Note: You must hold a reference to the MenuCommandBridge for the lifetime of the menu. An easy way to do this is to store it in a collection as a member of the form.

Responding to a WPF Command from Windows Forms
To allow a Windows Forms control to respond to a WPF command, you must host that control in a WindowsFormHost element in WPF (as described above). The solution described here takes advantage of the CommandBindings collection of the UIElement class (WindowsFormsHost inherits from UIElement). By creating CommandBindings, you can effectively wire up your Windows Forms control to a given WPF Command.

As with the previous example, it’s convenient to use a class (TextboxCommandBridge) to wrap up all this functionality. The example shown here focuses on the Paste command, but the downloadable code for this article includes implementations for the Cut and Copy commands as well.

The constructor tells most of the story:

   TextboxCommandBridge(TextBox textBox, WindowsFormsHost host)   {      _textBox = textBox;         host.CommandBindings.Add(new                    CommandBinding(ApplicationCommands.Paste,          new ExecutedRoutedEventHandler(PasteCommandExecuted),          new CanExecuteRoutedEventHandler(PasteCommandCanExecute)));   }

The constructor adds a CommandBinding to the host of the Windows Forms control. Notice that the constructor of the CommandBinding class accepted delegates for Executed and CanExecute.

In the implementation of the Executed delegate, TextBox.Paste does the heavy lifting:

   void PasteCommandExecuted(object sender,       ExecutedRoutedEventArgs args)   {      _textBox.Paste();   }   

In the CanExecute delegate, you have to perform some logic to determine whether the user should be able to paste, by calling the PasteCommandCanExecute method:

   void PasteCommandCanExecute(object sender,       CanExecuteRoutedEventArgs args)   {      args.CanExecute = !_textBox.ReadOnly         && _textBox.Enabled &&               System.Windows.Clipboard.ContainsText();   }

At this point, the menu enables only when the TextBox is not read only, is enabled, and the clipboard contains some text to paste.

WPF/Windows Forms Interoperability Limitations
While the interoperability support between WPF and Windows Forms is very powerful, there are a few things that you should avoid. For example, while WPF windows support transparency, Windows Forms controls do not. Also, transformations such as rotation do not work for Windows Forms controls even if they are hosted in WPF.

Another scenario to avoid is overlapping ElementHosts, because the ElementHosts don’t interact?they are rendered as separate items.

Finally, focus is handled differently between WPF and Windows Forms. While delving into the details of these differences is beyond the scope of this article, you shouldn’t assume that a Windows Forms control placed on a WPF window will behave in exactly the same way in terms of focus.

Despite these minor problems, I hope you’ve seen that?whether you’re building a new WPF project that needs to host some existing Windows Forms controls, or extending a Windows Forms project but want to take advantage of WPF controls?the process for hosting the controls is both similar and reasonably easy to accomplish.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist