연습: 범주 편집기 만들기
WPF Designer for Visual Studio의 확장성 모델에서는 속성 범주에 사용할 사용자 지정 범주 편집기를 만들 수 있습니다. 범주 편집기를 사용하면 텍스트 관련 속성과 같이 단일 범주에 속하는 관련 속성을 사용자가 편집할 수 있도록 사용자 지정 사용자 인터페이스를 제공할 수 있습니다. 이 연습에서는 컨트롤의 텍스트 관련 속성을 편집하는 데 사용할 수 있는 범주 편집기를 만듭니다.
이 연습에서는 다음 작업을 수행합니다.
WPF 사용자 지정 컨트롤 프로젝트를 만듭니다.
컨트롤의 텍스트 관련 속성을 편집하는 데 사용할 수 있는 범주 편집기를 만듭니다.
컨트롤의 범주 편집기를 나타내는 CategoryEditor에서 상속되는 클래스를 만듭니다.
IProvideAttributeTable 인터페이스를 구현하는 클래스를 만들어 새로 만든 확장 편집기를 등록합니다.
디자인 타임에 범주 편집기를 테스트합니다.
사전 요구 사항
이 연습을 완료하려면 다음 구성 요소가 필요합니다.
- Visual Studio 2010.
사용자 지정 컨트롤 만들기
첫 번째 단계로 사용자 지정 컨트롤에 대한 프로젝트를 만듭니다. 이 컨트롤은 디자인 타임 코드가 약간 사용되는 간단한 단추이며, 이 코드에서는 GetIsInDesignMode 메서드를 사용하여 디자인 타임 동작을 구현합니다.
사용자 지정 컨트롤을 만들려면
Visual C#에서 CustomControlLibrary라는 새 WPF 사용자 지정 컨트롤 라이브러리 프로젝트를 만듭니다.
코드 편집기에 CustomControl1의 코드가 열립니다.
CustomControl1에 대한 코드 편집기에서 CustomControlLibrary 네임스페이스의 코드를 다음 코드로 바꿉니다.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace CustomControlLibrary { public class CustomControl1 : Button { public CustomControl1() { if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) { Content = "In design mode"; } } } }
프로젝트의 출력 경로를 "bin\"으로 설정합니다.
솔루션을 빌드합니다.
속성 정보를 캡슐화할 클래스 만들기
이 연습에서 만들 범주 편집기에는 글꼴 및 관련 속성에 대한 몇 가지 정보가 필요하므로 이러한 정보를 캡슐화하는 클래스를 만듭니다. 이 클래스는 범주 편집기에서 데이터 소스로 사용됩니다.
글꼴 속성 정보를 캡슐화하는 클래스를 만들려면
Visual C#에서 CustomControlLibrary.Design이라는 새 WPF 사용자 지정 컨트롤 라이브러리 프로젝트를 솔루션에 추가합니다.
코드 편집기에 CustomControl1의 코드가 열립니다.
솔루션 탐색기에서 CustomControlLibrary.Design 프로젝트의 CustomControl1 파일을 삭제합니다.
솔루션 탐색기에서 CustomControlLibrary.Design 프로젝트의 Themes 폴더를 삭제합니다.
다음 WPF Designer 어셈블리에 대한 참조를 추가합니다.
Microsoft.Windows.Design.Extensibility
Microsoft.Windows.Design.Interaction
CustomControlLibrary 프로젝트에 대한 참조를 추가합니다.
프로젝트의 출력 경로를 ".. \CustomControlLibrary\bin\"으로 설정합니다. 이렇게 하면 컨트롤의 어셈블리와 메타데이터 어셈블리가 같은 폴더에 유지되므로 디자이너에서 메타데이터를 검색할 수 있습니다.
CustomControlLibrary.Design 프로젝트에 FontList라는 새 클래스를 추가합니다.
FontList에 대한 코드 편집기에서 자동으로 생성된 코드를 다음 코드로 바꿉니다.
using System; using System.Linq; using System.Collections.Generic; using System.Text; using System.Windows.Media; using System.Collections.ObjectModel; using System.Windows; using System.Windows.Data; using System.Globalization; namespace CustomControlLibrary.Design { public class FontList : ObservableCollection<FontFamily> { public FontList() { foreach (FontFamily ff in Fonts.SystemFontFamilies) { Add(ff); } } } public class FontSizeList : ObservableCollection<double> { public FontSizeList() { Add(8); Add(9); Add(10); Add(11); Add(12); Add(14); Add(16); Add(18); Add(20); } } public class FontStyleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { FontStyle fs = (FontStyle)value; return fs == FontStyles.Italic; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null) { bool isSet = (bool)value; if (isSet) { return FontStyles.Italic; } } return FontStyles.Normal; } } public class FontWeightConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { FontWeight fs = (FontWeight)value; return fs == FontWeights.Bold; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null) { bool isSet = (bool)value; if (isSet) { return FontWeights.Bold; } } return FontWeights.Normal; } } }
범주 편집기용 템플릿 만들기
범주 편집기는 XAML 데이터 템플릿을 사용하여 만듭니다. 이 템플릿은 몇 가지 텍스트 관련 속성에 바인딩되는 간단한 사용자 인터페이스를 제공합니다.
범주 편집기용 템플릿을 만들려면
CustomControlLibrary.Design 프로젝트에 EditorResources라는 새 클래스를 추가합니다.
EditorResources에 대한 코드 편집기에서 자동으로 생성된 코드를 다음 코드로 바꿉니다.
namespace CustomControlLibrary.Design { using System; using System.Collections.Generic; using System.Text; using System.Windows; public partial class EditorResources : ResourceDictionary { public EditorResources() : base() { InitializeComponent(); } } }
프로젝트 메뉴에서 리소스 사전 추가를 클릭합니다.
파일 이름을 EditorResources.xaml로 지정하고 추가를 클릭합니다.
EditorResources에 대한 XAML 뷰에서 자동으로 생성된 XAML을 다음 XAML로 바꿉니다.
<ResourceDictionary xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:PropertyEditing="clr-namespace:Microsoft.Windows.Design.PropertyEditing;assembly=Microsoft.Windows.Design.Interaction" xmlns:Local="clr-namespace:CustomControlLibrary.Design" xmlns:Media="clr-namespace:System.Windows.Media;assembly=PresentationCore" xmlns:sys="clr-namespace:System;assembly=mscorlib" x:Class="CustomControlLibrary.Design.EditorResources"> <Local:FontList x:Key="FontFamilyList"/> <Local:FontSizeList x:Key="FontSizeList"/> <Local:FontStyleConverter x:Key="FontStyleConverter"/> <Local:FontWeightConverter x:Key="FontWeightConverter"/> <DataTemplate x:Key="TextCategoryEditorTemplate"> <StackPanel Margin="5"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="50"/> </Grid.ColumnDefinitions> <ComboBox Grid.Column="0" Margin="2" ItemsSource="{Binding Source={StaticResource FontFamilyList}}" SelectedItem="{Binding [FontFamily].PropertyValue.Value}"/> <ComboBox Grid.Column="1" Margin="2" ItemsSource="{Binding Source={StaticResource FontSizeList}}" SelectedItem="{Binding [FontSize].PropertyValue.Value}"/> </Grid> <StackPanel Orientation="Horizontal"> <CheckBox Margin="2" Content="Bold" IsChecked="{Binding Path=[FontWeight].PropertyValue.Value, Converter={StaticResource FontWeightConverter}}"/> <CheckBox Margin="2" Content="Italic" IsChecked="{Binding Path=[FontStyle].PropertyValue.Value, Converter={StaticResource FontStyleConverter}}"/> </StackPanel> </StackPanel> </DataTemplate> </ResourceDictionary>
솔루션을 빌드합니다.
템플릿 캡슐화 및 범주 편집기 등록
범주 편집기용 템플릿을 만들었으므로 이제 CategoryEditor에서 상속되는 클래스를 만들어 템플릿을 사용자 지정 편집기로 사용하고 새 범주 편집기를 등록해야 합니다.
범주 편집기를 캡슐화하고 등록하려면
CustomControlLibrary.Design 프로젝트에 TextCategoryEditor라는 새 클래스를 추가합니다.
TextCategoryEditor에 대한 코드 편집기에서 자동으로 생성된 코드를 다음 코드로 바꿉니다.
namespace CustomControlLibrary.Design { using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using Microsoft.Windows.Design.PropertyEditing; public class TextCategoryEditor : CategoryEditor { private EditorResources res = new EditorResources(); public TextCategoryEditor() { } public override bool ConsumesProperty(PropertyEntry property) { return true; } public override DataTemplate EditorTemplate { get { return res["TextCategoryEditorTemplate"] as DataTemplate; } } public override object GetImage(Size desiredSize) { return null; } public override string TargetCategory { get { return "Text"; } } } }
CustomControlLibrary.Design 프로젝트에 Metadata라는 새 클래스를 추가합니다.
Metadata에 대한 코드 편집기에서 자동으로 생성된 코드를 다음 코드로 바꿉니다.
using System; using System.Collections.Generic; using System.Text; using Microsoft.Windows.Design.Metadata; using System.ComponentModel; using Microsoft.Windows.Design.PropertyEditing; using System.Windows.Media; using System.Windows.Controls; using System.Windows; using CustomControlLibrary; // The ProvideMetadata assembly-level attribute indicates to designers // that this assembly contains a class that provides an attribute table. [assembly: ProvideMetadata(typeof(CustomControlLibrary.Design.Metadata))] namespace CustomControlLibrary.Design { // Container for any general design-time metadata to initialize. // Designers look for a type in the design-time assembly that // implements IProvideAttributeTable. If found, designers instantiate // this class and access its AttributeTable property automatically. internal class Metadata : IProvideAttributeTable { // Accessed by the designer to register any design-time metadata. public AttributeTable AttributeTable { get { AttributeTableBuilder builder = new AttributeTableBuilder(); builder.AddCustomAttributes (typeof(CustomControl1), new EditorAttribute( typeof(TextCategoryEditor), typeof(TextCategoryEditor))); return builder.CreateTable(); } } } }
솔루션을 빌드합니다.
범주 편집기 테스트
범주 편집기가 완성되었으므로 언제든지 사용할 수 있습니다. 테스트 작업만 남았습니다. 범주 편집기를 테스트하려면 WPF 응용 프로그램을 프로젝트에 추가하고 사용자 지정 컨트롤을 WPF 응용 프로그램에 추가한 후 범주 편집기가 어떻게 작동하는지 봅니다.
범주 편집기를 테스트하려면
Visual C#에서 DemoApplication이라는 새 WPF 응용 프로그램 프로젝트를 솔루션에 추가합니다.
WPF Designer에 MainWindow.xaml이 열립니다.
CustomControlLibrary 프로젝트에 대한 참조를 추가합니다.
MainWindow.xaml에 대한 XAML 뷰에서 자동으로 생성된 XAML을 다음 XAML로 바꿉니다. 이 XAML은 CustomControlLibrary 네임스페이스에 대한 참조를 추가하고 CustomControl1 사용자 지정 컨트롤을 추가합니다. 디자인 뷰에서 디자인 모드임을 나타내는 텍스트와 함께 단추가 표시됩니다. 단추가 표시되지 않는 경우 디자이너 위쪽의 정보 표시줄을 클릭하여 뷰를 다시 로드해야 할 수 있습니다.
<Window x:Class="DemoApplication.MainWindow" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300" xmlns:my="clr-namespace:CustomControlLibrary;assembly=CustomControlLibrary"> <Grid> <my:CustomControl1 Margin="30,30,30,30" Name="customControl11"></my:CustomControl1> </Grid> </Window>
디자인 뷰에서 컨트롤을 선택합니다.
속성 창에서 텍스트 범주를 찾습니다.
다른 컨트롤과는 다른 텍스트 속성을 지정하는 데 사용할 수 있는 사용자 인터페이스가 표시됩니다. 드롭다운 목록에서 글꼴 이름과 글꼴 크기를 선택할 수 있습니다. 해당 확인란을 선택하여 굵게 및 기울임꼴을 지정할 수 있습니다.
이 범주에 있는 속성을 변경합니다. 그러면 변경한 내용이 컨트롤에 반영됩니다.