속성 창 사용자 지정
Visual Studio에서 DSL(도메인 특정 언어)의 속성 창 모양 및 동작을 사용자 지정할 수 있습니다. DSL 정의에서 각 도메인 클래스에 대해 도메인 속성을 정의합니다. 기본적으로 다이어그램 또는 모델 탐색기에서 클래스의 인스턴스를 선택하면 속성 창에 모든 도메인 속성이 나열됩니다. 이를 통해 다이어그램에서 도형 필드에 매핑하지 않은 경우에도 도메인 속성의 값을 보고 편집할 수 있습니다.
이름, 설명 및 범주
이름 및 표시 이름. 도메인 속성의 정의에서 속성의 표시 이름은 런타임에 속성 창에 표시되는 이름입니다. 반면 이름은 프로그램 코드를 작성하여 속성을 업데이트할 때 사용됩니다. 이름은 올바른 CLR 영숫자 이름이어야 하지만 표시 이름은 공백을 포함할 수 있습니다.
DSL 정의에서 속성의 이름을 설정하면 해당 표시 이름이 이름의 복사본으로 자동 설정됩니다. "FuelGauge"와 같은 파스칼식 대/소문자 이름을 쓰면 표시 이름은 공백이 자동으로 포함되어 “Fuel Gauge”가 됩니다. 다만 표시 이름을 명시적으로 다른 값으로 설정할 수 있습니다.
설명. 도메인 속성의 설명은 다음 두 위치에 표시됩니다.
사용자가 속성을 선택할 때 속성 창 맨 아래에. 이를 사용하여 속성이 나타내는 사용자를 설명할 수 있습니다.
생성된 프로그램 코드에. API 설명서를 추출하는 설명서 기능을 사용하는 경우 API에서 이 속성에 대한 설명으로 표시됩니다.
범주. 범주는 속성 창의 제목입니다.
스타일 기능 노출
그래픽 요소의 동적 기능 중 일부는 도메인 속성으로 표시하거나 노출할 수 있습니다. 이 방식으로 노출된 기능은 사용자가 업데이트할 수 있으며, 프로그램 코드를 사용하면 보다 쉽게 업데이트할 수 있습니다.
DSL 정의에서 도형 클래스를 마우스 오른쪽 단추로 클릭하고 노출 추가를 가리킨 다음 기능을 선택합니다.
도형에서 FillColor, OutlineColor, TextColor, OutlineDashStyle, OutlineThickness 및 FillGradientMode 속성을 노출할 수 있습니다. 연결선에서 Color,
TextColor, DashStyle 및 Thickness 속성을 노출할 수 있습니다. 다이어그램에서 FillColor 및 TextColor 속성을 노출할 수 있습니다.
전달: 관련 요소의 속성 표시
DSL의 사용자가 모델에서 요소를 선택하면 해당 요소의 속성이 속성 창에 표시됩니다. 하지만 지정된 관련 요소의 속성도 표시할 수 있습니다. 이는 함께 작동하는 요소 그룹을 정의한 경우에 유용합니다. 예를 들어 주 요소와 선택적 플러그 인 요소를 정의할 수 있습니다. 주 요소가 도형에 매핑되고 다른 요소는 매핑되지 않은 경우 모든 속성을 한 요소에 있는 것처럼 표시하는 것이 유용합니다.
이 효과를 속성 전달이라고 하며 몇몇 경우에 자동으로 발생합니다. 도메인 형식 설명자를 정의하여 속성을 전달할 수 있는 경우도 있습니다.
기본 속성 전달 사례
사용자가 도형이나 연결선 또는 요소를 탐색기에서 선택하면 속성 창에 다음 속성이 표시됩니다.
기본 클래스에 정의된 요소를 포함하여 모델 요소의 도메인 클래스에 정의된 도메인 속성. Is Browsable을
False
로 설정한 도메인 속성은 예외입니다.다중성이 0..1인 관계를 통해 연결된 요소의 이름. 이렇게 하면 관계의 연결선 매핑을 정의하지 않은 경우에도 선택적으로 연결된 요소를 편리하게 볼 수 있습니다.
요소를 대상으로 하는 포함 관계의 도메인 속성. 포함 관계는 일반적으로 명시적으로 표시되지 않으므로 이를 통해 사용자가 해당 속성을 볼 수 있습니다.
선택한 도형 또는 연결선에 정의된 도메인 속성.
속성 전달 추가
속성을 전달하려면 도메인 형식 설명자를 정의합니다. 두 도메인 클래스 간에 도메인 관계가 있는 경우 도메인 형식 설명자를 사용하여 첫 번째 클래스의 도메인 속성을 두 번째 도메인 클래스의 도메인 속성 값으로 설정할 수 있습니다. 예를 들어 Book 도메인 클래스와 Author 도메인 클래스 간에 관계가 있는 경우 도메인 형식 설명자를 사용하면 사용자가 Book을 선택할 때 Book의 Author의 Name 속성이 속성 창에 표시되도록 할 수 있습니다.
참고 항목
속성 전달은 사용자가 모델을 편집할 때 속성 창에만 영향을 줍니다. 받는 클래스의 도메인 속성은 정의하지 않습니다. DSL 정의의 다른 부분이나 프로그램 코드에서 전달된 도메인 속성에 액세스하려면 전달 요소에 액세스해야 합니다.
다음 절차에서는 DSL을 만들었다고 가정합니다. 처음 몇 단계에서는 필수 구성 요소를 요약합니다.
다른 요소에서 속성 전달
이 예제에서는 Book 및 Author라고 하는 두 개 이상의 클래스가 포함된 도메인 특정 언어 도구 솔루션을 만듭니다. Book과 Author 사이에는 다음 두 종류 중 하나의 관계가 있어야 합니다.
원본 역할(Book 쪽에서의 역할)의 다중성이 0..1 또는 1..1이어야 Book의 Author가 한 명이 됩니다.
DSL 탐색기에서 Book 도메인 클래스를 마우스 오른쪽 단추로 클릭한 다음 새 DomainTypeDescriptor 추가를 클릭합니다.
사용자 지정 형식 설명자 노드 아래에 사용자 지정 속성 설명자의 경로라는 노드가 나타납니다.
사용자 지정 형식 설명자 노드를 마우스 오른쪽 단추로 클릭한 다음 새 PropertyPath 추가를 클릭합니다.
새 속성 경로가 사용자 지정 속성 설명자의 경로 노드 아래에 나타납니다.
새 속성 경로를 선택하고, 속성 창에서 속성 경로를 적절한 모델 요소의 경로로 설정합니다.
이 속성의 오른쪽에 있는 아래쪽 화살표를 클릭하여 트리 뷰에서 경로를 편집할 수 있습니다. 도메인 경로에 대한 자세한 내용은 도메인 경로 구문을 참조하세요. 편집한 경로는 BookReferencesAuthor.Author/!Author와 비슷해야 합니다.
속성을 Author의 Name 도메인 속성으로 설정합니다.
표시 이름을 Author Name으로 설정합니다.
모든 템플릿을 변환하고 DSL을 빌드 및 실행합니다.
모델 다이어그램에서 책과 저자를 만들고 참조 관계를 사용하여 연결합니다. 책 요소를 선택합니다. 속성 창에 책의 속성 외에 저자 이름도 표시되어야 합니다. 연결된 저자의 이름을 변경하거나 책을 다른 저자에 연결하고, 책의 Author Name이 변경되는지 확인합니다.
사용자 지정 속성 편집기
속성 창은 각 도메인 속성의 형식을 편집할 수 있는 적절한 기본 환경을 제공합니다. 예를 들어 열거 형식의 경우 사용자에게 드롭다운 목록이 표시되고, 숫자 속성의 경우 사용자가 숫자를 입력할 수 있습니다. 이것은 기본 제공 형식에만 해당됩니다. 외부 형식을 지정하는 경우 사용자는 속성의 값을 볼 수 있지만 편집할 수는 없습니다.
다만 다음 편집기와 형식을 지정할 수 있습니다.
표준 형식과 함께 사용되는 다른 편집기. 예를 들어 문자열 속성을 위한 파일 경로 편집기를 지정할 수 있습니다.
도메인 속성의 외부 형식 및 해당 형식을 위한 편집기.
파일 경로 편집기와 같은 .NET 편집기(또는 자체 사용자 지정 속성 편집기를 만들 수 있습니다).
기본 편집기가 있는 문자열 같은 형식과 외부 형식 간의 변환.
DSL에서 외부 형식은 단순 형식(예: 부울 또는 Int32)이나 문자열이 아닌 형식입니다.
외부 형식이 있는 도메인 속성 정의
솔루션 탐색기에서 외부 형식이 포함된 어셈블리(DLL)에 대한 참조를 Dsl 프로젝트에 추가합니다.
어셈블리는 .NET 어셈블리이거나 사용자가 제공하는 어셈블리일 수 있습니다.
아직 추가하지 않은 경우 형식을 도메인 형식 목록에 추가합니다.
DslDefinition.dsl을 열고, DSL 탐색기에서 루트 노드를 마우스 오른쪽 단추로 클릭한 다음 새 외부 형식 추가를 클릭합니다.
도메인 형식 노드 아래에 새 항목이 나타납니다.
Warning
메뉴 항목은 도메인 형식 노드가 아닌 DSL 루트 노드에 있습니다.
속성 창에서 새 형식의 이름과 네임스페이스를 설정합니다.
일반적인 방법으로 도메인 클래스에 도메인 속성을 추가합니다.
속성 창의 형식 필드에 있는 드롭다운 목록에서 외부 형식을 선택합니다.
이 단계에서 사용자는 속성의 값을 볼 수 있지만 속성을 편집할 수는 없습니다. 표시된 값은
ToString()
함수에서 가져옵니다. 예를 들어 명령 또는 규칙에서 속성의 값을 설정하는 프로그램 코드를 작성할 수 있습니다.
속성 편집기 설정
도메인 속성에 다음 형식으로 CLR 특성을 추가합니다.
[System.ComponentModel.Editor (
typeof(AnEditor),
typeof(System.Drawing.Design.UITypeEditor))]
속성 창에서 사용자 지정 특성 항목을 사용하여 속성에 특성을 설정할 수 있습니다.
AnEditor
형식은 두 번째 매개 변수에 지정된 형식에서 파생되어야 합니다. 두 번째 매개 변수는 UITypeEditor 또는 ComponentEditor여야 합니다. 자세한 내용은 EditorAttribute를 참조하세요.
FileNameEditor 또는 ImageEditor와 같은 .NET 편집기 또는 자체 편집기를 지정할 수 있습니다. 예를 들어 다음 절차를 사용하면 사용자가 파일 이름을 입력할 수 있는 속성이 생깁니다.
파일 이름 도메인 속성 정의
DSL 정의에서 도메인 클래스에 도메인 속성을 추가합니다.
새 속성을 선택합니다. 속성 창의 사용자 지정 특성 필드에 다음 특성을 입력합니다. 이 특성을 입력하려면 줄임표 [...]를 클릭한 다음 특성 이름과 매개 변수를 따로 입력합니다.
[System.ComponentModel.Editor ( typeof(System.Windows.Forms.Design.FileNameEditor) , typeof(System.Drawing.Design.UITypeEditor))]
도메인 속성의 형식을 기본 설정인 String으로 둡니다.
편집기를 테스트하려면 사용자가 파일 이름 편집기를 열어 도메인 속성을 편집할 수 있는지 확인합니다.
Ctrl+F5 또는 F5 키를 누릅니다. 디버깅 솔루션에서 테스트 파일을 엽니다. 도메인 클래스의 요소를 만들고 선택합니다.
속성 창에서 도메인 속성을 선택합니다. 값 필드에 줄임표 [...]가 표시됩니다.
줄임표를 클릭합니다. 파일 대화 상자가 나타납니다. 파일을 선택하고 대화 상자를 닫습니다. 이제 파일 경로가 도메인 속성의 값입니다.
자체 속성 편집기 정의
자체 편집기를 정의할 수 있습니다. 이렇게 하면 정의한 형식을 사용자가 편집하거나 표준 형식을 특별한 방식으로 편집할 수 있습니다. 예를 들어 수식을 나타내는 문자열을 사용자가 입력하도록 할 수 있습니다.
UITypeEditor에서 파생된 클래스를 작성하여 편집기를 정의합니다. 클래스는 다음을 재정의해야 합니다.
EditValue - 사용자와 상호 작용하고 속성 값을 업데이트합니다.
GetEditStyle - 편집기에서 대화 상자를 열지 아니면 드롭다운 메뉴를 제공할지 지정합니다.
속성 그리드에 표시될 속성 값의 그래픽 표현을 제공할 수도 있습니다. 그러려면 GetPaintValueSupported
및 PaintValue
를 재정의합니다. 자세한 내용은 UITypeEditor를 참조하세요.
참고 항목
Dsl 프로젝트에서 별도의 코드 파일에 다음 코드를 추가합니다.
예시:
internal class TextFileNameEditor : System.Windows.Forms.Design.FileNameEditor
{
protected override void InitializeDialog(System.Windows.Forms.OpenFileDialog openFileDialog)
{
base.InitializeDialog(openFileDialog);
openFileDialog.Filter = "Text files(*.txt)|*.txt|All files (*.*)|*.*";
openFileDialog.Title = "Select a text file";
}
}
이 편집기를 사용하려면 도메인 속성의 사용자 지정 특성을 다음으로 설정합니다.
[System.ComponentModel.Editor (
typeof(MyNamespace.TextFileNameEditor)
, typeof(System.Drawing.Design.UITypeEditor))]
자세한 내용은 UITypeEditor를 참조하세요.
값의 드롭다운 목록 제공
사용자가 선택할 수 있는 값 목록을 제공할 수 있습니다.
참고 항목
이 방법은 런타임에 변경할 수 있는 값 목록을 제공합니다. 변경되지 않는 목록을 제공하려면 대신 열거형 형식을 도메인 속성의 형식으로 사용하는 것이 좋습니다.
표준 값 목록을 정의하려면 다음 형식의 CLR 특성을 도메인 속성에 추가합니다.
[System.ComponentModel.TypeConverter
(typeof(MyTypeConverter))]
TypeConverter에서 파생된 클래스를 정의합니다. Dsl 프로젝트에서 별도의 파일에 코드를 추가합니다. 예시:
/// <summary>
/// Type converter that provides a list of values
/// to be displayed in the property grid.
/// </summary>
/// <remarks>This type converter returns a list
/// of the names of all "ExampleElements" in the
/// current store.</remarks>
public class MyTypeConverter : System.ComponentModel.TypeConverter
{
/// <summary>
/// Return true to indicate that we return a list of values to choose from
/// </summary>
/// <param name="context"></param>
public override bool GetStandardValuesSupported
(System.ComponentModel.ITypeDescriptorContext context)
{
return true;
}
/// <summary>
/// Returns true to indicate that the user has
/// to select a value from the list
/// </summary>
/// <param name="context"></param>
/// <returns>If we returned false, the user would
/// be able to either select a value from
/// the list or type in a value that is not in the list.</returns>
public override bool GetStandardValuesExclusive
(System.ComponentModel.ITypeDescriptorContext context)
{
return true;
}
/// <summary>
/// Return a list of the values to display in the grid
/// </summary>
/// <param name="context"></param>
/// <returns>A list of values the user can choose from</returns>
public override StandardValuesCollection GetStandardValues
(System.ComponentModel.ITypeDescriptorContext context)
{
// Try to get a store from the current context
// "context.Instance" returns the element(s) that
// are currently selected i.e. whose values are being
// shown in the property grid.
// Note that the user could have selected multiple objects,
// in which case context.Instance will be an array.
Store store = GetStore(context.Instance);
List<string> values = new List<string>();
if (store != null)
{
values.AddRange(store.ElementDirectory
.FindElements<ExampleElement>()
.Select<ExampleElement, string>(e =>
{
return e.Name;
}));
}
return new StandardValuesCollection(values);
}
/// <summary>
/// Attempts to get to a store from the currently selected object(s)
/// in the property grid.
/// </summary>
private Store GetStore(object gridSelection)
{
// We assume that "instance" will either be a single model element, or
// an array of model elements (if multiple items are selected).
ModelElement currentElement = null;
object[] objects = gridSelection as object[];
if (objects != null && objects.Length > 0)
{
currentElement = objects[0] as ModelElement;
}
else
{
currentElement = gridSelection as ModelElement;
}
return (currentElement == null) ? null : currentElement.Store;
}
}