Прочитать на английском

Поделиться через


Пошаговое руководство. Размещение составного элемента управления Windows Forms в приложении WPF

Windows Presentation Foundation (WPF) предоставляет широкие возможности для создания приложений. Однако если у вас есть существенные инвестиции в код Windows Forms, это может быть более эффективным для повторного использования по крайней мере некоторых из этого кода в приложении WPF, а не для перезаписи его с нуля. Наиболее распространенным сценарием является наличие элементов управления Windows Forms. В некоторых случаях, возможно, у вас даже нет доступа к исходному коду для этих элементов управления. WPF предоставляет простую процедуру размещения таких элементов управления в приложении WPF. Например, можно использовать WPF для значительной части операций программирования при размещении специализированных элементов управления DataGridView.

В этом пошаговом руководстве создается приложение, в котором содержится составной элемент управления Windows Forms для поддержки ввода данных в WPF. Составной элемент управления упакован в библиотеку DLL. Эта общая процедура может быть расширена для более сложных приложений и элементов управления. Это пошаговое руководство почти идентично повторяет свойства и функциональные возможности, описанные в разделе Пошаговое руководство. Размещение составного элемента управления WPF в приложении Windows Forms. Основным отличием является то, что сценарий размещения выполняется в обратном порядке.

Пошаговое руководство состоит из двух разделов. В первом разделе кратко описывается реализация составного элемента управления Windows Forms. Во втором разделе подробно рассматриваются размещение составного элемента управления в приложении WPF, получение событий от него и доступ к некоторым свойствам элемента управления.

В данном пошаговом руководстве представлены следующие задачи.

  • Реализация составного элемента управления Windows Forms.

  • Реализация ведущего приложения WPF.

Полный пример кода для задач, демонстрируемых в этом руководстве, см. в разделе Пример размещения составного элемента управления Windows Forms в приложении WPF.

Необходимые компоненты

Для выполнения шагов, описанных в этом руководстве, вам понадобится Visual Studio.

Реализация составного элемента управления Windows Forms

Составной элемент управления Windows Forms, используемый в этом примере, представляет собой простую форму ввода данных. Эта форма принимает имя и адрес пользователя и затем использует пользовательское событие для возвращения сведений в основное приложение. На приведенном ниже рисунке показан отображаемый элемент управления.

На следующем рисунке показан составной элемент управления Windows Forms.

Screenshot that shows a simple Windows Forms control.

Создание проекта

Для запуска проекта выполните указанные ниже действия.

  1. Запустите Visual Studio и откройте диалоговое окно Новый проект.

  2. В категории Windows выберите шаблон Библиотека элементов управления Windows Forms.

  3. Присвойте проекту имя MyControls.

  4. В качестве расположения задайте папку верхнего уровня с понятным именем, например WpfHostingWindowsFormsControl. Позже ведущее приложение будет помещено в эту папку.

  5. Нажмите кнопку ОК, чтобы создать проект. По умолчанию проект содержит один элемент управления с именем UserControl1.

  6. В обозревателе решений переименуйте элемент управления UserControl1 в MyControl1.

Проект должен иметь ссылки на перечисленные ниже системные библиотеки DLL. Если какие-либо из этих библиотек DLL не включены по умолчанию, добавьте их в проект.

  • Система

  • System.Data

  • System.Drawing;

  • System.Windows.Forms.

  • System.Xml

Добавление элементов управления на форму

Чтобы добавить элементы управления в форму, выполните следующие действия.

  • Откройте MyControl1 в конструкторе.

Добавьте пять элементов управления Label и соответствующих элементов управления TextBox в масштабе и порядке, указанных на предыдущем рисунке, в форму. В этом примере элементы управления TextBox именуются следующим образом.

  • txtName

  • txtAddress

  • txtCity

  • txtState

  • txtZip

Добавьте два элемента управления Button с метками ОК и Отмена. В примере используются названия кнопок btnOK и btnCancel соответственно.

Реализация соответствующего кода

Откройте форму в представлении кода. Элемент управления возвращает собранные данные в основное приложение путем вызова пользовательского события OnButtonClick. Данные содержатся в объекте аргумента события. В следующем коде показано объявление события и делегата.

Добавьте в класс MyControl1 приведенный далее код.

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

Класс MyControlEventArgs содержит информацию, которая должна быть возвращена основному приложению.

Добавьте в форму следующий класс.

C#
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; }
    }
}

При нажатии пользователем кнопки ОК или Отмена обработчики событий Click создают объект MyControlEventArgs, который содержит данные и вызывает событие OnButtonClick. Единственное различие между двумя обработчиками заключается в свойстве IsOK аргумента события. Это свойство позволяет основному приложению определить, какая кнопка была нажата. Ему присвоено значение true для кнопки ОК и значение false для кнопки Отмена. В следующем примере кода показаны два обработчика кнопок.

Добавьте в класс MyControl1 приведенный далее код.

C#
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);
}

Присвоение сборке строгого имени и построение сборки

Чтобы приложение WPF ссылалось на эту сборку, ей необходимо присвоить строгое имя. Для создания строгого имени создайте файл ключа с Sn.exe и добавьте его в свой проект.

  1. Откройте командную строку Visual Studio. Для этого откройте меню Пуск, выберите Все программы/Microsoft Visual Studio 2010/Инструменты Visual Tools/Командная строка Visual Studio. Откроется окно консоли с настраиваемыми переменными среды.

  2. В командной строке используйте команду cd, чтобы перейти к папке проекта.

  3. Создайте файл ключа с именем MyControls.snk, выполнив следующую команду.

    Консоль
    Sn.exe -k MyControls.snk
    
  4. Чтобы включить файл ключа в проект, щелкните правой кнопкой мыши имя проекта в обозревателе решений и выберите Свойства. В конструкторе проектов щелкните Подписи, установите флажок Подписать сборку, а затем перейдите к файлу ключа.

  5. Постройте решение. Сборка создаст библиотеку DLL с именем MyControls.dll.

Реализация ведущего приложения WPF

Ведущее приложение WPF использует элемент управления WindowsFormsHost для размещения MyControl1. Приложение обрабатывает событие OnButtonClick для получения данных из элемента управления. Оно также содержит коллекцию переключателей, позволяющих менять некоторые свойства элемента управления из приложения WPF. Ниже показано готовое приложение.

На следующем рисунке показано приложение полностью, включая элемент управления, внедренный в приложение WPF.

Screenshot that shows a control embedded in a WPF page.

Создание проекта

Для запуска проекта выполните указанные ниже действия.

  1. Откройте Visual Studio и нажмите кнопку Новый проект.

  2. В категории Window выберите шаблон Приложение WPF.

  3. Присвойте проекту имя WpfHost.

  4. В качестве расположения укажите ту же папку верхнего уровня, в которой содержится проект MyControls.

  5. Нажмите кнопку ОК, чтобы создать проект.

Также необходимо добавить ссылки на библиотеку DLL, содержащую элемент управления MyControl1 и другие сборки.

  1. Щелкните правой кнопкой мыши имя проекта в обозревателе решений и выберите команду Добавить ссылку.

  2. Перейдите на вкладку Обзор и выберите папку, которая содержит файл MyControls.dll. В данном пошаговом руководстве это папка MyControls\bin\Debug.

  3. Выберите файл MyControls.dll и нажмите кнопку ОК.

  4. Добавьте ссылку на сборку WindowsFormsIntegration с именем WindowsFormsIntegration.dll.

Реализация базового макета

Пользовательский интерфейс ведущего приложения реализуется в файле MainWindow.xaml. Этот файл содержит расширяемую разметку языка разметки приложения (XAML), которая определяет макет и размещает элемент управления Windows Forms. Приложение состоит из трех областей:

  • Панель Свойства элемента управления, содержащая коллекцию переключателей, которые можно использовать для изменения различных свойств размещенного элемента управления.

  • Панель Данные из элемента управления, содержащая несколько элементов TextBlock, которые отображают данные, возвращенные из размещенного элемента управления.

  • Размещенный элемент.

Базовый макет показан в следующем XAML-коде. Разметка, необходимая для размещения MyControl1, пропущена в этом примере, однако этот вопрос рассматривается позже.

Замените XAML-код в файле MainWindow.xaml следующим. Если вы используете Visual Basic, измените класс на x:Class="MainWindow".

XAML
<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>

Первый элемент StackPanel содержит несколько наборов элементов управления RadioButton, которые позволяют вам модифицировать различные свойства по умолчанию размещенного элемента управления. За ним следует элемент WindowsFormsHost, в котором размещается MyControl1. И, наконец, элемент StackPanel содержит в себе несколько элементов TextBlock, которые служат для отображения данных, возвращаемых размещенным элементов управления. Порядок элементов и настройки атрибутов Dock и Height внедряют размещенный элемент в окно без промежутков и искажений.

Размещение элемента управления

В следующей отредактированной версии предыдущего XAML-кода особое внимание уделяется элементам, необходимым для размещения MyControl1.

XAML
<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">
XAML
<WindowsFormsHost Name="wfh"
                 DockPanel.Dock="Top"
                 Height="300">
  <mcl:MyControl1 Name="mc"/>
</WindowsFormsHost>

Атрибут сопоставления пространства имен xmlns создает ссылку на пространство имен MyControls, которое содержит размещенный элемент управления. Это сопоставление позволяет представить MyControl1 в XAML в качестве <mcl:MyControl1>.

Два элемента в коде XAML обрабатывают размещение:

  • WindowsFormsHost представляет элемент WindowsFormsHost, позволяющий разместить элемент управления Windows Forms в приложении WPF.

  • mcl:MyControl1, представляющий MyControl1, добавляется в коллекцию дочерних элементов WindowsFormsHost. В результате этот элемент управления Windows Forms отрисовывается в составе окна WPF и из приложения можно взаимодействовать с этим элементом управления.

Реализация файла кода программной части

Файл кода программной части MainWindow.xaml.vb или MainWindow.xaml.cs содержит процедурный код, реализующий функциональные возможности пользовательского интерфейса, которые обсуждались в предыдущем разделе. Основные задачи

  • Присоединение обработчика событий к событию OnButtonClick объекта MyControl1.

  • Изменение различных свойств MyControl1 в зависимости от способа настройки коллекции переключателей.

  • Отображение данных, собранных с помощью элемента управления.

Инициализация приложения

Код инициализации содержится в обработчике событий для события Loaded окна и прикрепляет обработчик событий к событию OnButtonClick элемента управления.

В файле MainWindow.xaml.vb или MainWindow.xaml.cs добавьте в класс MainWindow следующий код.

C#
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;
}

Так как код XAML, обсужденный ранее, добавляет MyControl1 в коллекцию дочерних элементов WindowsFormsHost, можно привести член Child элемента WindowsFormsHost, чтобы получить ссылку на MyControl1. Затем можно использовать эту ссылку для присоединения обработчика событий к OnButtonClick.

Помимо предоставления ссылки на элемент управления, WindowsFormsHost предоставляет ряд свойств элемента управления, которыми можно управлять из приложения. Код инициализации назначает эти значения закрытым глобальным переменным для последующего использования в приложении.

Это позволяет легко осуществлять доступ к типам в библиотеке DLL MyControls, добавлять инструкцию Imports или using в начало файла.

C#
using MyControls;

Обработка события OnButtonClick

MyControl1 вызывает событие OnButtonClick при нажатии любой из кнопок элемента управления.

Добавьте в класс MainWindow приведенный далее код.

C#
//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 );
    }
}

Данные в текстовых полях упакованы в объект MyControlEventArgs. Если пользователь нажимает кнопку ОК, обработчик событий извлекает данные и отображает их на панели ниже MyControl1.

Изменение свойств элемента управления

Элемент WindowsFormsHost предоставляет несколько свойств по умолчанию для размещенных элементов. В результате можно изменить внешний вид элемента управления, чтобы он более полно соответствовал стилю приложения. Наборы переключателей на левой панели позволяют пользователю изменять некоторые свойства цвета и шрифта. Каждый набор кнопок имеет обработчик для события Click, которое обнаруживает, какой переключатель нажал пользователь, и меняет соответствующее свойство элемента управления.

Добавьте в класс MainWindow приведенный далее код.

C#
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;
}

Выполните сборку приложения и запустите его. Добавьте какой-нибудь текст в составной элемент управления Windows Forms и нажмите кнопку ОК. Этот текст появится в метках. Щелкайте различные переключатели, чтобы увидеть соответствующий эффект в элементе управления.

См. также