Instruções passo a passo: organizando controles dos Windows Forms no WPF

Este passo a passo mostra como usar os recursos de layout do WPF para organizar controles do Windows Forms em um aplicativo híbrido.

As tarefas ilustradas neste passo a passo incluem:

  • Criação do projeto.
  • Usando as configurações padrão de layout.
  • Dimensionando o conteúdo.
  • Usando o posicionamento absoluto.
  • Especificando o tamanho explicitamente.
  • Definindo propriedades de layout.
  • Noções básicas sobre limitações da ordem z.
  • Encaixe.
  • Definindo a visibilidade.
  • Hospedando um controle que não se alonga.
  • Dimensionamento.
  • Girando.
  • Margens e preenchimento de configuração.
  • Usando contêineres de layout dinâmico.

Para uma listagem de código completa de todas tarefas ilustradas neste passo a passo, consulte Organizando controles do Windows Forms no WPF de exemplo.

Quando terminar, você terá uma compreensão dos recursos de layout do Windows Forms em aplicativos baseados em WPF.

Pré-requisitos

É necessário o Visual Studio para concluir este passo a passo.

Criando o Projeto

Para criar e configurar o projeto, execute estas etapas:

  1. Crie um projeto de aplicativo WPF chamado WpfLayoutHostingWf.

  2. No Gerenciador de Soluções, adicione referências aos seguintes assemblies:

    • WindowsFormsIntegration
    • System.Windows.Forms
    • System.Drawing
  3. Clique duas vezes em MainWindow.xaml para abri-lo no modo de exibição XAML.

  4. Window No elemento , adicione o seguinte mapeamento de namespace do Windows Forms.

    xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
    
  5. Grid No elemento , defina a ShowGridLines propriedade como true e defina cinco linhas e três colunas.

    <Grid ShowGridLines="true">
      <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
      </Grid.RowDefinitions>
    
      <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
      </Grid.ColumnDefinitions>
    

Usando as configurações padrão de layout

Por padrão, o elemento manipula o layout para o WindowsFormsHost controle Windows Forms hospedado.

Para usar as configurações de layout padrão, execute estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Default layout. -->
    <Canvas Grid.Row="0" Grid.Column="0">
      <WindowsFormsHost Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. Pressione F5 para compilar e executar o aplicativo. O controle Windows Forms System.Windows.Forms.Button aparece no Canvas. O controle hospedado é dimensionado com base em seu conteúdo e o elemento é dimensionado para acomodar o WindowsFormsHost controle hospedado.

Dimensionando para o conteúdo

O WindowsFormsHost elemento garante que o controle hospedado seja dimensionado para exibir seu conteúdo corretamente.

Para dimensionar o conteúdo, siga estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Sizing to content. -->
    <Canvas Grid.Row="1" Grid.Column="0">
      <WindowsFormsHost Background="Orange">
        <wf:Button Text="Windows Forms control with more content" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
    <Canvas Grid.Row="2" Grid.Column="0">
      <WindowsFormsHost FontSize="24" Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. Pressione F5 para compilar e executar o aplicativo. Os dois novos controles de botão são dimensionados para exibir a cadeia de caracteres de texto mais longa e o tamanho da fonte maior corretamente, e os elementos são redimensionados para acomodar os WindowsFormsHost controles hospedados.

Usando o posicionamento absoluto

Você pode usar o posicionamento absoluto para colocar o WindowsFormsHost elemento em qualquer lugar na interface do usuário (UI).

Para usar o posicionamento absoluto, execute estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Absolute positioning. -->
    <Canvas Grid.Row="3" Grid.Column="0">
      <WindowsFormsHost Canvas.Top="20" Canvas.Left="20" Background="Yellow">
        <wf:Button Text="Windows Forms control with absolute positioning" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. Pressione F5 para compilar e executar o aplicativo. O WindowsFormsHost elemento é colocado a 20 pixels do lado superior da célula da grade e a 20 pixels da esquerda.

Especificando o tamanho explicitamente

Você pode especificar o WindowsFormsHost tamanho do elemento usando as Width propriedades e Height .

Para especificar o tamanho explicitamente, execute estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Explicit sizing. -->
    <Canvas Grid.Row="4" Grid.Column="0">
      <WindowsFormsHost Width="50" Height="70" Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. Pressione F5 para compilar e executar o aplicativo. O WindowsFormsHost elemento é definido para um tamanho de 50 pixels de largura por 70 pixels de altura, que é menor do que as configurações de layout padrão. O conteúdo do controle Windows Forms é reorganizado de acordo.

Definindo propriedades de layout

Sempre defina propriedades relacionadas ao layout no controle hospedado usando as WindowsFormsHost propriedades do elemento. Definindo propriedades de layout diretamente no controle hospedado produzirá resultados indesejados.

A definição de propriedades relacionadas ao layout no controle hospedado em XAML não tem efeito.

Para ver os efeitos da definição de propriedades no controle hospedado, execute estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Setting hosted control properties directly. -->
    <Canvas Grid.Row="0" Grid.Column="1">
      <WindowsFormsHost Width="160" Height="50" Background="Yellow">
        <wf:Button Name="button1" Click="button1_Click" Text="Click me" FlatStyle="Flat" BackColor="Green"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. No Gerenciador de Soluções, clique duas vezes em MainWindow.xaml.vb ou MainWindow.xaml.cs para abri-lo no Editor de Códigos.

  3. Copie o seguinte código para a definição de MainWindow classe:

    private void button1_Click(object sender, EventArgs e )
    {
        System.Windows.Forms.Button b = sender as System.Windows.Forms.Button;
    
        b.Top = 20;
        b.Left = 20;
    }
    
    Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs)
        Dim b As System.Windows.Forms.Button = sender
    
        b.Top = 20
        b.Left = 20
    
    End Sub
    
  4. Pressione F5 para compilar e executar o aplicativo.

  5. Clique no botão Clique em mim . O button1_Click manipulador de eventos define as Top propriedades e Left no controle hospedado. Isso faz com que o controle hospedado seja reposicionado dentro do WindowsFormsHost elemento . O host mantém a mesma área da tela, mas o controle hospedado é cortado. Em vez disso, o controle hospedado deve sempre preencher o WindowsFormsHost elemento .

Noções básicas sobre limitações da ordem z

Os elementos visíveis WindowsFormsHost são sempre desenhados sobre outros elementos do WPF e não são afetados pela ordem z. Para ver esse comportamento de ordem z, faça o seguinte:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Z-order demonstration. -->
    <Canvas Grid.Row="1" Grid.Column="1">
      <WindowsFormsHost Canvas.Top="20" Canvas.Left="20" Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
      <Label Content="A WPF label" FontSize="24"/>
    </Canvas>
    
  2. Pressione F5 para compilar e executar o aplicativo. O WindowsFormsHost elemento é pintado sobre o elemento label.

Encaixe

WindowsFormsHost suporta encaixe WPF. Defina a propriedade anexada Dock para encaixar o controle hospedado em um DockPanel elemento .

Para encaixar um controle hospedado, execute estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Docking a WindowsFormsHost element. -->
    <DockPanel LastChildFill="false"  Grid.Row="2" Grid.Column="1">
      <WindowsFormsHost DockPanel.Dock="Right"  Canvas.Top="20" Canvas.Left="20" Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </DockPanel>
    
  2. Pressione F5 para compilar e executar o aplicativo. O WindowsFormsHost elemento é encaixado no lado direito do DockPanel elemento.

Definindo a visibilidade

Você pode tornar seu controle do Windows Forms invisível ou colapsá-lo definindo a VisibilityWindowsFormsHost propriedade no elemento . Quando um controle estiver invisível, ele não será exibido, mas ocupa espaço de layout. Quando um controle estiver recolhido, ele não será exibido, mas também não ocupa espaço de layout.

Para definir a visibilidade de um controle hospedado, execute estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Setting Visibility to hidden and collapsed. -->
    <StackPanel Grid.Row="3" Grid.Column="1">
      <Button Name="button2" Click="button2_Click" Content="Click to make invisible" Background="OrangeRed"/>
      <WindowsFormsHost Name="host1"  Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
      <Button Name="button3" Click="button3_Click" Content="Click to collapse" Background="OrangeRed"/>
    </StackPanel>
    
  2. Em MainWindow.xaml.vb ou MainWindow.xaml.cs, copie o seguinte código para a definição de classe:

    private void button2_Click(object sender, EventArgs e)
    {
        this.host1.Visibility = Visibility.Hidden;
    }
    
    private void button3_Click(object sender, EventArgs e)
    {
        this.host1.Visibility = Visibility.Collapsed;
    }
    
    Private Sub button2_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Me.host1.Visibility = Windows.Visibility.Hidden
    End Sub
    
    
    Private Sub button3_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Me.host1.Visibility = Windows.Visibility.Collapsed
    End Sub
    
  3. Pressione F5 para compilar e executar o aplicativo.

  4. Clique no botão Clique para tornar invisível para tornar o WindowsFormsHost elemento invisível.

  5. Clique no botão Clique para recolher para ocultar totalmente o WindowsFormsHost elemento do layout. Quando o controle Windows Forms é recolhido, os elementos circundantes são reorganizados para ocupar seu espaço.

Hospedando um controle que não se alonga

Alguns controles do Windows Forms têm um tamanho fixo e não se esticam para preencher o espaço disponível no layout. Por exemplo, o MonthCalendar controle exibe um mês em um espaço fixo.

Para hospedar um controle que não se estica, execute estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Hosting a control that does not stretch. -->
    <!-- The MonthCalendar has a discrete size. -->
    <StackPanel Grid.Row="4" Grid.Column="1">
      <Label Content="A WPF element" Background="OrangeRed"/>
      <WindowsFormsHost Background="Yellow">
        <wf:MonthCalendar/>
      </WindowsFormsHost>
      <Label Content="Another WPF element" Background="OrangeRed"/>
    </StackPanel>
    
  2. Pressione F5 para compilar e executar o aplicativo. O WindowsFormsHost elemento é centralizado na linha de grade, mas não é esticado para preencher o espaço disponível. Se a janela for grande o suficiente, você poderá ver dois ou mais meses exibidos pelo controle hospedado MonthCalendar , mas eles estarão centralizados na linha. O mecanismo de layout do WPF centraliza elementos que não podem ser dimensionados para preencher o espaço disponível.

Scaling

Ao contrário dos elementos WPF, a maioria dos controles do Windows Forms não são continuamente escalonáveis. Para fornecer dimensionamento personalizado, substitua o WindowsFormsHost.ScaleChild método.

Para dimensionar um controle hospedado usando o comportamento padrão, execute estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Scaling transformation. -->
    <StackPanel Grid.Row="0" Grid.Column="2">
      
      <StackPanel.RenderTransform>
        <ScaleTransform CenterX="0" CenterY="0" ScaleX="0.5" ScaleY="0.5" />
      </StackPanel.RenderTransform>
    
      <Label Content="A WPF UIElement" Background="OrangeRed"/>
      
      <WindowsFormsHost Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
      
      <Label Content="Another WPF UIElement" Background="OrangeRed"/>
      
    </StackPanel>
    
  2. Pressione F5 para compilar e executar o aplicativo. O controle hospedado e seus elementos adjacentes são dimensionados por um fator de 0,5. No entanto, a fonte do controle hospedada não é redimensionada.

Girando

Ao contrário dos elementos WPF, os controles do Windows Forms não oferecem suporte à rotação. O WindowsFormsHost elemento não gira com outros elementos WPF quando uma transformação de rotação é aplicada. Qualquer valor de rotação diferente de 180 graus eleva o LayoutError evento.

Para ver o efeito da rotação em um aplicativo híbrido, execute estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Rotation transformation. -->
    <StackPanel Grid.Row="1" Grid.Column="2">
    
      <StackPanel.RenderTransform>
        <RotateTransform CenterX="200" CenterY="50" Angle="180" />
      </StackPanel.RenderTransform>
    
      <Label Content="A WPF element" Background="OrangeRed"/>
    
      <WindowsFormsHost Background="Yellow">
        <wf:Button Text="Windows Forms control" FlatStyle="Flat"/>
      </WindowsFormsHost>
    
      <Label Content="Another WPF element" Background="OrangeRed"/>
    
    </StackPanel>
    
  2. Pressione F5 para compilar e executar o aplicativo. O controle hospedado não é girado, mas seus elementos adjacentes são girados por um ângulo de 180 graus. Você terá que redimensionar a janela para ver os elementos.

Margens e preenchimento de configuração

O preenchimento e as margens no layout do WPF são semelhantes ao preenchimento e às margens no Windows Forms. Basta definir as Padding propriedades e Margin no WindowsFormsHost elemento .

Para definir preenchimento e margens para um controle hospedado, execute estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Padding. -->
    <Canvas Grid.Row="2" Grid.Column="2">
      <WindowsFormsHost Padding="0, 20, 0, 0" Background="Yellow">
        <wf:Button Text="Windows Forms control with padding" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
    <!-- Margin. -->
    <Canvas Grid.Row="3" Grid.Column="2">
      <WindowsFormsHost Margin="20, 20, 0, 0" Background="Yellow">
        <wf:Button Text="Windows Forms control with margin" FlatStyle="Flat"/>
      </WindowsFormsHost>
    </Canvas>
    
  2. Pressione F5 para compilar e executar o aplicativo. As configurações de preenchimento e margem são aplicadas aos controles hospedados do Windows Forms da mesma forma que seriam aplicadas no Windows Forms.

Usando contêineres de layout dinâmico

O Windows Forms fornece dois contêineres FlowLayoutPanel de layout dinâmico e TableLayoutPanelo . Você também pode usar esses contêineres em layouts WPF.

Para usar um contêiner de layout dinâmico, execute estas etapas:

  1. Copie o seguinte XAML para o Grid elemento :

    <!-- Flow layout. -->
    <DockPanel Grid.Row="4" Grid.Column="2">
      <WindowsFormsHost Name="flowLayoutHost" Background="Yellow">
        <wf:FlowLayoutPanel/>
      </WindowsFormsHost>
    </DockPanel>
    
  2. Em MainWindow.xaml.vb ou MainWindow.xaml.cs, copie o seguinte código para a definição de classe:

    private void InitializeFlowLayoutPanel()
    {
        System.Windows.Forms.FlowLayoutPanel flp =
            this.flowLayoutHost.Child as System.Windows.Forms.FlowLayoutPanel;
    
        flp.WrapContents = true;
    
        const int numButtons = 6;
    
        for (int i = 0; i < numButtons; i++)
        {
            System.Windows.Forms.Button b = new System.Windows.Forms.Button();
            b.Text = "Button";
            b.BackColor = System.Drawing.Color.AliceBlue;
            b.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
    
            flp.Controls.Add(b);
        }
    }
    
    Private Sub InitializeFlowLayoutPanel()
        Dim flp As System.Windows.Forms.FlowLayoutPanel = Me.flowLayoutHost.Child
    
        flp.WrapContents = True
    
        Const numButtons As Integer = 6
    
        Dim i As Integer
        For i = 0 To numButtons
            Dim b As New System.Windows.Forms.Button()
            b.Text = "Button"
            b.BackColor = System.Drawing.Color.AliceBlue
            b.FlatStyle = System.Windows.Forms.FlatStyle.Flat
    
            flp.Controls.Add(b)
        Next i
    
    End Sub
    
  3. Adicione uma chamada ao InitializeFlowLayoutPanel método no construtor:

    public MainWindow()
    {
        InitializeComponent();
    
        this.InitializeFlowLayoutPanel();
    }
    
    Public Sub New()
        InitializeComponent()
    
        Me.InitializeFlowLayoutPanel()
    
    End Sub
    
  4. Pressione F5 para compilar e executar o aplicativo. O WindowsFormsHost elemento preenche o DockPanel, e FlowLayoutPanel organiza seus controles filho no padrão FlowDirection.

Confira também