연습: Windows Forms 구성 요소에 스마트 태그 추가

스마트 태그는 일반적으로 사용되는 디자인 타임 옵션을 제공하는 메뉴와 비슷한 UI(사용자 인터페이스) 요소입니다..NET Framework에서 제공하는 표준 구성 요소 및 컨트롤 대부분은 스마트 태그와 디자이너 동사 고급 기능을 포함하고 있습니다.이 연습의 절차에서는 구성 요소와 사용자 지정 컨트롤에 스마트 태그 지원을 추가하는 방법을 보여 줍니다.

Window Forms 구성 요소에 스마트 태그를 추가하여 일반적으로 사용되는 디자인 타임 옵션을 제공할 수 있습니다.스마트 태그 패널의 항목은 범주를 기준으로 논리적으로 그룹화되며 각각의 DesignerActionMethodItem 인스턴스는 선택적으로 디자이너 동사 엔트리로 복제될 수 있습니다..NET Framework에서 제공하는 표준 구성 요소 및 컨트롤 대부분은 스마트 태그와 디자이너 동사 고급 기능을 포함하고 있습니다.또한 구성 요소 및 사용자 지정 컨트롤의 작성자는 일반적으로 푸시 모델을 사용하여 스마트 태그 지원을 추가할 수 있습니다.

푸시 모델을 사용하여 스마트 태그를 추가하려면 구성 요소 프로젝트에 다음을 추가해야 합니다.

  • DesignerActionList에서 파생되고 스마트 태그 메뉴 항목의 대상인 메서드와 속성을 정의하는 클래스를 구현합니다.또한 이 클래스는 DesignerActionItem 인스턴스의 배열을 반환하는 재정의된 GetSortedActionItems 메서드를 제공할 수도 있습니다.

  • ‎구성 요소와 연결된 디자이너 클래스는 ActionLists 속성을 구현해야 합니다.이 속성을 검색하면 하나의 스마트 태그 메뉴와 연결된 DesignerActionList 인스턴스를 모두 포함하는 DesignerActionListCollection이 제공됩니다.이러한 컬렉션에는 하나의 목록만 있는 경우가 종종 있습니다.

[!참고]

스마트 태그 창에서는 스크롤 및 페이징이 지원되지 않습니다. 따라서 창에 스마트 태그 항목을 많이 채우지 않도록 주의해야 합니다.항목이 너무 많으면 스마트 태그 창이 화면 경계 아래로 넘어갈 수 있습니다.

다음 절차에서는 간단한 예제 컨트롤 ColorLabel에서 코드를 사용하여 스마트 태그를 추가하는 방법을 보여 줍니다. 이 컨트롤은 표준 Windows Forms Label 컨트롤에서 파생됩니다.이 컨트롤에는 ColorLabelDesigner라는 관련 디자이너가 있습니다.

이 항목의 코드를 단일 목록으로 복사하려면 방법: Windows Forms 구성 요소에 스마트 태그 연결을 참조하십시오.

사전 요구 사항

이 연습을 완료하려면 다음과 같은 요건이 필요합니다.

  • .NET Framework가 설치된 컴퓨터에서 Windows Forms 응용 프로그램 프로젝트를 만들고 실행할 수 있는 충분한 권한이 있어야 합니다.

‏DesignerActionList에서 파생된 클래스를 구현하려면

  1. 구성 요소와 같은 네임스페이스에 DesignerActionList에서 파생된 클래스의 선언을 추가합니다.

    [!참고]

    디자인 타임 어셈블리 System.Design.dll에 대한 참조를 추가해야 합니다.이 어셈블리는 .NET Framework 4 Client Profile에 포함되지 않습니다.System.Design.dll에 대한 참조를 추가하려면 프로젝트의 대상 프레임워크를 .NET Framework 4로 변경해야 합니다.

    Public Class ColorLabelActionList
        Inherits System.ComponentModel.Design.DesignerActionList
    
    public class ColorLabelActionList :
              System.ComponentModel.Design.DesignerActionList
    
  2. 연결된 컨트롤의 인스턴스를 받는 생성자를 이 클래스에 추가합니다.이 인스턴스에 대한 참조를 보관할 전용 필드를 제공합니다.또한 DesignerActionService에 대한 참조를 캐시할 전용 필드도 제공합니다.이 필드는 목록을 업데이트하는 데 사용됩니다.

    Private colLabel As ColorLabel
    
    
    ...
    
    
    Private designerActionUISvc As DesignerActionUIService = Nothing
    
    
    ...
    
    
    Public Sub New(ByVal component As IComponent)
    
        MyBase.New(component)
        Me.colLabel = component
    
        ' Cache a reference to DesignerActionUIService, so the
        ' DesigneractionList can be refreshed.
        Me.designerActionUISvc = _
        CType(GetService(GetType(DesignerActionUIService)), _
        DesignerActionUIService)
    
    End Sub
    
    private ColorLabel colLabel;
    
    
    ...
    
    
    private DesignerActionUIService designerActionUISvc = null;
    
    
    ...
    
    
    public ColorLabelActionList( IComponent component ) : base(component) 
    {
        this.colLabel = component as ColorLabel;
    
        // Cache a reference to DesignerActionUIService, so the
        // DesigneractionList can be refreshed.
        this.designerActionUISvc =
            GetService(typeof(DesignerActionUIService))
            as DesignerActionUIService;
    }
    
  3. 스마트 태그 항목과 연결하려는 메서드 및 속성을 추가합니다.메서드는 해당 스마트 태그 엔트리가 선택될 때 실행됩니다.속성은 현재 값이 표시될 수 있도록 getter 섹션이 있어야 합니다. 그 값을 해당 스마트 태그 엔트리에서 편집할 수 있으면 GetProperties 메서드를 사용하는 setter 섹션을 가질 수도 있습니다.

    [!참고]

    디자인 타임 환경 전체에서 그렇듯이, 속성이 편집 가능하려면 기본 형식 중 하나를 .NET Framework에서 제공하거나 제공된 TypeConverter에 의해 해당 형식이 기본 형식으로 변환될 수 있거나 사용자 지정 UITypeEditor가 제공되어야 합니다.

    Public Property ForeColor() As Color
        Get
            Return colLabel.ForeColor
        End Get
        Set(ByVal value As Color)
            GetPropertyByName("ForeColor").SetValue(colLabel, value)
        End Set
    End Property
    
    
    ...
    
    
    'Boolean properties are automatically displayed with binary 
    ' UI (such as a checkbox).
    Public Property LockColors() As Boolean
        Get
            Return colLabel.ColorLocked
        End Get
        Set(ByVal value As Boolean)
            GetPropertyByName("ColorLocked").SetValue(colLabel, value)
    
            ' Refresh the list.
            Me.designerActionUISvc.Refresh(Me.Component)
        End Set
    End Property
    
    
    ...
    
    
    Public Sub InvertColors()
        Dim currentBackColor As Color = colLabel.BackColor
        BackColor = Color.FromArgb( _
        255 - currentBackColor.R, _
        255 - currentBackColor.G, _
        255 - currentBackColor.B)
    
        Dim currentForeColor As Color = colLabel.ForeColor
        ForeColor = Color.FromArgb( _
        255 - currentForeColor.R, _
        255 - currentForeColor.G, _
        255 - currentForeColor.B)
    End Sub
    
    public Color ForeColor
    {
        get
        {
            return colLabel.ForeColor;
        }
        set
        {
            GetPropertyByName("ForeColor").SetValue(colLabel, value);
        }
    }
    
    
    ...
    
    
    // Boolean properties are automatically displayed with binary 
    // UI (such as a checkbox).
    public bool LockColors
    {
        get
        {
            return colLabel.ColorLocked;
        }
        set
        {
            GetPropertyByName("ColorLocked").SetValue(colLabel, value);
    
            // Refresh the list.
            this.designerActionUISvc.Refresh(this.Component);
        }
    }
    
    
    ...
    
    
    public void InvertColors()
    {
        Color currentBackColor = colLabel.BackColor;
        BackColor = Color.FromArgb(
            255 - currentBackColor.R, 
            255 - currentBackColor.G, 
            255 - currentBackColor.B);
    
        Color currentForeColor = colLabel.ForeColor;
        ForeColor = Color.FromArgb(
            255 - currentForeColor.R, 
            255 - currentForeColor.G, 
            255 - currentForeColor.B);
    }
    
  4. 필요에 따라 DesignerActionItem 인스턴스의 배열을 반환하려면 GetSortedActionItems 메서드의 재정의된 버전을 구현합니다. 여기서 각 항목은 이전 단계에서 만들어진 속성 또는 메서드와 연결됩니다.항목 순서를 바꾸거나 분류하거나 또는 선택적으로 항목을 표시하기 위해 이 작업을 수행할 수 있습니다.또한 목록에 논리 그룹 제목과 같은 정적 항목이 포함될 수도 있습니다.

    Public Overrides Function GetSortedActionItems() _
    As DesignerActionItemCollection
        Dim items As New DesignerActionItemCollection()
    
        'Define static section header entries.
        items.Add(New DesignerActionHeaderItem("Appearance"))
        items.Add(New DesignerActionHeaderItem("Information"))
    
        'Boolean property for locking color selections.
        items.Add(New DesignerActionPropertyItem( _
        "LockColors", _
        "Lock Colors", _
        "Appearance", _
        "Locks the color properties."))
    
        If Not LockColors Then
            items.Add( _
            New DesignerActionPropertyItem( _
            "BackColor", _
            "Back Color", _
            "Appearance", _
            "Selects the background color."))
    
            items.Add( _
            New DesignerActionPropertyItem( _
            "ForeColor", _
            "Fore Color", _
            "Appearance", _
            "Selects the foreground color."))
    
            'This next method item is also added to the context menu 
            ' (as a designer verb).
            items.Add( _
            New DesignerActionMethodItem( _
            Me, _
            "InvertColors", _
            "Invert Colors", _
            "Appearance", _
            "Inverts the fore and background colors.", _
            True))
        End If
        items.Add( _
        New DesignerActionPropertyItem( _
        "Text", _
        "Text String", _
        "Appearance", _
        "Sets the display text."))
    
        'Create entries for static Information section.
        Dim location As New StringBuilder("Location: ")
        location.Append(colLabel.Location)
        Dim size As New StringBuilder("Size: ")
        size.Append(colLabel.Size)
    
        items.Add( _
        New DesignerActionTextItem( _
        location.ToString(), _
        "Information"))
    
        items.Add( _
        New DesignerActionTextItem( _
        size.ToString(), _
        "Information"))
    
        Return items
    End Function
    
    public override DesignerActionItemCollection GetSortedActionItems()
    {
        DesignerActionItemCollection items = new DesignerActionItemCollection();
    
        //Define static section header entries.
        items.Add(new DesignerActionHeaderItem("Appearance"));
        items.Add(new DesignerActionHeaderItem("Information"));
    
        //Boolean property for locking color selections.
        items.Add(new DesignerActionPropertyItem("LockColors",
                         "Lock Colors", "Appearance",
                         "Locks the color properties."));
        if (!LockColors)
        {
            items.Add(new DesignerActionPropertyItem("BackColor",
                             "Back Color", "Appearance",
                             "Selects the background color."));
            items.Add(new DesignerActionPropertyItem("ForeColor",
                             "Fore Color", "Appearance",
                             "Selects the foreground color."));
    
            //This next method item is also added to the context menu 
            // (as a designer verb).
            items.Add(new DesignerActionMethodItem(this,
                             "InvertColors", "Invert Colors",
                             "Appearance",
                             "Inverts the fore and background colors.",
                              true));
        }
        items.Add(new DesignerActionPropertyItem("Text",
                         "Text String", "Appearance",
                         "Sets the display text."));
    
        //Create entries for static Information section.
        StringBuilder location = new StringBuilder("Location: ");
        location.Append(colLabel.Location);
        StringBuilder size = new StringBuilder("Size: ");
        size.Append(colLabel.Size);
        items.Add(new DesignerActionTextItem(location.ToString(),
                         "Information"));
        items.Add(new DesignerActionTextItem(size.ToString(),
                         "Information"));
    
        return items;
    }
    

ActionLists 속성을 구현하도록 관련 디자이너 클래스를 업데이트하려면

  1. 해당 컨트롤의 디자이너 클래스를 찾습니다.디자이너 클래스가 없으면 하나를 만들고 이를 컨트롤 클래스와 연결합니다.디자이너에 대한 자세한 내용은 기본 디자이너 클래스를 참조하십시오.

  2. 최적화 기술로 DesignerActionListCollection 형식의 전용 필드를 추가합니다.

    Private lists As DesignerActionListCollection
    
    private DesignerActionListCollection actionLists;
    
  3. 앞서 만든 ColorLabelActionList 클래스의 새 인스턴스를 반환하려면 재정의된 ActionLists 속성을 추가합니다.

    Public Overrides ReadOnly Property ActionLists() _
    As DesignerActionListCollection
        Get
            If lists Is Nothing Then
                lists = New DesignerActionListCollection()
                lists.Add( _
                New ColorLabelActionList(Me.Component))
            End If
            Return lists
        End Get
    End Property
    
    public override DesignerActionListCollection ActionLists
    {
        get
        {
            if (null == actionLists)
            {
                actionLists = new DesignerActionListCollection();
                actionLists.Add(
                    new ColorLabelActionList(this.Component));
            }
            return actionLists;
        }
    }
    

설명

일부 코드 영역에 대해서는 자세히 설명할 필요가 있습니다.

  • DesignerActionList에서 파생된 클래스에서 속성이나 메서드가 연결된 컨트롤의 상태를 변경할 경우 구성 요소의 속성에 대해 직접 setter 호출을 수행하여 변경할 수 없습니다.대신 올바로 만들어진 PropertyDescriptor를 통해 변경해야 합니다.이렇게 간접적인 방법을 사용하면 스마트 태그 실행 취소 및 UI 업데이트 작업이 제대로 작동합니다.

  • DesignerActionUIService.Refresh를 호출하여 스마트 태그 패널을 동적으로 업데이트할 수 있습니다.이 프로세스는 스마트 태그 패널의 내용을 동적으로 변경할 때 사용할 수 있습니다.이 예제에서 색상 변경에 해당되는 스마트 태그는 LockColors 속성의 상태에 따라 조건적으로 포함됩니다.이 부울 속성은 스마트 태그와도 연결되므로 개발자는 적어도 메뉴를 통해 현재 색상 선택을 잠그거나 잠금 취소할 수 있습니다.

  • DesignerActionMethodItem 형식의 스마트 태그 엔트리를 생성자의 includeAsDesignerVerb 매개 변수를 true로 설정하여 연결된 컨트롤의 바로 가기 메뉴에 선택적으로 포함시킬 수도 있습니다.그러면 .NET Framework는 해당 DesignerVerb를 암시적으로 만들어 이를 바로 가기 메뉴에 추가합니다.이 예제에서 InvertColors 항목이 이러한 방식으로 처리됩니다.

  • 스마트 태그 항목은 패널에서 해당 Category 속성에 의해 그룹화됩니다. 이 속성은 각 항목의 생성자에 설정됩니다.이 속성이 명시적으로 설정되지 않으면 기본 범주로 할당됩니다.스마트 태그 패널에서 각 항목은 범주별로 정렬된 다음 DesignerActionList 클래스에서 파생된 클래스가 반환하는 DesignerActionItem 배열에서 나타나는 순서를 기준으로 정렬됩니다.다음 예제에는 두 개의 범주 Appearance 및 Information이 포함되어 있습니다.

    [!참고]

    두 번째 범주에 대해서는 어떤 DesignerActionHeaderItem도 제공되지 않습니다.

  • 정적 텍스트 정보를 표시하는 엔트리는 연결된 속성에 setter만 포함하는 DesignerActionTextItem 또는 DesignerActionPropertyItem을 사용하여 구현할 수 있습니다.이 예제에서는 전자의 방식을 사용합니다.

다음 단계

디자인 타임 환경에 구성 요소를 통합하기 시작했으면 해당 디자이너 지원을 확장하는 방안을 고려해 보십시오.

참고 항목

참조

DesignerVerb

DesignerActionItem

DesignerActionList

ActionLists

DesignerActionService

개념

Windows Forms용 디자이너 명령 및 DesignerAction 개체 모델