요소 만들기 및 이동 사용자 지정
도구 상자에서 또는 붙여넣기 또는 이동 작업에서 요소를 다른 요소에 끌어 놓도록 허용할 수 있습니다. 지정한 관계를 사용하여 이동된 요소를 대상 요소에 연결할 수 있습니다.
EMD(요소 병합 지시문)는 한 모델 요소를 다른 모델 요소에 병합할 때 무엇이 발생하는지 지정합니다. 이 문제는 다음과 같은 경우에 발생합니다.
사용자가 도구 상자에서 다이어그램 또는 도형으로 끌어 놓습니다.
사용자가 탐색기의 추가 메뉴 또는 구획 도형을 사용하여 요소를 만듭니다.
사용자가 스윔 레인에서 다른 스윔 레인으로 항목을 이동합니다.
사용자가 요소를 붙여넣습니다.
프로그램 코드가 요소 병합 지시문을 호출합니다.
만들기 작업은 복사 작업과 달라 보일지 모르지만 실제로 작동 방식은 동일합니다. 예를 들어 도구 상자에서 요소를 추가하면 해당 요소의 프로토타입이 복제됩니다. 프로토타입은 모델의 다른 부분에서 복사된 요소와 동일한 방식으로 모델에 병합됩니다.
EMD가 할 일은 개체 또는 개체의 그룹을 모델의 특정 위치에 병합하는 방법을 결정하는 것입니다. 특히 병합된 그룹을 모델에 연결하기 위해 인스턴스화해야 하는 관계를 결정합니다. 속성을 설정하고 추가 개체를 만들도록 사용자 지정할 수도 있습니다.
EMD는 포함 관계를 정의할 때 자동으로 생성됩니다. 이 기본 EMD는 사용자가 새 자식 인스턴스를 부모에 추가할 때 관계의 인스턴스를 만듭니다. 예를 들어 사용자 지정 코드를 추가하여 이러한 기본 EMD를 수정할 수 있습니다.
DSL 정의에 자체 EMD를 추가하여 사용자들이 병합된 클래스와 받는 클래스의 다양한 조합을 끌거나 붙여넣도록 할 수도 있습니다.
요소 병합 지시문 정의
도메인 클래스, 도메인 관계, 도형, 연결선 및 다이어그램에 요소 병합 지시문을 추가할 수 있습니다. DSL 탐색기의 받는 도메인 클래스에서 요소 병합 지시문을 추가하거나 찾을 수 있습니다. 받는 클래스는 모델에 이미 있고, 새 요소나 복사된 요소가 병합될 요소의 도메인 클래스입니다.
인덱싱 클래스는 받는 클래스의 멤버에 병합할 수 있는 요소의 도메인 클래스입니다. 하위 클래스에 적용을 False로 설정하지 않으면 인덱싱 클래스의 하위 클래스 인스턴스도 이 EMD에 의해 병합됩니다.
병합 지시문에는 두 가지 종류가 있습니다.
프로세스 병합 지시문은 새 요소를 트리에 연결해야 하는 관계를 지정합니다.
정방향 병합 지시문은 새 요소를 다른 수신 요소(일반적으로 부모)로 리디렉션합니다.
병합 지시문에 사용자 지정 코드를 추가할 수 있습니다.
사용자 지정 허용 사용을 설정하여 자체 코드를 추가하면 인덱싱 요소의 특정 인스턴스를 대상 요소에 병합해야 하는지 여부를 결정할 수 있습니다. 사용자가 도구 상자에서 끌 때 코드가 병합을 허용하지 않는 경우 "잘못된" 포인터가 표시됩니다.
예를 들어 받는 요소가 특정 상태일 때만 병합을 허용할 수 있습니다.
사용자 지정 병합 사용을 설정하여 병합이 수행될 때 모델 변경 내용을 정의하는 자체 코드를 추가합니다.
예를 들어 모델의 새 데이터 위치에서 데이터를 사용하여 병합된 요소의 속성을 설정할 수 있습니다.
참고 항목
사용자 지정 병합 코드를 작성하는 경우 이 EMD를 사용하여 수행되는 병합에만 영향을 미칩니다. 동일한 형식의 개체를 병합하는 다른 EMD가 있거나 EMD를 사용하지 않고 이러한 개체를 만드는 다른 사용자 지정 코드가 있는 경우 사용자 지정 병합 코드의 영향을 받지 않습니다.
새 요소 또는 새 관계가 항상 사용자 지정 코드에서 처리되도록 하려면 포함 관계에서 AddRule
을 정의하고 요소의 도메인 클래스에 DeleteRule
을 정의하는 것이 좋습니다. 자세한 내용은 규칙으로 모델 내에서 변경 내용 전파를 참조하세요.
예: 사용자 지정 코드 없이 EMD 정의
다음 예에서는 도구 상자에서 기존 도형으로 끌어 요소와 연결선을 동시에 만들 수 있습니다. 이 예는 DSL 정의에 EMD를 추가합니다. 이 수정 전에 사용자는 도구를 다이어그램으로 끌어다 놓을 수 있지만 기존 도형으로 끌어다 놓을 수는 없습니다.
사용자는 요소를 다른 요소에 붙여넣을 수도 있습니다.
사용자가 요소와 연결선을 동시에 만들 수 있도록 하려면
최소 언어 솔루션 템플릿을 사용하여 새 DSL을 만듭니다.
이 DSL을 실행하면 도형 간에 도형과 연결선을 만들 수 있습니다. 도구 상자에서 기존 도형으로 새 ExampleElement 도형을 끌어올 수 없습니다.
사용자가 요소를
ExampleElement
도형에 병합할 수 있도록 하려면ExampleElement
도메인 클래스에 새 EMD를 만듭니다.DSL 탐색기에서 도메인 클래스를 확장합니다.
ExampleElement
를 마우스 오른쪽 단추로 클릭한 다음 새 요소 병합 지시문 추가를 클릭합니다.새 EMD의 세부 정보를 볼 수 있도록 DSL 정보 창이 열려 있는지 확인합니다. (메뉴: 보기, 다른 창, DSL 세부 정보.)
DSL 정보 창에서 인덱싱 클래스를 설정하여
ExampleElement
개체에 병합할 수 있는 요소의 클래스를 정의합니다.이 예에서는 사용자가 새 요소를 기존 요소로 끌 수 있도록
ExampleElements
를 선택합니다.인덱싱 클래스가 DSL 탐색기에서 EMD의 이름이 됩니다.
링크를 만들어 병합 처리에서 다음 두 개의 경로를 추가합니다.
한 경로는 새 요소를 부모 모델에 연결합니다. 입력해야 하는 경로 식은 기존 요소에서 포함 관계를 거쳐 부모 모델까지 이동합니다. 마지막으로 새 요소가 할당될 새 링크의 역할을 지정합니다. 경로는 다음과 같습니다.
ExampleModelHasElements.ExampleModel/!ExampleModel/.Elements
다른 경로는 새 요소를 기존 요소에 연결합니다. 경로 식은 참조 관계 및 새 요소가 할당될 역할을 지정합니다. 이 경로는 다음과 같습니다.
ExampleElementReferencesTargets.Sources
경로 탐색 도구를 사용하여 각 경로를 만들 수 있습니다.
경로에 링크를 만들어 병합 처리에서 <경로 추가>를 클릭합니다.
목록 항목의 오른쪽에 있는 드롭다운 화살표를 클릭합니다. 트리 뷰가 나타납니다.
트리의 노드를 확장하여 지정하려는 경로를 구성합니다.
DSL 테스트:
F5 키를 눌러 솔루션을 다시 빌드하고 실행합니다.
생성된 코드가 새 DSL 정의를 준수하도록 텍스트 템플릿에서 업데이트되기 때문에 다시 빌드하려면 평소보다 오래 걸릴 수 있습니다.
Visual Studio의 실험적 인스턴스가 시작되면 DSL의 모델 파일을 엽니다. 몇 가지 예시 요소를 만듭니다.
예시 요소 도구에서 기존 도형으로 끌어 놓습니다.
새 도형이 나타나고 연결선으로 기존 도형에 연결됩니다.
기존 도형을 복사합니다. 다른 도형을 선택하고 붙여넣습니다.
첫 번째 도형의 복사본이 만들어집니다. 이 복사본은 새 이름이 있으며, 연결선으로 두 번째 도형에 연결됩니다.
이 절차에서 다음 사항에 유의하세요.
요소 병합 지시문을 만들면 요소의 모든 클래스가 다른 클래스를 허용하도록 할 수 있습니다. EMD는 받는 도메인 클래스에서 만들어지며, 허용되는 도메인 클래스는 인덱스 클래스 필드에서 지정됩니다.
경로를 정의하여 새 요소를 기존 모델에 연결하는 데 사용해야 하는 링크를 지정할 수 있습니다.
지정한 링크에는 하나의 포함 관계가 포함되어야 합니다.
EMD는 도구 상자에서의 만들기 작업과 붙여넣기 작업 모두에 영향을 미칩니다.
새 요소를 만드는 사용자 지정 코드를 작성하는 경우
ElementOperations.Merge
메서드를 사용하여 EMD를 명시적으로 호출할 수 있습니다. 이렇게 하면 코드가 다른 작업과 동일한 방식으로 새 요소를 모델에 연결합니다. 자세한 내용은 복사 동작 사용자 지정을 참조하세요.
예: EMD에 사용자 지정 허용 코드 추가
EMD에 사용자 지정 코드를 추가하여 더 복잡한 병합 동작을 정의할 수 있습니다. 이 간단한 예에서는 사용자가 고정된 개수 이상의 요소를 다이어그램에 추가할 수 없습니다. 이 예는 포함 관계에 동반하는 기본 EMD를 수정합니다.
사용자가 추가할 수 있는 내용을 제한하는 사용자 지정 수락 코드를 작성하려면
최소 언어 솔루션 템플릿을 사용하여 DSL을 만듭니다. DSL 정의 다이어그램을 엽니다.
DSL 탐색기에서 도메인 클래스,
ExampleModel
, 요소 병합 지시문을 확장합니다. 이름이ExampleElement
인 요소 병합 지시문을 선택합니다.이 EMD는 사용자가 모델에서 새
ExampleElement
개체를 만드는 방법(예: 도구 상자에서 끌어서)을 제어합니다.DSL 정보 창에서 사용자 지정 허용 사용을 선택합니다.
솔루션을 다시 빌드합니다. 생성된 코드가 모델에서 업데이트되기 때문에 평소보다 오래 걸릴 수 있습니다.
"Company.ElementMergeSample.ExampleElement does not contain a definition for CanMergeExampleElement..."와 비슷한 빌드 오류가 보고됩니다.
CanMergeExampleElement
메서드를 구현해야 합니다.Dsl 프로젝트에 새 코드 파일을 만듭니다. 내용을 다음 코드로 바꾸고 네임스페이스를 프로젝트의 네임스페이스로 변경합니다.
using Microsoft.VisualStudio.Modeling; namespace Company.ElementMergeSample // EDIT. { partial class ExampleModel { /// <summary> /// Called whenever an ExampleElement is to be merged into this ExampleModel. /// This happens when the user pastes an ExampleElement /// or drags from the toolbox. /// Determines whether the merge is allowed. /// </summary> /// <param name="rootElement">The root element in the merging EGP.</param> /// <param name="elementGroupPrototype">The EGP that the user wants to merge.</param> /// <returns>True if the merge is allowed</returns> private bool CanMergeExampleElement(ProtoElementBase rootElement, ElementGroupPrototype elementGroupPrototype) { // Allow no more than 4 elements to be added: return this.Elements.Count < 4; } } }
이 간단한 예는 부모 모델에 병합할 수 있는 요소 수를 제한합니다. 조건을 더 흥미롭게 만들기 위해 받는 개체의 속성과 링크를 메서드가 검사할 수 있습니다. 메서드는 병합 요소의 속성도 검사할 수 있습니다. 이는 ElementGroupPrototype에서 수행됩니다.
ElementGroupPrototypes
에 대한 자세한 내용은 복사 동작 사용자 지정을 참조하세요. 모델을 읽는 코드를 작성하는 방법에 대한 자세한 내용은 프로그램 코드에서 모델 탐색 및 업데이트를 참조하세요.DSL 테스트:
F5 키를 눌러 솔루션을 다시 빌드합니다. Visual Studio의 실험적 인스턴스가 열리면 DSL의 인스턴스를 엽니다.
여러 가지 방법으로 새 요소를 만듭니다.
예시 요소 도구에서 다이어그램으로 끌어 놓습니다.
예시 모델 탐색기에서 루트 노드를 마우스 오른쪽 단추로 클릭한 다음 새 예시 요소 추가를 클릭합니다.
요소를 복사하여 다이어그램에 붙여넣습니다.
이 중 어떤 방법을 사용해도 모델에 5개 이상의 요소를 추가할 수 없는 것을 확인합니다. 모두가 요소 병합 지시문을 사용하기 때문입니다.
예: EMD에 사용자 지정 병합 코드 추가
사용자 지정 병합 코드에서 사용자가 도구를 끌거나 요소에 붙여넣을 때 무슨 일이 일어나는지 정의할 수 있습니다. 사용자 지정 병합을 정의하는 두 가지 방법이 있습니다.
사용자 지정 병합 사용을 설정하고 필요한 코드를 지정합니다. 생성된 병합 코드를 코드가 대체합니다. 병합이 수행하는 작업을 완전히 다시 정의하려면 이 옵션을 사용합니다.
MergeRelate
메서드를 재정의하고, 필요에 따라MergeDisconnect
메서드를 재정의합니다. 이렇게 하려면 도메인 클래스의 Generates Double Derived 속성을 설정해야 합니다. 코드는 기본 클래스에서 생성된 병합 코드를 호출할 수 있습니다. 병합이 수행된 후 추가 작업을 수행하려면 이 옵션을 사용하세요.이러한 방법은 이 EMD를 사용하여 수행되는 병합에만 영향을 미칩니다. 병합된 요소를 만들 수 있는 모든 방법에 영향을 주려면 포함 관계에서
AddRule
을 정의하고 병합된 도메인 클래스에서DeleteRule
을 정의할 수도 있습니다. 자세한 내용은 규칙으로 모델 내에서 변경 내용 전파를 참조하세요.
MergeRelate를 재정의하려면
DSL 정의에서 코드를 추가할 EMD를 정의했는지 확인합니다. 원하는 경우 이전 섹션에서 설명한 대로 경로를 추가하고 사용자 지정 허용 코드를 정의할 수 있습니다.
DslDefinition 다이어그램에서 병합의 받는 클래스를 선택합니다. 일반적으로 포함 관계의 소스 끝에 있는 클래스입니다.
예를 들어 최소 언어 솔루션에서 생성된 DSL에서
ExampleModel
을 선택합니다.속성 창에서 Generates Double Derived를 true로 설정합니다.
솔루션을 다시 빌드합니다.
Dsl\Generated Files\DomainClasses.cs의 내용을 검사합니다. 이름이
MergeRelate
인 메서드를 검색하고 해당 내용을 검사합니다. 그러면 자체 버전을 작성하는 데 도움이 됩니다.새 코드 파일에서 받는 클래스에 대한 partial 클래스를 작성하고
MergeRelate
메서드를 재정의합니다. 기본 메서드를 호출해야 합니다. 예시:partial class ExampleModel { /// <summary> /// Called when the user drags or pastes an ExampleElement onto the diagram. /// Sets the time of day as the name. /// </summary> /// <param name="sourceElement">Element to be added</param> /// <param name="elementGroup">Elements to be merged</param> protected override void MergeRelate(ModelElement sourceElement, ElementGroup elementGroup) { // Connect the element according to the EMD: base.MergeRelate(sourceElement, elementGroup); // Custom actions: ExampleElement mergingElement = sourceElement as ExampleElement; if (mergingElement != null) { mergingElement.Name = DateTime.Now.ToLongTimeString(); } } }
사용자 지정 병합 코드를 작성하려면
Dsl\Generated Code\DomainClasses.cs에서 이름이
MergeRelate
인 메서드를 검사합니다. 이러한 메서드는 새 요소와 기존 모델 간에 링크를 만듭니다.이름이
MergeDisconnect
인 메서드도 검사합니다. 이러한 메서드는 삭제될 모델에서 요소의 연결을 해제합니다.DSL 탐색기에서 사용자 지정할 요소 병합 지시문을 선택하거나 만듭니다. DSL 정보 창에서 사용자 지정 병합 사용을 선택합니다.
이 옵션을 설정하면 병합 처리 및 정방향 병합 옵션이 무시됩니다. 코드가 대신 사용됩니다.
솔루션을 다시 빌드합니다. 생성된 코드 파일이 모델에서 업데이트되기 때문에 평소보다 오래 걸릴 수 있습니다.
오류 메시지가 표시됩니다. 생성된 코드의 지침을 보려면 오류 메시지를 두 번 클릭합니다. 이 지침에서는
MergeRelate
YourDomainClass 및MergeDisconnect
YourDomainClass라는 두 가지 메서드를 제공하라는 메시지가 표시됩니다.partial 클래스 정의의 메서드를 별도의 코드 파일에 씁니다. 앞서 검사한 예에서 무엇이 필요한지 제안되어야 합니다.
사용자 지정 병합 코드는 개체와 관계를 직접 만드는 코드에 영향을 미치지 않으며, 다른 EMD에도 영향을 미치지 않습니다. 요소를 만드는 방법에 관계없이 추가 변경 내용이 구현되도록 하려면 대신
AddRule
및DeleteRule
을 작성하는 것이 좋습니다. 자세한 내용은 규칙으로 모델 내에서 변경 내용 전파를 참조하세요.
병합 작업 리디렉션
정방향 병합 지시문은 병합 작업의 대상을 리디렉션합니다. 일반적으로 새 대상은 초기 대상의 포함 부모입니다.
예를 들어 구성 요소 다이어그램 템플릿으로 만든 DSL에서 포트는 구성 요소에 포함됩니다. 포트는 구성 요소 도형의 가장자리에 작은 도형으로 표시됩니다. 사용자는 포트 도구를 구성 요소 도형으로 끌어 놓아 포트를 만듭니다. 하지만 경우에 따라 사용자가 실수로 포트 도구를 구성 요소 대신 기존 포트로 끌어 놓으면 작업이 실패합니다. 기존 포트가 여러 개 있는 경우 범하기 쉬운 실수입니다. 사용자에게 이러한 문제가 발생하지 않도록 하기 위해 포트를 기존 포트로 끌어 놓는 것을 허용하되 작업이 부모 구성 요소로 리디렉션되도록 할 수 있습니다. 작업은 대상 요소가 구성 요소인 것처럼 작동합니다.
구성 요소 모델 솔루션에서 정방향 병합 지시문을 만들 수 있습니다. 원래 솔루션을 컴파일하고 실행하는 경우 사용자가 도구 상자에서 구성 요소 요소로 원하는 수의 입력 포트 또는 출력 포트 요소를 끌어 놓을 수 있음을 알 수 있습니다. 하지만 사용자가 포트를 기존 포트로 끌어 놓을 수는 없습니다. 사용할 수 없음 포인터는 이 이동을 사용할 수 없음을 사용자에게 경고합니다. 하지만 기존 입력 포트에서 의도치 않게 삭제되는 포트가 구성 요소 요소로 전달되도록 정방향 병합 지시문을 만들 수 있습니다.
정방향 병합 지시문을 만들려면
구성 요소 모델 템플릿을 사용하여 도메인 특정 언어 도구 솔루션을 만듭니다.
DslDefinition.dsl을 열어 DSL 탐색기를 표시합니다.
DSL 탐색기에서 도메인 클래스를 확장합니다.
ComponentPort 추상 도메인 클래스는 InPort 및 OutPort의 기본 클래스입니다. ComponentPort를 마우스 오른쪽 단추로 클릭한 다음 새 요소 병합 지시문 추가를 클릭합니다.
새 요소 병합 지시문 노드가 요소 병합 지시문 노드 아래에 나타납니다.
요소 병합 지시문 노드를 선택하고 DSL 정보 창을 엽니다.
인덱싱 클래스 목록에서 ComponentPort를 선택합니다.
다른 도메인 클래스에 병합 전달을 선택합니다.
경로 선택 목록에서 ComponentPort를 확장하고 ComponentHasPorts를 확장한 다음 구성 요소를 선택합니다.
새 경로는 다음과 비슷합니다.
ComponentHasPorts.Component/!Component
솔루션을 저장한 다음 솔루션 탐색기 도구 모음에서 가장 오른쪽 단추를 클릭하여 템플릿을 변환합니다.
솔루션을 빌드하고 실행합니다. 새 Visual Studio 인스턴스가 표시됩니다.
솔루션 탐색기에서 Sample.mydsl을 엽니다. 다이어그램과 ComponentLanguage 도구 상자가 나타납니다.
입력 포트를 도구 상자에서 다른 입력 포트로 끌어옵니다. 그런 다음 출력 포트를 입력 포트로 끌어다 놓은 다음 다른 출력 포트로 끌어옵니다.
사용할 수 없음 포인터가 표시되지 않아야 하며, 기존 입력 포트에서 새 입력 포트를 삭제할 수 있어야 합니다. 새 입력 포트를 선택하고 구성 요소의 다른 지점으로 끌어 놓습니다.