Exportar (0) Imprimir
Expandir todo
Este artículo se tradujo de forma manual. Mueva el puntero sobre las frases del artículo para ver el texto original.
Traducción
Original

Tutorial: Hospedar un control compuesto de formularios Windows Forms en WPF

Windows Presentation Foundation (WPF) proporciona un entorno enriquecido para crear aplicaciones. Sin embargo, cuando se tiene una inversión sustancial en código de Windows Forms, puede resultar más efectivo reutilizar al menos parte de ese código en la aplicación de WPF en lugar de volver a escribirlo todo desde el principio. El escenario más común es el caso en que ya existen controles de Windows Forms. En algunos casos, puede que ni siquiera tenga acceso al código fuente de estos controles. WPF proporciona un procedimiento sencillo para hospedar estos controles en una aplicación WPF. Por ejemplo, puede utilizar WPF para realizar la mayoría de la programación al hospedar los controles DataGridView especializados.

Este tutorial describe una aplicación que hospeda un control compuesto de Windows Forms para realizar la entrada de datos en una aplicación de WPF. El control compuesto se empaqueta en una DLL. Este procedimiento general se puede hacer extensivo a aplicaciones y controles más complejos. Este tutorial se ha diseñado para que sea casi idéntico en aspecto y funcionalidad a Tutorial: Hospedar un control compuesto de WPF en formularios Windows Forms. La diferencia principal es que se invierte el escenario de hospedaje.

El tutorial está dividido en dos secciones. La primera sección describe brevemente la implementación del control compuesto de Windows Forms. La segunda sección explica en detalle cómo hospedar el control compuesto en una aplicación de WPF, recibir eventos del control y obtener acceso a algunas de las propiedades del control.

Las tareas ilustradas en este tutorial incluyen:

  • Implementar el control compuesto de Windows Forms.

  • Implementar la aplicación host de WPF.

Para ver una lista de código completa de las tareas mostradas en este tutorial, vea Hosting a Windows Forms Composite Control in WPF Sample.

Necesita los componentes siguientes para completar este tutorial:

  • Visual Studio 2010.

El control compuesto de Windows Forms utilizado en este ejemplo es un formulario de entrada de datos simple. Este formulario toma el nombre del usuario y su dirección y, a continuación, utiliza un evento personalizado para devolver esa información al host. En la siguiente ilustración se muestra el control representado.

Control compuesto de Windows Forms

Control simple de formularios Windows Forms

Crear el proyecto

Para iniciar el proyecto:

  1. Inicie Microsoft Visual Studio y abra el cuadro de diálogo Nuevo proyecto.

  2. En la categoría de ventana, seleccione la plantilla Biblioteca de controles de Windows Forms.

  3. Denomine el nuevo proyecto MyControls.

  4. Para la ubicación, especifique una carpeta de nivel superior con un nombre adecuado, por ejemplo WpfHostingWindowsFormsControl. Más adelante, colocará la aplicación host en esta carpeta.

  5. Haga clic en Aceptar para crear el proyecto. El proyecto predeterminado contiene un solo control cuyo nombre es UserControl1.

  6. En el Explorador de soluciones, cambie el nombre UserControl1 por MyControl1.

El proyecto debe tener referencias a las siguientes DLL del sistema. Si cualquiera de estas DLL no está incluida de forma predeterminada, agréguela al proyecto.

  • Sistema

  • System.Data

  • System.Drawing

  • System.Windows.Forms

  • System.Xml

Agregar controles al formulario

Para agregar controles al formulario:

  • Abra MyControl1 en el diseñador.

Agregue cinco controles Label y sus controles TextBox correspondientes, con los tamaños y la organización indicados en la ilustración anterior, en el formulario. En el ejemplo, los controles TextBox tienen los nombres siguientes:

  • txtName

  • txtAddress

  • txtCity

  • txtState

  • txtZip

Agregue dos controles Button con las etiquetas Aceptar y Cancelar. En el ejemplo, los nombres de botón son btnOK y btnCancel, respectivamente.

Implementar el código de compatibilidad

Abra el formulario en la vista de código. El control devuelve los datos recolectados al host provocando el evento OnButtonClick personalizado. Los datos están contenidos en el objeto de argumento de evento. En el siguiente código se muestra la declaración del evento y el delegado.

Agregue el código siguiente a la clase MyControl1.


public delegate void MyControlEventHandler(object sender, MyControlEventArgs args);
public event MyControlEventHandler OnButtonClick;


La clase MyControlEventArgs contiene la información que se devolverá al host.

Agregue la clase siguiente al formulario.


public class MyControlEventArgs : EventArgs
{
    private string _Name;
    private string _StreetAddress;
    private string _City;
    private string _State;
    private string _Zip;
    private bool _IsOK;

    public MyControlEventArgs(bool result,
                                   string name,
                                   string address,
                                   string city,
                                   string state,
                                   string zip)
    {
        _IsOK = result;
        _Name = name;
        _StreetAddress = address;
        _City = city;
        _State = state;
        _Zip = zip;
    }

    public string MyName
    {
        get { return _Name; }
        set { _Name = value; }
    }
    public string MyStreetAddress
    {
        get { return _StreetAddress; }
        set { _StreetAddress = value; }
    }
    public string MyCity
    {
        get { return _City; }
        set { _City = value; }
    }
    public string MyState
    {
        get { return _State; }
        set { _State = value; }
    }
    public string MyZip
    {
        get { return _Zip; }
        set { _Zip = value; }
    }
    public bool IsOK
    {
        get { return _IsOK; }
        set { _IsOK = value; }
    }
}


Cuando el usuario hace clic en el botón Aceptar o Cancelar, los controladores del evento Click crean un objeto MyControlEventArgs que contiene los datos y provoca el evento OnButtonClick. La única diferencia entre los dos controladores es la propiedad IsOK del argumento de evento. Esta propiedad permite al host determinar en qué botón se hizo clic. Se establece en true para el botón Aceptar y en false para el botón Cancelar. En el siguiente código se muestran los controladores de los dos botones.

Agregue el código siguiente a la clase MyControl1.


private void btnOK_Click(object sender, System.EventArgs e)
{

    MyControlEventArgs retvals = new MyControlEventArgs(true,
                                                         txtName.Text,
                                                         txtAddress.Text,
                                                         txtCity.Text,
                                                         txtState.Text,
                                                         txtZip.Text);
    OnButtonClick(this, retvals);
}

private void btnCancel_Click(object sender, System.EventArgs e)
{
    MyControlEventArgs retvals = new MyControlEventArgs(false,
                                                         txtName.Text,
                                                         txtAddress.Text,
                                                         txtCity.Text,
                                                         txtState.Text,
                                                         txtZip.Text);
    OnButtonClick(this, retvals);
}


Dar un nombre seguro al ensamblado y generar el ensamblado

Para que una aplicación de WPF pueda hacer referencia a este ensamblado, debe tener un nombre seguro. Para crear un nombre seguro, cree un archivo de clave con Sn.exe y agréguelo al proyecto.

  1. Abra un símbolo del sistema de Visual Studio. Para ello, haga clic en el menú Inicio y seleccione Todos los programas/Microsoft Visual Studio 2010/Visual Studio Tools/Símbolo del sistema de Visual Studio. Se iniciará una ventana de consola con variables de entorno personalizadas.

  2. En el símbolo del sistema, utilice el comando cd para ir a la carpeta del proyecto.

  3. Genere un archivo de clave con el nombre MyControls.snk ejecutando el comando siguiente.

    Sn.exe -k MyControls.snk
    

  4. Para incluir el archivo de clave en el proyecto, haga clic con el botón secundario en el nombre del proyecto en el Explorador de soluciones y, a continuación, haga clic en Propiedades. En el Diseñador de proyectos, haga clic en la pestaña Firma, active la casilla Firmar el ensamblado y, a continuación, busque el archivo de clave.

  5. Compile la solución. La compilación generará una DLL denominada MyControls.dll.

La aplicación host de WPF utiliza el control WindowsFormsHost para hospedar MyControl1. La aplicación controla el evento OnButtonClick para recibir los datos del control. También tiene una colección de botones de opción que permiten cambiar algunas de las propiedades del control desde la aplicación WPF. En la ilustración siguiente se muestra la aplicación acabada.

La aplicación completa, que muestra el control incrustado en la aplicación WPF

Control incrustado en una página de WPF

Crear el proyecto

Para iniciar el proyecto:

  1. Abra Visual Studio y seleccione Nuevo proyecto.

  2. En la categoría de ventana, seleccione la plantilla Aplicación WPF.

  3. Denomine el nuevo proyecto WpfHost.

  4. Para la ubicación, especifique la misma carpeta de nivel superior que contiene el proyecto MyControls.

  5. Haga clic en Aceptar para crear el proyecto.

También debe agregar referencias a la DLL que contiene MyControl1 y a otros ensamblados.

  1. En el Explorador de soluciones, haga clic con el botón secundario del mouse en el nombre del proyecto y seleccione Agregar referencia.

  2. Haga clic en la pestaña Examinar y busque la carpeta que contiene MyControls.dll. Para este tutorial, esta carpeta es MyControls\bin\Debug.

  3. Seleccione MyControls.dll y, a continuación, haga clic en Aceptar.

  4. Agregue una referencia al ensamblado WindowsFormsIntegration, que se denomina WindowsFormsIntegration.dll.

Implementar el diseño básico

La user interface (UI) de la aplicación host se implementa en MainWindow.xaml. Este archivo contiene el marcado de Extensible Application Markup Language (XAML) que define el diseño y hospeda el control de Windows Forms. La aplicación está dividida en tres áreas:

  • El panel Control Properties (Propiedades del control), que contiene una colección de botones de opción que puede utilizar para modificar varias propiedades del control hospedado.

  • El panel Data from Control (Datos del control) que contiene varios elementos TextBlock que muestran los datos devueltos del control hospedado.

  • El propio control hospedado.

El diseño básico se muestra en el código XAML siguiente. El marcado que se necesita para hospedar MyControl1 se omite en este ejemplo, pero se explicará más adelante.

Reemplace el XAML de MainWindow.xaml con lo siguiente. Si utiliza Visual Basic, cambie el nombre de la clase a x:Class="MainWindow".


<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="WpfHost.MainWindow"
      xmlns:mcl="clr-namespace:MyControls;assembly=MyControls"
      Loaded="Init">
  <DockPanel>
    <DockPanel.Resources>
      <Style x:Key="inlineText" TargetType="{x:Type Inline}">
        <Setter Property="FontWeight" Value="Normal"/>
      </Style>
      <Style x:Key="titleText" TargetType="{x:Type TextBlock}">
        <Setter Property="DockPanel.Dock" Value="Top"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Margin" Value="10,5,10,0"/>
      </Style>
    </DockPanel.Resources>

    <StackPanel Orientation="Vertical"
                DockPanel.Dock="Left"
                Background="Bisque"
                Width="250">

      <TextBlock  Margin="10,10,10,10"
                  FontWeight="Bold"
                  FontSize="12">Control Properties</TextBlock>
      <TextBlock Style="{StaticResource titleText}">Background Color</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalBackColor"
                    IsChecked="True"
                    Click="BackColorChanged">Original</RadioButton>
        <RadioButton Name="rdbtnBackGreen"
                    Click="BackColorChanged">LightGreen</RadioButton>
        <RadioButton Name="rdbtnBackSalmon"
                    Click="BackColorChanged">LightSalmon</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Foreground Color</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalForeColor"
                    IsChecked="True"
                    Click="ForeColorChanged">Original</RadioButton>
        <RadioButton Name="rdbtnForeRed"
                    Click="ForeColorChanged">Red</RadioButton>
        <RadioButton Name="rdbtnForeYellow"
                    Click="ForeColorChanged">Yellow</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Family</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalFamily"
                     IsChecked="True"
                    Click="FontChanged">Original</RadioButton>
        <RadioButton Name="rdbtnTimes"
                    Click="FontChanged">Times New Roman</RadioButton>
        <RadioButton Name="rdbtnWingdings"
                    Click="FontChanged">Wingdings</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Size</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalSize"
                    IsChecked="True"
                    Click="FontSizeChanged">Original</RadioButton>
        <RadioButton Name="rdbtnTen"
                    Click="FontSizeChanged">10</RadioButton>
        <RadioButton Name="rdbtnTwelve"
                    Click="FontSizeChanged">12</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Style</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnNormalStyle"
                     IsChecked="True"
                     Click="StyleChanged">Original</RadioButton>
        <RadioButton Name="rdbtnItalic"
                     Click="StyleChanged">Italic</RadioButton>
      </StackPanel>

      <TextBlock Style="{StaticResource titleText}">Font Weight</TextBlock>
      <StackPanel Margin="10,10,10,10">
        <RadioButton Name="rdbtnOriginalWeight"
                     IsChecked="True"
                   Click="WeightChanged">
          Original
        </RadioButton>
        <RadioButton Name="rdbtnBold"
                   Click="WeightChanged">Bold</RadioButton>
      </StackPanel>
    </StackPanel>

    <WindowsFormsHost Name="wfh"
                     DockPanel.Dock="Top"
                     Height="300">
      <mcl:MyControl1 Name="mc"/>
    </WindowsFormsHost>

    <StackPanel Orientation="Vertical"
                Height="Auto"
                Background="LightBlue">
      <TextBlock Margin="10,10,10,10"
            FontWeight="Bold"
            FontSize="12">Data From Control</TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        Name: <Span Name="txtName" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        Street Address: <Span Name="txtAddress" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        City: <Span Name="txtCity" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        State: <Span Name="txtState" Style="{StaticResource inlineText}"/>
      </TextBlock>
      <TextBlock Style="{StaticResource titleText}">
        Zip: <Span Name="txtZip" Style="{StaticResource inlineText}"/>
      </TextBlock>
    </StackPanel>
  </DockPanel>
</Window>


El primer elemento StackPanel contiene varios conjuntos de controles RadioButton que permiten modificar diversas propiedades predeterminadas del control hospedado. A continuación, hay un elemento WindowsFormsHost en el que se hospeda MyControl1. El último elemento StackPanel contiene varios elementos TextBlock que muestran los datos devueltos por el control hospedado. El orden de los elementos y los valores de atributo de Dock y Height incrustan el control hospedado en la ventana sin dejar separaciones ni provocar distorsión.

Hospedar el control

La versión editada siguiente del XAML anterior se centra en los elementos que se necesitan para hospedar MyControl1.


<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="WpfHost.MainWindow"
      xmlns:mcl="clr-namespace:MyControls;assembly=MyControls"
      Loaded="Init">


...


<WindowsFormsHost Name="wfh"
                 DockPanel.Dock="Top"
                 Height="300">
  <mcl:MyControl1 Name="mc"/>
</WindowsFormsHost>


Los atributos de asignación del espacio de nombres xmlns crean una referencia al espacio de nombres MyControls que contiene el control hospedado. Esta asignación permite representar MyControl1 en XAML como <mcl:MyControl1>.

Dos elementos del XAML controlan el hospedaje:

  • WindowsFormsHost representa el elemento WindowsFormsHost que permite hospedar un control de Windows Forms en una aplicación WPF.

  • mcl:MyControl1, que representa a MyControl1, se agrega a la colección de elementos secundarios del elemento WindowsFormsHost. Por consiguiente, este control de Windows Forms se presenta como parte de la ventana de WPF y es posible comunicarse con el control desde la aplicación.

Implementar el archivo de código subyacente

El archivo de código subyacente, MainWindow.xaml.vb o MainWindow.xaml.cs, contiene el código de procedimiento que implementa la funcionalidad de la UI descrito en la sección anterior. Las principales tareas son:

  • Asociar un controlador al evento OnButtonClick de MyControl1.

  • Modificar diversas propiedades de MyControl1, basándose en cómo se establezca la colección de botones de opción.

  • Mostrar los datos recolectados por el control.

Inicializar la aplicación

El código de inicialización está contenido en un controlador para el evento Loaded de la ventana y adjunta un controlador al evento OnButtonClick del control.

En MainWindow.xaml.vb o MainWindow.xaml.cs, agregue el código siguiente a la clase MainWindow.


private Application app;
private Window myWindow;
FontWeight initFontWeight;
Double initFontSize;
FontStyle initFontStyle;
SolidColorBrush initBackBrush;
SolidColorBrush initForeBrush;
FontFamily initFontFamily;
bool UIIsReady = false;

private void Init(object sender, EventArgs e)
{
    app = System.Windows.Application.Current;
    myWindow = (Window)app.MainWindow;
    myWindow.SizeToContent = SizeToContent.WidthAndHeight;
    wfh.TabIndex = 10;
    initFontSize = wfh.FontSize;
    initFontWeight = wfh.FontWeight;
    initFontFamily = wfh.FontFamily;
    initFontStyle = wfh.FontStyle;
    initBackBrush = (SolidColorBrush)wfh.Background;
    initForeBrush = (SolidColorBrush)wfh.Foreground;
    (wfh.Child as MyControl1).OnButtonClick += new MyControl1.MyControlEventHandler(Pane1_OnButtonClick);
    UIIsReady = true;
}


Dado que en el XAML descrito anteriormente se ha agregado MyControl1 a la colección de elementos secundarios del elemento WindowsFormsHost, puede convertir la propiedad Child del elemento WindowsFormsHost para obtener la referencia a MyControl1. A continuación, puede utilizar esa referencia para asociar un controlador de eventos a OnButtonClick.

Además de proporcionar una referencia al propio control, WindowsFormsHost expone varias propiedades del control, que puede manipular desde la aplicación. En el código de inicialización se asignan esos valores a las variables globales privadas para su uso posterior en la aplicación.

Para poder tener un fácil acceso a los tipos de la DLL MyControls, agregue la siguiente instrucción Imports o using a la parte superior del archivo.

using MyControls;

Controlar el evento OnButtonClick

MyControl1 provoca el evento OnButtonClick cuando el usuario hace clic en cualquiera de los botones del control.

Agregue el código siguiente a la clase MainWindow.


//Handle button clicks on the Windows Form control
private void Pane1_OnButtonClick(object sender, MyControlEventArgs args)
{
    txtName.Inlines.Clear();
    txtAddress.Inlines.Clear();
    txtCity.Inlines.Clear();
    txtState.Inlines.Clear();
    txtZip.Inlines.Clear();

    if (args.IsOK)
    {
        txtName.Inlines.Add( " " + args.MyName );
        txtAddress.Inlines.Add( " " + args.MyStreetAddress );
        txtCity.Inlines.Add( " " + args.MyCity );
        txtState.Inlines.Add( " " + args.MyState );
        txtZip.Inlines.Add( " " + args.MyZip );
    }
}


Los datos de los cuadros de texto se empaquetan en el objeto MyControlEventArgs. Si el usuario hace clic en el botón Aceptar botón, el controlador de eventos extrae los datos y los muestra en el panel situado debajo de MyControl1.

Modificar las propiedades del control

El elemento WindowsFormsHost expone algunas de las propiedades predeterminadas de control hospedado. Por consiguiente, puede cambiar el aspecto del control para adaptarlo mejor al estilo de la aplicación. Los conjuntos de botones de opción del panel izquierdo permiten al usuario modificar varias propiedades de color y fuente. Cada conjunto de botones tiene un controlador para el evento Click, que detecta qué botón selecciona el usuario y cambia la propiedad correspondiente del control.

Agregue el código siguiente a la clase MainWindow.


private void BackColorChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnBackGreen)
        wfh.Background = new SolidColorBrush(Colors.LightGreen);
    else if (sender == rdbtnBackSalmon)
        wfh.Background = new SolidColorBrush(Colors.LightSalmon);
    else if (UIIsReady == true)
        wfh.Background = initBackBrush;
}

private void ForeColorChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnForeRed)
        wfh.Foreground = new SolidColorBrush(Colors.Red);
    else if (sender == rdbtnForeYellow)
        wfh.Foreground = new SolidColorBrush(Colors.Yellow);
    else if (UIIsReady == true)
        wfh.Foreground = initForeBrush;
}

private void FontChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnTimes)
        wfh.FontFamily = new FontFamily("Times New Roman");
    else if (sender == rdbtnWingdings)
        wfh.FontFamily = new FontFamily("Wingdings");
    else if (UIIsReady == true)
        wfh.FontFamily = initFontFamily;
}
private void FontSizeChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnTen)
        wfh.FontSize = 10;
    else if (sender == rdbtnTwelve)
        wfh.FontSize = 12;
    else if (UIIsReady == true)
        wfh.FontSize = initFontSize;
}
private void StyleChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnItalic)
        wfh.FontStyle = FontStyles.Italic;
    else if (UIIsReady == true)
        wfh.FontStyle = initFontStyle;
}
private void WeightChanged(object sender, RoutedEventArgs e)
{
    if (sender == rdbtnBold)
        wfh.FontWeight = FontWeights.Bold;
    else if (UIIsReady == true)
        wfh.FontWeight = initFontWeight;
}


Genere y ejecute la aplicación. Agregue texto en el control compuesto de Windows Forms y, a continuación, haga clic en Aceptar. El texto aparece en las etiquetas. Haga clic en los distintos botones de radio para ver el efecto en el control.

date

Historial

Motivo

Agosto de 2010

Se ha actualizado para Visual Studio 2010.

Comentarios de los clientes.

Adiciones de comunidad

AGREGAR
Mostrar:
© 2014 Microsoft