Integración de Windows Forms 2.0 en WPF
Esto a más de uno le puede parecer curioso a más de uno. ¿Para qué vamos a usar Windows Forms dentro de WPF si ya tenemos WPF? Eso, yo creo, que lo pensamos todos cuando empezamos con WPF, pero a medida que nos metemos en un proyecto nos damos cuenta que necesitamos más de que creemos Windows Forms, y para ser concretos las librerías de GDI+ (System.Drawing).
En mi caso tenía que integrar la captura de una WebCam en una ventana de WPF y grabarlo en el disco. En este artículo solo me centraré en lo primero, el tema de la grabación no es necesario para este ejemplo.
Para ello usé las librerías que se encuentran en este artículo de CodeProject.
Antes de empezar con el tema de integración voy a comentar una cosa. Para poder mostrar un control en Windows Forms éste se debe heredar de la clase Control (Sytem.Windows.Forms.Control, de la librería System.Windows.Forms.dll) mientras que para poder mostrar un elemento en WPF (declarándolo en XAML) éste se debe de heredar de la clase UIElement (System.Windows.UIElement, de la librería WindowsBase.dll). Y esa es la razón por la que no podemos añadir controles de Windows Forms en WPF y no podemos añadir controles de WPF en Windows Forms.
Pero todo tiene una solución, y esa se llama WindowsFormsIntegration.dll, que nos permite tanto la integración de controles de Windows Forms en WPF como la de elementos de WPF en Windows Forms.
Ya sé que esto es un poco lioso. Pero ahora vamos a ver un ejemplo. En este post solo trataremos de la integración de Windows Forms en WPF. Esto es lo que pretendemos obtener:

Para poder hacer ese ejemplo, debemos crear un proyecto tipo Windows Application (WPF), en mi caso C#. Y a él añadir las tres referencias que necesitamos:
· System.Windows.Forms
· DirectX.Capture
· WindowsIntegration
La última referencia es la importante en este caso, ya que debemos usar el objeto WindowsFormsHost.
El XAML de nuestro ejemplo es:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WebCamCapture.Window1"
x:Name="Window"
Title="Window1"
Width="350"
Height="400"
Loaded="WindowLoaded">
<Grid x:Name="LayoutRoot">
<WindowsFormsHost x:Name="wfh"
Height="300"
Width="300"
Margin="8,50,0,55"
HorizontalAlignment="Left" />
<ComboBox x:Name="VideoList"
SelectionChanged="VideoSelected"
HorizontalAlignment="Left"
Margin="64,12,0,0"
Width="232"
IsSynchronizedWithCurrentItem="True"
Height="24"
VerticalAlignment="Top" />
<Label Content="Video"
HorizontalAlignment="Left"
Margin="8,10.04,0,0"
Width="52"
VerticalAlignment="Top" />
</Grid>
</Window>
Y el C#:
DirectX.Capture.Capture capt = null;
DirectX.Capture.Filters filters = new DirectX.Capture.Filters();
DirectX.Capture.Filter _video = null;
private void WindowLoaded(object sender, RoutedEventArgs e)
{
VideoList.Items.Clear();
ListBoxItem m = new ListBoxItem();
m.Content = "(None)";
VideoList.Items.Add(m);
foreach (DirectX.Capture.Filter var in filters.VideoInputDevices)
{
ListBoxItem lbi = new ListBoxItem();
lbi.Content = var.Name;
VideoList.Items.Add(lbi);
}
VideoList.SelectedIndex = 0;
}
private void VideoSelected(object sender, SelectionChangedEventArgs e)
{
string codec = (string)(VideoList.SelectedValue as ListBoxItem).Content;
if (codec != "(None)")
{
foreach (DirectX.Capture.Filter var in filters.VideoInputDevices)
{
if (var.Name == codec)
{
_video = var;
break;
}
}
Start();
}
}
private void Start()
{
if (capt == null)
{
capt = new DirectX.Capture.Capture(_video, null);
//Usamos la propiedad Child del WindowsFormsHost
//para poner controles de Windows Forms
wfh.Child = new System.Windows.Forms.Panel();
capt.PreviewWindow = wfh.Child;
}
else
{
System.Windows.Forms.Control oldPreview = capt.PreviewWindow;
capt.PreviewWindow = null;
capt = new DirectX.Capture.Capture(_video, null);
capt.PreviewWindow = oldPreview;
wfh.Child = capt.PreviewWindow;
}
}
Como podeis ver usando la propiedad Child del WindowsFormsHost podemos incluir controles de Windows.Forms
.