연습: Windows Forms에서 WPF 복합 컨트롤 호스팅

WPF(Windows Presentation Foundation)는 애플리케이션을 만들기 위한 풍부한 환경을 제공합니다. 하지만 Windows Forms 코드에 상당한 투자를 한 경우 코드를 처음부터 다시 작성하는 대신 WPF를 사용하여 기존 Windows Forms 애플리케이션을 확장하는 것이 더 효과적일 수 있습니다. 일반적으로 WPF로 구현된 하나 이상의 컨트롤을 애플리케이션 내에 포함할 수 있습니다. WPF 컨트롤 사용자 지정에 대한 자세한 내용은 컨트롤 사용자 지정을 참조하세요.

이 연습에서는 Windows Forms 애플리케이션에서 데이터 입력을 수행하기 위해 WPF 복합 컨트롤을 호스트하는 애플리케이션을 안내합니다. 복합 컨트롤은 DLL로 패키지됩니다. 이 일반적인 절차는 더 복잡한 애플리케이션 및 컨트롤로 확장할 수 있습니다. 이 연습은 모양과 기능이 연습: WPF에서 Windows Forms 복합 컨트롤 호스팅과 거의 동일하게 디자인되었습니다. 주요 차이점은 호스팅 시나리오가 반대라는 점입니다.

이 연습은 두 개의 섹션으로 구분됩니다. 첫 번째 섹션에서는 WPF 복합 컨트롤의 구현에 대해 간략하게 설명합니다. 두 번째 섹션에서는 Windows Forms 애플리케이션에서 복합 컨트롤을 호스트하고, 컨트롤에서 이벤트를 수신하고, 컨트롤의 일부 속성에 액세스하는 방법을 자세히 설명합니다.

이 연습에서 설명하는 작업은 다음과 같습니다.

  • WPF 복합 컨트롤 구현

  • Windows Forms 호스트 애플리케이션 구현

이 연습에 설명된 작업의 전체 코드 목록은 Windows Forms에서 WPF 복합 컨트롤 호스팅 샘플을 참조하세요.

필수 구성 요소

이 연습을 완료하려면 Visual Studio가 필요합니다.

WPF 복합 컨트롤 구현

이 예제에서 사용되는 WPF 복합 컨트롤은 사용자의 이름과 주소를 사용하는 간단한 데이터 입력 폼입니다. 사용자가 작업이 완료되었음을 나타내는 두 개의 단추 중 하나를 클릭하면 컨트롤에서 사용자 지정 이벤트가 발생하여 해당 정보가 호스트에 반환됩니다. 다음 그림에서는 렌더링된 컨트롤을 보여 줍니다.

다음 이미지는 WPF 복합 컨트롤을 보여 줍니다.

간단한 WPF 컨트롤을 보여주는 스크린샷.

프로젝트 만들기

프로젝트를 시작하려면

  1. Visual Studio를 실행하고 새 프로젝트 대화 상자를 엽니다.

  2. Visual C# 및 Windows 범주에서 WPF 사용자 정의 컨트롤 라이브러리 템플릿을 선택합니다.

  3. 새 프로젝트의 이름을 MyControls로 지정합니다.

  4. 위치에 편리하게 명명된 최상위 수준 폴더(예: WindowsFormsHostingWpfControl)를 지정합니다. 나중에 이 폴더에 호스트 애플리케이션을 넣습니다.

  5. 확인을 클릭하여 프로젝트를 만듭니다. 기본 프로젝트에는 UserControl1이라는 단일 컨트롤이 포함됩니다.

  6. 솔루션 탐색기에서 UserControl1 이름을 MyControl1로 바꿉니다.

프로젝트에는 다음과 같은 시스템 DLL에 대한 참조가 있어야 합니다. 이러한 DLL이 기본적으로 포함되지 않은 경우 프로젝트에 추가합니다.

  • PresentationCore

  • PresentationFramework

  • 시스템

  • WindowsBase

사용자 인터페이스 만들기

복합 컨트롤의 UI(사용자 인터페이스)는 XAML(Extensible Application Markup Language)을 사용하여 구현됩니다. 복합 컨트롤 UI는 다섯 개의 TextBox 요소로 구성됩니다. 각 TextBox 요소에는 연결된 TextBlock 요소가 있어, 레이블 역할을 합니다. 하단에는 2가지 Button 요소인 확인취소가 있습니다. 사용자가 이 단추 중 하나를 클릭하면 컨트롤에서 사용자 지정 이벤트가 발생하여 호스트에 정보가 반환됩니다.

기본 레이아웃

다양한 UI 요소가 Grid 요소에 포함되어 있습니다. Grid를 사용하면 HTML의 Table 요소와 같은 방법으로 복합 컨트롤의 콘텐츠를 정렬할 수 있습니다. WPF에도 Table 요소가 있지만 Grid가 더 가볍고 단순한 레이아웃 작업에 더 적합합니다.

다음 XAML에서는 기본 레이아웃을 보여 줍니다. 이 XAML에서는 Grid 요소의 열 및 행 수를 지정하여 컨트롤의 전체 구조를 정의합니다.

MyControl1.xaml에서 기존 XAML을 다음 XAML로 바꿉니다.

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="MyControls.MyControl1"
      Background="#DCDCDC"
      Width="375"
      Height="250"
      Name="rootElement"
      Loaded="Init">

  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="Auto"/>
    <ColumnDefinition Width="Auto"/>
  </Grid.ColumnDefinitions>

  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
</Grid>

그리드에 TextBlock 및 TextBox 요소 추가

요소의 RowPropertyColumnProperty 속성을 적절한 행과 열 번호에 설정하여 UI 요소를 그리드에 배치합니다. 행 및 열 번호는 0부터 시작해야 합니다. ColumnSpanProperty 속성을 설정하여 요소가 여러 열을 포함하게 할 수 있습니다. Grid 요소에 관한 자세한 정보는 그리드 요소 만들기를 참조하세요.

다음 XAML은 복합 컨트롤의 TextBoxTextBlock 요소와 RowPropertyColumnProperty 속성을 보여 줍니다. 이러한 속성은 요소를 그리드에 적절하게 배치하도록 설정되어 있습니다.

MyControl1.xaml에서 Grid 요소 내에 다음 XAML을 추가합니다.

  <TextBlock Grid.Column="0"
        Grid.Row="0" 
        Grid.ColumnSpan="4"
        Margin="10,5,10,0"
        HorizontalAlignment="Center"
        Style="{StaticResource titleText}">Simple WPF Control</TextBlock>

  <TextBlock Grid.Column="0"
        Grid.Row="1"
        Style="{StaticResource inlineText}"
        Name="nameLabel">Name</TextBlock>
  <TextBox Grid.Column="1"
        Grid.Row="1"
        Grid.ColumnSpan="3"
        Name="txtName"/>

  <TextBlock Grid.Column="0"
        Grid.Row="2"
        Style="{StaticResource inlineText}"
        Name="addressLabel">Street Address</TextBlock>
  <TextBox Grid.Column="1"
        Grid.Row="2"
        Grid.ColumnSpan="3"
        Name="txtAddress"/>

  <TextBlock Grid.Column="0"
        Grid.Row="3"
        Style="{StaticResource inlineText}"
        Name="cityLabel">City</TextBlock>
  <TextBox Grid.Column="1"
        Grid.Row="3"
        Width="100"
        Name="txtCity"/>

  <TextBlock Grid.Column="2"
        Grid.Row="3"
        Style="{StaticResource inlineText}"
        Name="stateLabel">State</TextBlock>
  <TextBox Grid.Column="3"
        Grid.Row="3"
        Width="50"
        Name="txtState"/>

  <TextBlock Grid.Column="0"
        Grid.Row="4"
        Style="{StaticResource inlineText}"
        Name="zipLabel">Zip</TextBlock>
  <TextBox Grid.Column="1"
        Grid.Row="4"
        Width="100"
        Name="txtZip"/>

UI 요소 스타일 지정

데이터 입력 폼의 요소는 대부분 모양이 비슷합니다. 즉, 이러한 요소의 여러 속성 설정이 동일합니다. 위의 XAML에서는 각 요소의 특성을 별도로 설정하지 않고 Style 요소를 사용하여 요소의 클래스에 대한 표준 속성 설정을 정의합니다. 이 방법을 사용하면 컨트롤의 복잡도를 줄이고 하나의 스타일 특성을 통해 여러 요소의 모양을 변경할 수 있습니다.

Style 요소는 Grid 요소의 Resources 속성에 포함되어 있으므로 컨트롤의 모든 요소에서 사용할 수 있습니다. 스타일의 이름을 지정하는 경우 요소에 스타일을 적용하려면 Style 요소 집합을 해당 스타일 이름에 추가합니다. 이름이 지정되지 않은 스타일은 요소의 기본 스타일이 됩니다. WPF 스타일에 대한 자세한 내용은 스타일 지정 및 템플릿을 참조하세요.

다음 XAML은 복합 컨트롤에 대한 Style 요소를 보여 줍니다. 스타일이 요소에 어떻게 적용되는지 확인하려면 앞의 XAML을 참조하세요. 예를 들어 마지막 TextBlock 요소에는 inlineText 스타일이 있으며, 마지막 TextBox 요소는 기본 스타일을 사용합니다.

MyControl1.xaml에서 Grid 시작 요소 뒤에 다음 XAML을 추가합니다.

<Grid.Resources>
  <Style x:Key="inlineText" TargetType="{x:Type TextBlock}">
    <Setter Property="Margin" Value="10,5,10,0"/>
    <Setter Property="FontWeight" Value="Normal"/>
    <Setter Property="FontSize" Value="12"/>
  </Style>
  <Style x:Key="titleText" TargetType="{x:Type TextBlock}">
    <Setter Property="DockPanel.Dock" Value="Top"/>
    <Setter Property="FontWeight" Value="Bold"/>
    <Setter Property="FontSize" Value="14"/>
    <Setter Property="Margin" Value="10,5,10,0"/>
  </Style>
  <Style TargetType="{x:Type Button}">
    <Setter Property="Margin" Value="10,5,10,0"/>
    <Setter Property="Width" Value="60"/>
  </Style>
  <Style TargetType="{x:Type TextBox}">
    <Setter Property="Margin" Value="10,5,10,0"/>
  </Style>
</Grid.Resources>

확인 및 취소 단추 추가

복합 컨트롤의 최종 요소는 확인취소Button 요소이며, 이 두 요소는 Grid의 마지막 행에서 첫 두 열을 차지합니다. 이러한 요소는 일반적인 이벤트 처리기인 ButtonClicked와 이전 XAML에서 정의된 기본 Button 스타일을 사용합니다.

MyControl1.xaml에서 마지막 TextBox 요소 뒤에 다음 XAML을 추가합니다. 이제 복합 컨트롤의 XAML 부분을 완료했습니다.

<Button Grid.Row="5"
        Grid.Column="0"
        Name="btnOK"
        Click="ButtonClicked">OK</Button>
<Button Grid.Row="5"
        Grid.Column="1"
        Name="btnCancel"
        Click="ButtonClicked">Cancel</Button>

코드 숨김 파일 구현

코드 숨김 파일 MyControl1.xaml.cs에서는 다음과 같은 세 가지 필수 작업을 구현합니다.

  1. 사용자가 단추 중 하나를 클릭할 때 발생하는 이벤트를 처리합니다.

  2. TextBox 요소에서 데이터를 가져오고 사용자 지정 이벤트 인수 개체에 패키지합니다.

  3. 사용자 지정 OnButtonClick 이벤트를 발생시켜 사용자가 완료했음을 호스트에 알리고 데이터를 다시 호스트에 전달합니다.

또한 컨트롤에서는 모양을 변경하는 데 사용할 수 있는 많은 수의 색 및 글꼴 속성을 노출합니다. Windows Forms 컨트롤을 호스트하는 데 사용되는 WindowsFormsHost 클래스와 달리 ElementHost 클래스는 컨트롤의 Background 속성만 노출합니다. 이 코드 예제와 연습: WPF에서 Windows Forms 복합 컨트롤 호스팅에서 설명하는 예제 사이의 유사성을 유지하기 위해 이 컨트롤에서는 나머지 속성을 직접 노출합니다.

코드 숨김 파일의 기본 구조

코드 숨김 파일은 하나의 네임스페이스 MyControls로 구성되며, 이 네임스페이스는 MyControl1MyControlEventArgs라는 두 개의 클래스를 포함합니다.

namespace MyControls  
{  
  public partial class MyControl1 : Grid  
  {  
    //...  
  }  
  public class MyControlEventArgs : EventArgs  
  {  
    //...  
  }  
}  

첫 번째 클래스 MyControl1은 MyControl1.xaml에 정의된 UI의 기능을 구현하는 코드를 포함하는 partial 클래스입니다. MyControl1.xaml를 구문 분석할 때 XAML이 동일한 partial 클래스로 변환되고 두 partial 클래스가 병합되어 컴파일된 컨트롤을 형성합니다. 따라서 코드 숨김 파일의 클래스 이름이 MyControl1.xaml에 할당된 클래스 이름과 일치해야 하며 컨트롤의 루트 요소에서 상속되어야 합니다. 두 번째 클래스 MyControlEventArgs는 데이터를 다시 호스트에 보내는 데 사용되는 이벤트 인수 클래스입니다.

MyControl1.xaml.cs를 엽니다. 다음 이름을 사용하고 Grid에서 상속되도록 기존 클래스 선언을 변경합니다.

public partial class MyControl1 : Grid

컨트롤 초기화

다음 코드에서는 다음과 같은 몇 가지 기본 작업을 구현합니다.

  • 비공개 이벤트 OnButtonClick 및 관련 대리자 MyControlEventHandler를 선언합니다.

  • 사용자 데이터를 저장하는 여러 private 전역 변수를 만듭니다. 이 데이터는 해당 속성을 통해 노출됩니다.

  • 컨트롤의 Init 이벤트에 대한 처리기인 Loaded를 구현합니다. 이 처리기에서는 MyControl1.xaml에 정의된 값을 할당하여 전역 변수를 초기화합니다. 이를 위해서는 일반적인 TextBlock 요소인 nameLabel에 할당된 Name을 사용하여 요소의 속성 설정에 액세스합니다.

기존 생성자를 삭제하고 다음 코드를 MyControl1 클래스에 추가합니다.

public delegate void MyControlEventHandler(object sender, MyControlEventArgs args);
public event MyControlEventHandler OnButtonClick;
private FontWeight _fontWeight;
private double _fontSize;
private FontFamily _fontFamily;
private FontStyle _fontStyle;
private SolidColorBrush _foreground;
private SolidColorBrush _background;

private void Init(object sender, EventArgs e)
{
    //They all have the same style, so use nameLabel to set initial values.
    _fontWeight = nameLabel.FontWeight;
    _fontSize = nameLabel.FontSize;
    _fontFamily = nameLabel.FontFamily;
    _fontStyle = nameLabel.FontStyle;
    _foreground = (SolidColorBrush)nameLabel.Foreground;
    _background = (SolidColorBrush)rootElement.Background;
}

단추의 클릭 이벤트 처리

사용자는 확인 단추나 취소 단추를 클릭하여 데이터 입력 작업을 완료했음을 표시합니다. 두 가지 단추는 모두 동일한 Click 이벤트 처리기인 ButtonClicked를 사용합니다. 두 단추의 이름은 btnOK 또는 btnCancel입니다. 처리기에서 sender 인수의 값을 검사하여 어떤 단추가 클릭되었는지 확인할 때 이 이름을 사용합니다. 처리기에서는 다음 작업을 수행합니다.

  • TextBox 요소의 데이터를 포함한 MyControlEventArgs 개체를 만듭니다.

  • 사용자가 취소 단추를 클릭한 경우 MyControlEventArgs 개체의 IsOK 속성을 false로 설정합니다.

  • OnButtonClick 이벤트를 발생시켜 사용자가 완료했음을 호스트에 알리고 수집한 데이터를 다시 전달합니다.

MyControl1 클래스의 Init 메서드 뒤에 다음 코드를 추가합니다.

private void ButtonClicked(object sender, RoutedEventArgs e)
{
    MyControlEventArgs retvals = new MyControlEventArgs(true,
                                                        txtName.Text,
                                                        txtAddress.Text,
                                                        txtCity.Text,
                                                        txtState.Text,
                                                        txtZip.Text);
    if (sender == btnCancel)
    {
        retvals.IsOK = false;
    }
    if (OnButtonClick != null)
        OnButtonClick(this, retvals);
}

속성 만들기

클래스의 나머지 부분에서는 위에서 설명한 전역 변수에 해당하는 속성을 노출하기만 합니다. 속성이 변경되면 set 접근자가 해당 요소 속성을 변경하고 기본 전역 변수를 업데이트하여 컨트롤 모양을 수정합니다.

MyControl1 클래스에 다음 코드를 추가합니다.

public FontWeight MyControl_FontWeight
{
    get { return _fontWeight; }
    set
    {
        _fontWeight = value;
        nameLabel.FontWeight = value;
        addressLabel.FontWeight = value;
        cityLabel.FontWeight = value;
        stateLabel.FontWeight = value;
        zipLabel.FontWeight = value;
    }
}
public double MyControl_FontSize
{
    get { return _fontSize; }
    set
    {
        _fontSize = value;
        nameLabel.FontSize = value;
        addressLabel.FontSize = value;
        cityLabel.FontSize = value;
        stateLabel.FontSize = value;
        zipLabel.FontSize = value;
    }
}
public FontStyle MyControl_FontStyle
{
    get { return _fontStyle; }
    set
    {
        _fontStyle = value;
        nameLabel.FontStyle = value;
        addressLabel.FontStyle = value;
        cityLabel.FontStyle = value;
        stateLabel.FontStyle = value;
        zipLabel.FontStyle = value;
    }
}
public FontFamily MyControl_FontFamily
{
    get { return _fontFamily; }
    set
    {
        _fontFamily = value;
        nameLabel.FontFamily = value;
        addressLabel.FontFamily = value;
        cityLabel.FontFamily = value;
        stateLabel.FontFamily = value;
        zipLabel.FontFamily = value;
    }
}

public SolidColorBrush MyControl_Background
{
    get { return _background; }
    set
    {
        _background = value;
        rootElement.Background = value;
    }
}
public SolidColorBrush MyControl_Foreground
{
    get { return _foreground; }
    set
    {
        _foreground = value;
        nameLabel.Foreground = value;
        addressLabel.Foreground = value;
        cityLabel.Foreground = value;
        stateLabel.Foreground = value;
        zipLabel.Foreground = value;
    }
}

데이터를 다시 호스트에 보내기

파일의 마지막 구성 요소는 수집한 데이터를 호스트에 다시 보내는 데 사용되는 MyControlEventArgs 클래스입니다.

MyControls 네임스페이스에 다음 코드를 추가합니다. 구현 방법은 간단하므로 자세히 설명하지 않습니다.

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

솔루션을 빌드합니다. 빌드하면 MyControls.dll이라는 DLL이 생성됩니다.

Windows Forms 호스트 애플리케이션 구현

Windows Forms 호스트 애플리케이션은 ElementHost 개체를 사용하여 WPF 복합 컨트롤을 호스트합니다. 애플리케이션은 OnButtonClick 이벤트를 처리하여 복합 컨트롤에서 데이터를 수신합니다. 또한 애플리케이션은 컨트롤 모양을 수정하는 데 사용할 수 있는 옵션 단추 집합도 포함합니다. 다음 그림에서는 애플리케이션을 보여 줍니다.

다음 이미지는 Windows Forms 애플리케이션에서 호스트되는 WPF 복합 컨트롤을 보여 줍니다.

Avalon 컨트롤을 호스팅하는 Windows Form을 보여주는 스크린샷.

프로젝트 만들기

프로젝트를 시작하려면

  1. Visual Studio를 실행하고 새 프로젝트 대화 상자를 엽니다.

  2. Visual C# 및 Windows 범주에서 Windows Forms 애플리케이션 템플릿을 선택합니다.

  3. 새 프로젝트의 이름을 WFHost로 지정합니다.

  4. 위치에는 MyControls 프로젝트를 포함하는 동일한 최상위 폴더를 지정합니다.

  5. 확인을 클릭하여 프로젝트를 만듭니다.

MyControl1 및 기타 어셈블리를 포함하는 DLL에 대한 참조도 추가해야 합니다.

  1. 솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 단추로 클릭하고 참조 추가를 선택합니다.

  2. 찾아보기 탭을 클릭하고 MyControls.dll이 포함된 폴더를 찾습니다. 이 연습에서 이 폴더는 MyControls\bin\Debug입니다.

  3. MyControls.dll을 선택한 다음 확인을 클릭합니다.

  4. 다음 어셈블리에 대한 참조를 추가합니다.

    • PresentationCore

    • PresentationFramework

    • System.Xaml

    • WindowsBase

    • WindowsFormsIntegration

애플리케이션에 대한 사용자 인터페이스 구현

Windows Form 애플리케이션의 UI에는 WPF 복합 컨트롤과 상호 작용하는 여러 컨트롤이 포함되어 있습니다.

  1. Windows Form 디자이너에서 Form1을 엽니다.

  2. 컨트롤 크기에 맞게 폼을 확장합니다.

  3. 양식의 오른쪽 상단에서 System.Windows.Forms.Panel 컨트롤을 추가하여 WPF 복합 컨트롤을 유지합니다.

  4. 양식에 다음 System.Windows.Forms.GroupBox 컨트롤을 추가합니다.

    이름 텍스트
    groupBox1 배경색
    groupBox2 전경색
    groupBox3 글꼴 크기
    groupBox4 글꼴 패밀리
    groupBox5 글꼴 스타일
    groupBox6 글꼴 두께
    groupBox7 컨트롤의 데이터
  5. 다음 System.Windows.Forms.RadioButton 컨트롤을 System.Windows.Forms.GroupBox 컨트롤에 추가합니다.

    GroupBox 이름 텍스트
    groupBox1 radioBackgroundOriginal Original
    groupBox1 radioBackgroundLightGreen LightGreen
    groupBox1 radioBackgroundLightSalmon LightSalmon
    groupBox2 radioForegroundOriginal Original
    groupBox2 radioForegroundRed 빨간색
    groupBox2 radioForegroundYellow 노란색
    groupBox3 radioSizeOriginal Original
    groupBox3 radioSizeTen 10
    groupBox3 radioSizeTwelve 12
    groupBox4 radioFamilyOriginal Original
    groupBox4 radioFamilyTimes Times New Roman
    groupBox4 radioFamilyWingDings WingDings
    groupBox5 radioStyleOriginal 보통
    groupBox5 radioStyleItalic 기울임꼴
    groupBox6 radioWeightOriginal Original
    groupBox6 radioWeightBold 굵게
  6. 다음 System.Windows.Forms.Label 컨트롤을 마지막 System.Windows.Forms.GroupBox에 추가합니다. 이러한 컨트롤은 WPF 복합 컨트롤에서 반환하는 데이터를 표시합니다.

    GroupBox 이름 텍스트
    groupBox7 lblName 이름:
    groupBox7 lblAddress 구/군/시:
    groupBox7 lblCity 시/도:
    groupBox7 lblState 상태:
    groupBox7 lblZip 우편 번호:

폼 초기화

일반적으로 양식의 Load 이벤트 처리기에서 호스팅 코드를 구현합니다. 다음 코드는 WPF 복합 컨트롤의 Loaded 이벤트에 대한 처리기인 Load 이벤트 처리기와 나중에 사용할 여러 전역 변수에 대한 선언을 보여 줍니다.

Windows Forms 디자이너에서 양식을 두 번 클릭하여 Load 이벤트 처리기를 만듭니다. Form1.cs 위쪽에 다음 using 문을 추가합니다.

using System.Windows;
using System.Windows.Forms.Integration;
using System.Windows.Media;

다음 코드로 기존 Form1 클래스의 콘텐츠를 바꿉니다.

private ElementHost ctrlHost;
private MyControls.MyControl1 wpfAddressCtrl;
System.Windows.FontWeight initFontWeight;
double initFontSize;
System.Windows.FontStyle initFontStyle;
System.Windows.Media.SolidColorBrush initBackBrush;
System.Windows.Media.SolidColorBrush initForeBrush;
System.Windows.Media.FontFamily initFontFamily;

public Form1()
{
    InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
    ctrlHost = new ElementHost();
    ctrlHost.Dock = DockStyle.Fill;
    panel1.Controls.Add(ctrlHost);
    wpfAddressCtrl = new MyControls.MyControl1();
    wpfAddressCtrl.InitializeComponent();
    ctrlHost.Child = wpfAddressCtrl;

    wpfAddressCtrl.OnButtonClick +=
        new MyControls.MyControl1.MyControlEventHandler(
        avAddressCtrl_OnButtonClick);
    wpfAddressCtrl.Loaded += new RoutedEventHandler(
        avAddressCtrl_Loaded);
}

void avAddressCtrl_Loaded(object sender, EventArgs e)
{
    initBackBrush = (SolidColorBrush)wpfAddressCtrl.MyControl_Background;
    initForeBrush = wpfAddressCtrl.MyControl_Foreground;
    initFontFamily = wpfAddressCtrl.MyControl_FontFamily;
    initFontSize = wpfAddressCtrl.MyControl_FontSize;
    initFontWeight = wpfAddressCtrl.MyControl_FontWeight;
    initFontStyle = wpfAddressCtrl.MyControl_FontStyle;
}

앞의 코드에서 Form1_Load 메서드는 WPF 컨트롤을 호스트하는 일반적인 절차를 보여 줍니다.

  1. ElementHost 개체를 만듭니다.

  2. 컨트롤의 Dock 속성을 DockStyle.Fill로 설정합니다.

  3. ElementHost 컨트롤을 Panel 컨트롤의 Controls 컬렉션에 추가합니다.

  4. WPF 컨트롤의 인스턴스를 만듭니다.

  5. 컨트롤을 ElementHost 컨트롤의 Child 속성에 할당하여 양식에서 복합 컨트롤을 호스트합니다.

Form1_Load 메서드에서 나머지 두 줄은 처리기를 두 가지 컨트롤 이벤트에 연결합니다.

  • OnButtonClick은 사용자가 확인 또는 취소 단추를 클릭할 때 복합 컨트롤에서 발생하는 사용자 지정 이벤트입니다. 이 이벤트를 처리하여 사용자의 응답을 수신하고 사용자가 지정한 데이터를 수집합니다.

  • Loaded는 완전히 로드되었을 대 WPF 컨트롤에 의해 발생하는 표준 이벤트입니다. 이 예제에서는 컨트롤의 속성을 사용하여 여러 전역 변수를 초기화해야 하기 때문에 이 이벤트가 사용됩니다. 양식의 Load 이벤트 발생 시 컨트롤은 완전히 로드되지 않으며 이러한 값은 여전히 null로 설정됩니다. 이러한 속성에 액세스하기 전에 컨트롤의 Loaded 이벤트가 발생할 때까지 기다려야 합니다.

Loaded 이벤트 처리기가 이전 코드에 표시됩니다. OnButtonClick 처리기는 다음 섹션에서 설명합니다.

OnButtonClick 처리

OnButtonClick 이벤트는 사용자가 확인 또는 취소 단추를 클릭할 때 발생합니다.

이벤트 처리기는 이벤트 인수의 IsOK 필드를 확인하여 어떤 단추를 클릭했는지 확인합니다. 앞에서 논의한 Label 컨트롤에 해당하는 lbl데이터 변수입니다. 사용자가 확인 단추를 클릭하면 컨트롤의 TextBox 컨트롤에 있는 데이터가 해당하는 Label 컨트롤에 할당됩니다. 사용자가 취소를 클릭하면 Text 값이 기본 문자열로 설정됩니다.

Form1 클래스에 다음 단추 클릭 이벤트 처리기 코드를 추가합니다.

void avAddressCtrl_OnButtonClick(
    object sender,
    MyControls.MyControl1.MyControlEventArgs args)
{
    if (args.IsOK)
    {
        lblAddress.Text = "Street Address: " + args.MyStreetAddress;
        lblCity.Text = "City: " + args.MyCity;
        lblName.Text = "Name: " + args.MyName;
        lblState.Text = "State: " + args.MyState;
        lblZip.Text = "Zip: " + args.MyZip;
    }
    else
    {
        lblAddress.Text = "Street Address: ";
        lblCity.Text = "City: ";
        lblName.Text = "Name: ";
        lblState.Text = "State: ";
        lblZip.Text = "Zip: ";
    }
}

애플리케이션을 빌드 및 실행합니다. WPF 복합 컨트롤에 텍스트를 추가하고 확인을 클릭합니다. 텍스트가 레이블에 나타납니다. 현재는 라디오 단추를 처리하는 코드가 추가되지 않았습니다.

컨트롤의 모양 수정

양식의 RadioButton 컨트롤을 사용하면 사용자가 WPF 복합 컨트롤의 전경색, 배경색 및 여러 글꼴 속성을 변경할 수 있습니다. 배경색은 ElementHost 개체에 의해 노출됩니다. 나머지 속성은 컨트롤의 사용자 지정 속성으로 노출됩니다.

양식에서 각 RadioButton 컨트롤을 두 번 클릭하여 CheckedChanged 이벤트 처리기를 만듭니다. CheckedChanged 이벤트 처리기를 다음 코드로 바꿉니다.

private void radioBackgroundOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Background = initBackBrush;
}

private void radioBackgroundLightGreen_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Background = new SolidColorBrush(Colors.LightGreen);
}

private void radioBackgroundLightSalmon_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Background = new SolidColorBrush(Colors.LightSalmon);
}

private void radioForegroundOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Foreground = initForeBrush;
}

private void radioForegroundRed_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Foreground = new System.Windows.Media.SolidColorBrush(Colors.Red);
}

private void radioForegroundYellow_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_Foreground = new System.Windows.Media.SolidColorBrush(Colors.Yellow);
}

private void radioFamilyOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontFamily = initFontFamily;
}

private void radioFamilyTimes_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontFamily = new System.Windows.Media.FontFamily("Times New Roman");
}

private void radioFamilyWingDings_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontFamily = new System.Windows.Media.FontFamily("WingDings");
}

private void radioSizeOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontSize = initFontSize;
}

private void radioSizeTen_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontSize = 10;
}

private void radioSizeTwelve_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontSize = 12;
}

private void radioStyleOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontStyle = initFontStyle;
}

private void radioStyleItalic_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontStyle = System.Windows.FontStyles.Italic;
}

private void radioWeightOriginal_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontWeight = initFontWeight;
}

private void radioWeightBold_CheckedChanged(object sender, EventArgs e)
{
    wpfAddressCtrl.MyControl_FontWeight = FontWeights.Bold;
}

애플리케이션을 빌드 및 실행합니다. WPF 복합 컨트롤에 대한 효과를 확인하려면 다른 라디오 단추를 클릭합니다.

참고 항목