연습: Windows Forms에서 WPF 복합 컨트롤 호스팅
Windows Presentation Foundation (WPF)에서는 응용 프로그램을 만들기 위한 다양한 환경을 제공합니다. 그러나 Windows Forms 코드에 상당한 노력을 기울인 경우 이 코드를 처음부터 다시 작성하지 않고 WPF을 사용하여 기존 Windows Forms 응용 프로그램을 확장하는 것이 더 효율적일 수 있습니다. 일반적으로 WPF에서 구현한 하나 이상의 컨트롤을 Windows Forms 응용 프로그램 내에 포함할 수 있습니다. WPF 컨트롤 사용자 지정에 대한 자세한 내용은 컨트롤 사용자 지정을 참조하십시오.
이 연습에서는 Windows Forms 응용 프로그램에서 데이터 입력을 수행하기 위한 WPF 복합 컨트롤을 호스팅하는 응용 프로그램을 설명합니다. 복합 컨트롤은 DLL 파일로 패키지됩니다. 이러한 일반 절차를 확장하여 보다 복잡한 응용 프로그램과 컨트롤에 적용할 수 있습니다. 이 연습에서 다루는 복합 컨트롤은 연습: WPF에서 Windows Forms 복합 컨트롤 호스팅의 복합 컨트롤과 모양 및 기능이 매우 비슷하게 디자인되었습니다. 주된 차이점은 호스팅 시나리오가 반대로 되어 있다는 것입니다.
이 연습은 두 단원으로 나뉘어져 있습니다. 첫 번째 단원에서는 WPF 복합 컨트롤의 구현에 대해 간략히 설명합니다. 두 번째 단원에서는 Windows Forms 응용 프로그램에서 이 복합 컨트롤을 호스팅하고 컨트롤의 이벤트를 수신하고 컨트롤의 일부 속성에 액세스하는 방법에 대해 자세히 설명합니다.
이 연습에서 수행할 작업은 다음과 같습니다.
WPF 복합 컨트롤 구현
Windows Forms 호스트 응용 프로그램 구현
이 연습에서 설명하는 작업의 전체 코드 목록은 Hosting a WPF Composite Control in Windows Forms 샘플을 참조하십시오.
사전 요구 사항
이 연습을 완료하려면 다음 구성 요소가 필요합니다.
- Visual Studio 2010.
WPF 복합 컨트롤 구현
이 예제에서 사용되는 WPF 복합 컨트롤은 사용자의 이름과 주소를 입력하는 간단한 데이터 입력 폼입니다. 사용자가 작업이 완료되었음을 나타내는 두 개의 단추 중 하나를 클릭하면 컨트롤에서 사용자 지정 이벤트가 발생하여 해당 정보가 호스트에 반환됩니다. 다음 그림에서는 렌더링된 컨트롤을 보여 줍니다.
WPF 복합 컨트롤
프로젝트 만들기
프로젝트를 시작하려면
Microsoft Visual Studio를 시작하고 새 프로젝트 대화 상자를 엽니다.
Visual C# 및 Windows 범주에서 WPF 사용자 정의 컨트롤 라이브러리 템플릿을 선택합니다.
새 프로젝트의 이름을 MyControls로 지정합니다.
위치로는 WindowsFormsHostingWpfControl과 같은 편리한 이름의 최상위 폴더를 지정합니다. 나중에 호스트 응용 프로그램도 이 폴더에 넣습니다.
확인을 클릭하여 프로젝트를 만듭니다. 기본 프로젝트에는 UserControl1이라는 컨트롤 하나가 포함되어 있습니다.
솔루션 탐색기에서 UserControl1의 이름을 MyControl1로 변경합니다.
이 프로젝트에서는 다음과 같은 시스템 DLL에 대한 참조를 포함해야 합니다. 이러한 DLL이 기본적으로 포함되지 않는 경우 프로젝트에 추가합니다.
PresentationCore
PresentationFramework
시스템
WindowsBase
사용자 인터페이스 만들기
이 복합 컨트롤의 user interface (UI)는 Extensible Application Markup Language (XAML)로 구현됩니다. 복합 컨트롤 UI는 다섯 개의 TextBox 요소로 구성됩니다. 각 TextBox 요소에는 레이블로 사용되는 TextBlock 요소가 연결됩니다. 아래쪽에는 확인 및 취소라는 두 개의 Button 요소가 있습니다. 사용자가 이 단추 중 하나를 클릭하면 컨트롤에서 사용자 지정 이벤트가 발생하여 호스트에 정보가 반환됩니다.
기본 레이아웃
다양한 UI 요소가 Grid 요소에 포함됩니다. Grid를 사용하면 HTML의 Table 요소와 같은 방법으로 복합 컨트롤의 내용을 정렬할 수 있습니다. WPF에는 Table 요소도 있지만 Grid가 더 가볍고 단순한 레이아웃 작업에 보다 적합합니다.
다음 XAML에서는 기본적인 레이아웃을 보여 줍니다. 이 XAML에서는 Grid 요소의 열 및 행 수를 지정하여 컨트롤의 전체 구조를 정의합니다.
MyControl1.xaml에서 기존 XAML을 다음 XAML로 바꿉니다.
<Grid xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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 요소 추가
표 요소의 RowProperty 및 ColumnProperty 특성을 해당 행 및 열 번호로 설정하여 표에서 UI 요소를 배치합니다. 행 및 열 번호는 0부터 시작합니다. 요소의 ColumnSpanProperty 특성을 설정하면 요소가 여러 열에 걸쳐 있을 수 있습니다. Grid 요소에 대한 자세한 내용은 방법: Grid 요소 만들기를 참조하십시오.
다음 XAML에서는 복합 컨트롤의 TextBox 및 TextBlock 요소를 보여 줍니다. 여기서는 요소의 RowProperty 및 ColumnProperty 특성을 설정하여 표에서 해당 요소를 적절히 배치합니다.
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에서는 다음과 같은 세 가지 필수 작업을 구현합니다.
사용자가 단추 중 하나를 클릭할 때 발생하는 이벤트를 처리합니다.
TextBox 요소에서 데이터를 검색하고 그 결과를 사용자 지정 이벤트 인수 개체에 패키지합니다.
OnButtonClick 이벤트를 발생시켜 사용자가 완료했음을 호스트에 알리고 데이터를 다시 호스트에 전달합니다.
또한 컨트롤에서는 모양을 변경하는 데 사용할 수 있는 많은 수의 색 및 글꼴 속성을 노출합니다. Windows Forms 컨트롤을 호스팅하는 데 사용되는 WindowsFormsHost 클래스와 달리 ElementHost 클래스에서는 컨트롤의 Background 속성만 노출합니다. 이 코드 예제와 연습: WPF에서 Windows Forms 복합 컨트롤 호스팅에서 설명하는 예제 사이의 유사성을 유지하기 위해 이 컨트롤에서는 나머지 속성을 직접 노출합니다.
코드 숨김 파일의 기본 구조
코드 숨김 파일은 하나의 네임스페이스 MyControls로 구성되며, 이 네임스페이스는 MyControl1 및 MyControlEventArgs라는 두 개의 클래스를 포함합니다.
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
컨트롤 초기화
다음 코드에서는 다음과 같은 몇 가지 기본 작업을 구현합니다.
Private 이벤트 OnButtonClick 및 관련 대리자 MyControlEventHandler를 선언합니다.
사용자 데이터를 저장하는 여러 private 전역 변수를 만듭니다. 이 데이터는 해당 속성을 통해 노출됩니다.
컨트롤의 Loaded 이벤트에 대한 Init 처리기를 구현합니다. 이 처리기에서는 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 복합 컨트롤
프로젝트 만들기
프로젝트를 시작하려면
Visual Studio를 시작하고 새 프로젝트 대화 상자를 엽니다.
Visual C# 및 Windows 범주에서 Windows Forms 응용 프로그램 템플릿을 선택합니다.
새 프로젝트의 이름을 WFHost로 지정합니다.
위치에서 MyControls 프로젝트가 포함된 동일한 최상위 폴더를 지정합니다.
확인을 클릭하여 프로젝트를 만듭니다.
또한 MyControl1 및 다른 어셈블리를 포함하는 DLL에 대한 참조도 추가해야 합니다.
솔루션 탐색기에서 프로젝트 이름을 마우스 오른쪽 단추로 클릭하고 참조 추가를 선택합니다.
찾아보기 탭을 클릭하고 MyControls.dll이 들어 있는 폴더로 이동합니다. 이 연습의 경우 이 폴더는 MyControls\bin\Debug입니다.
MyControls.dll을 선택하고 확인을 클릭합니다.
다음 어셈블리에 대한 참조를 추가합니다.
PresentationCore
PresentationFramework
System.Xaml
WindowsBase
WindowsFormsIntegration
응용 프로그램의 사용자 인터페이스 구현
Windows Form 응용 프로그램의 UI에는 WPF 복합 컨트롤과 상호 작용하는 여러 컨트롤이 포함되어 있습니다.
Windows Form 디자이너에서 Form1을 엽니다.
컨트롤 크기에 맞게 폼을 확장합니다.
폼의 오른쪽 위에서 WPF 복합 컨트롤을 보관할 System.Windows.Forms.Panel 컨트롤을 추가합니다.
폼에 다음 System.Windows.Forms.GroupBox 컨트롤을 추가합니다.
이름
텍스트
groupBox1
배경색
groupBox2
전경색
groupBox3
글꼴 크기
groupBox4
글꼴 패밀리
groupBox5
글꼴 스타일
groupBox6
글꼴 두께
groupBox7
컨트롤의 데이터
System.Windows.Forms.GroupBox 컨트롤에 다음 System.Windows.Forms.RadioButton 컨트롤을 추가합니다.
GroupBox
이름
텍스트
groupBox1
radioBackgroundOriginal
원래 설정
groupBox1
radioBackgroundLightGreen
연한 녹색
groupBox1
radioBackgroundLightSalmon
연한 연어살색
groupBox2
radioForegroundOriginal
원래 설정
groupBox2
radioForegroundRed
빨강
groupBox2
radioForegroundRed
노랑
groupBox3
radioSizeOriginal
원래 설정
groupBox3
radioSizeTen
10
groupBox3
radioSizeTwelve
12
groupBox4
radioFamilyOriginal
원래 설정
groupBox4
radioFamilyTimes
Times New Roman
groupBox4
radioFamilyWingDings
WingDings
groupBox5
radioStyleOriginal
보통
groupBox5
radioStyleItalic
기울임꼴
groupBox6
radioWeightOriginal
원래 설정
groupBox6
radioWeightBold
굵게
마지막 System.Windows.Forms.GroupBox에 다음 System.Windows.Forms.Label 컨트롤을 추가합니다. 이러한 컨트롤에서는 WPF 복합 컨트롤에서 반환하는 데이터를 표시합니다.
GroupBox
이름
텍스트
groupBox7
lblName
이름:
groupBox7
lblAddress
주소:
groupBox7
lblCity
구/군/시:
groupBox7
lblState
시/도:
groupBox7
lblZip
우편 번호:
폼 초기화
일반적으로 폼의 Load 이벤트 처리기에서 호스팅 코드를 구현합니다. 다음 코드에서는 Load 이벤트 처리기, WPF 복합 컨트롤 Loaded 이벤트에 대한 처리기 및 나중에 사용하는 여러 전역 변수에 대한 선언을 보여 줍니다.
Windows Forms 디자이너에서 폼을 두 번 클릭하여 Load 이벤트 처리기를 만듭니다. Form1.cs 맨 위에 다음 using 문을 추가합니다.
using System;
using System.Windows;
using System.Windows.Navigation;
using System.Windows.Controls;
using System.Windows.Media;
namespace MyControls
{
public partial class MyControl1 : Grid
{
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;
}
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);
}
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;
}
}
}
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; }
}
}
}
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 컨트롤을 호스팅하는 다음과 같은 일반적인 절차를 보여 줍니다.
새 ElementHost 개체를 만듭니다.
컨트롤의 Dock 속성을 DockStyle.Fill로 설정합니다.
Panel 컨트롤의 Controls 컬렉션에 ElementHost 컨트롤을 추가합니다.
WPF 컨트롤의 인스턴스를 만듭니다.
ElementHost 컨트롤의 Child 속성에 컨트롤을 할당하여 폼에서 복합 컨트롤을 호스팅합니다.
Form1_Load 메서드에서 나머지 두 줄은 처리기를 다음의 두 가지 컨트롤 이벤트에 연결합니다.
OnButtonClick은 복합 컨트롤에서 사용자가 확인 또는 취소 단추를 클릭할 때 발생하는 사용자 지정 이벤트입니다. 이 이벤트를 처리하여 사용자의 응답을 수신하고 사용자가 지정한 데이터를 수집합니다.
Loaded는 WPF 컨트롤이 완전히 로드되면 발생하는 표준 이벤트입니다. 이 예제에서는 컨트롤의 속성을 사용하여 여러 전역 변수를 초기화해야 하기 때문에 이 이벤트가 사용됩니다. 폼의 Load 이벤트가 발생할 때는 컨트롤이 완전히 로드되지 않았으므로 이 값은 여전히 null로 설정되어 있습니다. 이러한 속성에 액세스할 수 있으려면 컨트롤의 Loaded 이벤트가 발생할 때까지 기다려야 합니다.
Loaded 이벤트 처리기는 앞의 코드에 나와 있습니다. OnButtonClick 처리기는 다음 단원에서 설명합니다.
OnButtonClick 처리
OnButtonClick 이벤트는 사용자가 확인 또는 취소 단추를 클릭할 때 발생합니다.
이 이벤트의 처리기에서는 이벤트 인수의 IsOK 필드를 확인하여 어떤 단추를 클릭했는지 확인합니다. lbldata 변수는 앞에서 설명한 Label 컨트롤에 해당합니다. 사용자가 확인 단추를 클릭한 경우 컨트롤의 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 복합 컨트롤의 효과를 확인합니다.
참고 항목
작업
연습: Windows Forms에서 3-D WPF 복합 컨트롤 호스팅
참조
개념
연습: WPF에서 Windows Forms 복합 컨트롤 호스팅