다음을 통해 공유


연습: 색 편집기 구현

WPF Designer for Visual Studio의 확장성 모델을 사용하면 디자인 타임에 속성 창의 속성에 사용할 사용자 지정 값 편집기를 만들 수 있습니다. 속성 창에서 직접 값을 편집할 수 있도록 인라인 편집기를 만들거나 속성 창 외부에서 속성을 편집할 수 있도록 추가 UI를 제공하는 확장 편집기를 만들 수 있습니다. 확장 편집기를 만드는 방법을 보여 주기 위해 이 연습에서는 컨트롤의 Background 속성에 사용할 색 편집기를 만드는 단계별 절차를 제공합니다. 이 확장 편집기는 속성 창의 인라인 편집기에서 열립니다.

이 연습에서는 다음 작업을 수행합니다.

  • WPF 사용자 지정 컨트롤 프로젝트를 만듭니다.

  • 확장 편집기 기능을 수행하는 사용자 정의 컨트롤을 만듭니다.

  • 속성 창에서 속성 값을 편집하고 확장 편집기를 여는 데 사용할 수 있는 인라인 편집기를 만듭니다.

  • ExtendedPropertyValueEditor에서 상속되는 클래스를 만듭니다. 이 클래스는 사용자 지정 편집 기능을 제공할 클래스에 편집기를 연결하는 데 사용됩니다.

  • IProvideAttributeTable 인터페이스를 구현하는 클래스를 만들어 새로 만든 확장 편집기를 등록합니다.

  • 디자인 타임에 확장 편집기를 테스트합니다.

사전 요구 사항

이 연습을 완료하려면 다음 구성 요소가 필요합니다.

  • Visual Studio 2010.

사용자 지정 컨트롤 만들기

첫 번째 단계로 사용자 지정 컨트롤에 대한 프로젝트를 만듭니다. 이 컨트롤은 디자인 타임 코드가 약간 사용되는 간단한 단추이며, 이 코드에서는 GetIsInDesignMode 메서드를 사용하여 디자인 타임 동작을 구현합니다.

사용자 지정 컨트롤을 만들려면

  1. Visual C#에서 CustomControlLibrary라는 새 WPF 사용자 지정 컨트롤 라이브러리 프로젝트를 만듭니다.

    코드 편집기에 CustomControl1의 코드가 열립니다.

  2. 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))
                {
                    Background = Brushes.Red;
                }
            }
        }
    }
    
  3. 프로젝트의 출력 경로를 "bin\"으로 설정합니다.

  4. 솔루션을 빌드합니다.

확장 편집기의 사용자 정의 컨트롤 만들기

앞의 절차에서 만든 컨트롤은 사용자 지정 색 편집기에 연결할 컨트롤입니다. 이 절차에서는 확장 편집기 기능을 수행할 다른 사용자 정의 컨트롤을 만듭니다.

확장 편집기 기능을 수행하는 사용자 정의 컨트롤을 만들려면

  1. Visual C#에서 CustomControlLibrary.Design이라는 새 WPF 사용자 지정 컨트롤 라이브러리 프로젝트를 솔루션에 추가합니다.

    코드 편집기에 CustomControl1의 코드가 열립니다.

  2. 솔루션 탐색기에서 CustomControlLibrary.Design 프로젝트의 CustomControl1 파일을 삭제합니다.

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

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

  4. CustomControlLibrary 프로젝트에 대한 참조를 추가합니다.

  5. 프로젝트의 출력 경로를 ".. \CustomControlLibrary\bin\"으로 설정합니다. 이렇게 하면 컨트롤의 어셈블리와 메타데이터 어셈블리가 같은 폴더에 유지되므로 디자이너에서 메타데이터를 검색할 수 있습니다.

  6. CustomControlLibrary.Design 프로젝트에 ColorsList라는 새 클래스를 추가합니다.

  7. ColorsList에 대한 코드 편집기에서 자동으로 생성된 코드를 다음 코드로 바꿉니다.

    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Media;
    using System.Reflection;
    using System.Collections.ObjectModel;
    
    namespace CustomControlLibrary.Design
    {
        public class ColorsList : ObservableCollection<Color>
        {
            public ColorsList()
            {
                Type type = typeof(Colors);
                foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.Static))
                {
                    if (propertyInfo.PropertyType == typeof(Color))
                    {
                        Add((Color)propertyInfo.GetValue(null, null));
                    }
                }
            }
        }
    }
    
  8. CustomControlLibrary.Design 프로젝트에 ColorsListControl이라는 새 사용자 정의 컨트롤(WPF)을 추가합니다.

    디자이너에 ColorsListControl.xaml의 코드가 열립니다.

  9. ColorsListControl.xaml에 대한 XAML 뷰에서 자동으로 생성된 XAML을 다음 XAML로 바꿉니다.

        <UserControl x:Class="CustomControlLibrary.Design.ColorsListControl"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Local="clr-namespace:CustomControlLibrary.Design" 
        xmlns:PropertyEditing="clr-namespace:Microsoft.Windows.Design.PropertyEditing;assembly=Microsoft.Windows.Design.Interaction"
        Height="184" Width="260" Background="White">
        <UserControl.Resources>
            <Local:ColorsList x:Key="colors"/>
            <Style TargetType="{x:Type Button}">
                <EventSetter Event="Click" Handler="ItemsControl_Click"/>
            </Style>
        </UserControl.Resources>
    
        <ItemsControl 
            ItemsSource="{Binding Source={StaticResource colors}}" 
            HorizontalContentAlignment="Stretch" 
            VerticalContentAlignment="Stretch" 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch">
            <ItemsControl.Template>
                <ControlTemplate TargetType="ItemsControl">
                    <Border CornerRadius="5" >
                        <WrapPanel Orientation="Horizontal"
                                   VerticalAlignment="Center"
                                   HorizontalAlignment="Center">
                            <ScrollViewer>
                                <ItemsPresenter/>
                            </ScrollViewer>
                        </WrapPanel>
                    </Border>
                </ControlTemplate>
            </ItemsControl.Template>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Tag="{Binding}" Command="{x:Static PropertyEditing:PropertyValueEditorCommands.ShowInlineEditor}">
                        <Button.Template>
                            <ControlTemplate>
                                <Border Width="30" Height="30" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                                    <Rectangle Width="22" Height="22" ToolTip="{Binding}">
                                        <Rectangle.Fill>
                                            <SolidColorBrush Color="{Binding}"/>
                                        </Rectangle.Fill>
                                    </Rectangle>
                                </Border>
                            </ControlTemplate>
                        </Button.Template>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </UserControl>
    
  10. 솔루션 탐색기에서 ColorsListControl.xaml을 확장하고 ColorsListControl.xaml.cs를 엽니다.

  11. ColorsListControl에 대한 코드 편집기에서 자동으로 생성된 코드를 다음 코드로 바꿉니다.

    using System;
    using System.Linq;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    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.Design
    {
        public partial class ColorsListControl : System.Windows.Controls.UserControl
        {
            public ColorsListControl()
            {
                InitializeComponent();
            }
    
            public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register("SelectedColor", typeof(Color), typeof(ColorsListControl), new FrameworkPropertyMetadata(null));
            public Color SelectedColor
            {
                get { return (Color)base.GetValue(SelectedColorProperty); }
                set { base.SetValue(SelectedColorProperty, value); }
            }
    
            public static readonly DependencyProperty SelectedBrushProperty = DependencyProperty.Register("SelectedBrush", typeof(SolidColorBrush), typeof(ColorsListControl), new FrameworkPropertyMetadata(null));
            public SolidColorBrush SelectedBrush
            {
                get { return (SolidColorBrush)base.GetValue(SelectedBrushProperty); }
                set { base.SetValue(SelectedBrushProperty, value); }
            }
    
            private void ItemsControl_Click(object sender, RoutedEventArgs e)
            {
                SelectedColor = (Color)((Button)sender).Tag;
                SelectedBrush = new SolidColorBrush(SelectedColor);
            }
        }
    }
    
  12. 솔루션을 빌드합니다.

  13. 디자이너에 ColorsListControl.xaml을 다시 로드합니다. 그러면 디자인 뷰에 확장 편집기 UI가 나타납니다.

색 편집기용 템플릿 만들기

색 편집기에 대한 인라인 편집기는 확장 편집기보다 단순하며 XAML 데이터 템플릿을 사용하여 만들 수 있습니다. 앞의 절차에서 만든 사용자 정의 컨트롤을 사용하도록 지정하는 확장 편집기용 데이터 템플릿도 만듭니다.

색 편집기용 템플릿을 만들려면

  1. CustomControlLibrary.Design 프로젝트에 EditorResources라는 새 클래스를 추가합니다.

  2. EditorResources에 대한 코드 편집기에서 자동으로 생성된 코드를 다음 코드로 바꿉니다.

    namespace ExtendedEditorNamespace
    {
        using System;
        using System.Collections.Generic;
        using System.Text;
        using System.Windows;
        public partial class EditorResources : ResourceDictionary {
            public EditorResources()
                : base()
            {
                InitializeComponent();
            }
        }
    }
    
  3. 프로젝트 메뉴에서 리소스 사전 추가를 클릭합니다.

  4. 파일 이름을 EditorResources.xaml로 지정하고 추가를 클릭합니다.

    디자이너에 EditorResources.xaml의 코드가 열립니다.

  5. EditorResources.xaml에 대한 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">
    
        <DataTemplate x:Key="BrushExtendedEditorTemplate">
            <Local:ColorsListControl SelectedBrush="{Binding Value, Mode=TwoWay}"/>
        </DataTemplate>
    
    
        <DataTemplate x:Key="BrushInlineEditorTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <TextBox Grid.Column="0" Text="{Binding StringValue}"/>
                <PropertyEditing:EditModeSwitchButton Grid.Column="1"/>
            </Grid>
        </DataTemplate>
    
    </ResourceDictionary>
    
  6. 솔루션을 빌드합니다.

템플릿 캡슐화 및 편집기 등록

이제 어려운 작업은 모두 끝났습니다. 색 편집기용 확장 편집기 및 인라인 편집기 템플릿을 모두 만들었으므로 이제 이들을 캡슐화하는 클래스를 만든 다음 사용자 지정 컨트롤과 함께 등록할 수 있습니다.

편집기를 캡슐화하고 등록하려면

  1. CustomControlLibrary.Design 프로젝트에 BrushExtendedEditor라는 새 클래스를 추가합니다.

  2. BrushExtendedEditor에 대한 코드 편집기에서 자동으로 생성된 코드를 다음 코드로 바꿉니다.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Windows.Design.PropertyEditing;
    using System.Windows;
    
    namespace CustomControlLibrary.Design
    {
        public class BrushExtendedEditor : ExtendedPropertyValueEditor
        {
            private EditorResources res = new EditorResources();
    
            public BrushExtendedEditor()
            {
                this.ExtendedEditorTemplate = res["BrushExtendedEditorTemplate"] as DataTemplate;
                this.InlineEditorTemplate = res["BrushInlineEditorTemplate"] as DataTemplate;
            }
        }
    }
    
  3. CustomControlLibrary.Design 프로젝트에 Metadata라는 새 클래스를 추가합니다.

  4. 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),
                        "Background",
                        PropertyValueEditor.CreateEditorAttribute(
                            typeof(BrushExtendedEditor)));
    
                    return builder.CreateTable();
                }
            }
        }
    }
    
  5. 솔루션을 빌드합니다.

색 편집기 테스트

색 편집기를 만드는 작업을 마쳤습니다. 이제 테스트 작업만 남았습니다. 편집기를 테스트하려면 WPF 응용 프로그램 프로젝트를 솔루션에 추가한 후 사용자 지정 컨트롤을 추가합니다. 그런 다음 속성 창에서 Background 값을 변경하여 새 편집기가 어떻게 작동하는지 봅니다.

색 편집기를 테스트하려면

  1. Visual C#에서 DemoApplication이라는 새 WPF 응용 프로그램 프로젝트를 솔루션에 추가합니다.

    WPF Designer에 MainWindow.xaml이 열립니다.

  2. CustomControlLibrary 프로젝트에 대한 참조를 추가합니다.

  3. 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>
    
  4. 디자이너 뷰에서 컨트롤을 선택합니다.

  5. 속성 창에서 Background 속성 옆의 드롭다운 단추를 클릭합니다. 기본 색 목록 대신 시각적 색 편집기가 표시됩니다.

  6. 편집기에서 색을 선택합니다. 그러면 사용자 지정 컨트롤의 배경이 선택한 색으로 변경됩니다.

참고 항목

작업

연습: 인라인 값 편집기 구현

방법: 값 편집기 만들기

기타 리소스

사용자 지정 편집기 만들기

WPF Designer 확장성