코드를 복제하지 않고 WPF에서 변경할 수 없는 개체를 편집하려면 어떻게 해야 합니까?

StackOverflow https://stackoverflow.com/questions/862209

  •  21-08-2019
  •  | 
  •  

문제

도메인 모델에는 변경할 수 없는 값 개체가 많이 있습니다. 이에 대한 한 가지 예는 위도, 경도 및 높이로 정의되는 위치입니다.

/// <remarks>When I grow up I want to be an F# record.</remarks>
public class Position
{
    public double Latitude
    {
        get;
        private set;
    }

    // snip

    public Position(double latitude, double longitude, double height)
    {
        Latitude = latitude;
        // snip
    }
}

위치 편집을 허용하는 확실한 방법은 getter가 있는 ViewModel을 구축하는 것입니다. 그리고 검증된 불변 위치 인스턴스를 추출하기 위한 Setter 및 ToPosition() 메서드.이 솔루션은 괜찮지만 특히 XAML과 같은 코드가 많이 중복될 수 있습니다.

문제의 값 개체는 일반적으로 X, Y, Z 및 일부 보조 항목의 일부 변형인 3~5개 속성으로 구성됩니다.이를 고려하여 저는 다양한 가능성을 처리하기 위해 세 개의 ViewModel을 생성하는 것을 고려했습니다. 여기서 각 ViewModel은 각 속성의 값에 대한 속성과 각 레이블에 대해 표시할 설명을 노출해야 합니다(예:"위도").

더 나아가 N 속성을 처리하고 리플렉션을 사용하여 모든 것을 연결할 수 있는 하나의 일반 ViewModel로 단순화할 수 있을 것 같습니다.속성 그리드와 비슷하지만 변경할 수 없는 객체에 사용됩니다.속성 그리드의 한 가지 문제는 다음과 같은 레이블과 텍스트 상자를 가질 수 있도록 모양을 변경할 수 있기를 원한다는 것입니다.

Latitude:   [      32 ]  <- TextBox
Longitude:  [     115 ]
Height:     [      12 ]

또는 다음과 같은 DataGrid에 넣습니다.

Latitude  |  Longitude  |  Height
      32           115         12

그래서 내 질문은 다음과 같습니다

이 문제를 해결하는 우아한 방법을 생각해 볼 수 있나요?이 작업을 수행하는 라이브러리나 유사한 내용에 대한 기사가 있나요?

나는 주로 다음을 찾고 있습니다:

  • 코드 중복 최소화
  • 새로운 가치 개체 유형을 쉽게 추가할 수 있음
  • 일종의 검증을 통해 확장 가능
도움이 되었습니까?

해결책

같은 상황에서 가능한 옵션을 연구 하면서이 오래된 질문을 찾았습니다. 다른 사람이 우연히 발견 될 경우를 대비하여 업데이트해야한다고 생각했습니다.

또 다른 옵션 (Paul이 .NET 4가 아직 출시되지 않았기 때문에 솔루션을 제공 할 때 사용할 수 없음)은 동일한 전략을 사용하는 것입니다. .

이 경우 클래스를 정의합니다

class Mutable<ImmutableType> : DynamicObject
{
   //...
}

생성자는 바울의 대답과 마찬가지로 사전에서 새로운 인스턴스를 구성하는 불변의 유형의 인스턴스를 취합니다. 그러나 여기서의 차이점은 TrygetMember와 TrysetMember를 무시하여 결국 생성자-델리 게이트의 인수로 사용할 내부 사전을 채우는 것입니다. 당신이 수락하는 유일한 속성은 실제로 EmpableBeType에서 구현되는 속성인지 확인하기 위해 반사를 사용합니다.

성능 현명하게, 나는 Paul의 대답이 더 빠르며, C# 개발자를 적합하게 만드는 것으로 알려진 역동적 인 물체를 포함하지 않는다고 베팅합니다. 그러나이 솔루션에 대한 구현도 약간 더 간단합니다. 유형 설명자가 약간 비밀 스럽기 때문입니다.


요청 된 개념 증명 / 예제 구현은 다음과 같습니다.

https://bitbucket.org/jwrush/mutable-generic-example

다른 팁

사용자 정의 유형 설명자를 사용하여 이 문제를 해결할 수 있습니다.위치에 바인딩하기 전에 유형 설명자가 시작되어 일시적으로 값을 작성하기 위한 get 및 set 메소드를 제공할 수 있습니다.변경 사항이 커밋되면 불변 객체가 빌드될 수 있습니다.

다음과 같이 보일 수 있습니다.

DataContext = new Mutable(position, 
    dictionary => new Position(dictionary["lattitude"], ...)
);

바인딩은 여전히 ​​다음과 같습니다.

<TextBox Text="{Binding Path=Lattitude}" />

Mutable 객체는 TypeDescriptor 덕분에 Lattitude와 같은 속성을 가진 것처럼 '가장'하기 때문입니다.

또는 바인딩에 변환기를 사용하고 일종의 규칙을 생각해 낼 수도 있습니다.

Mutable 클래스는 현재 불변 객체를 취하고 Func<IDictionary, object> 편집이 완료되면 변경 불가능한 새 객체를 생성할 수 있습니다.Mutable 클래스는 설정 시 새로운 불변 ​​객체를 생성하는 PropertyDescriptor를 생성하는 유형 설명자를 사용합니다.

유형 설명자를 사용하는 방법에 대한 예는 여기를 참조하세요.

http://www.paulstovell.com/editable-object-adapter

편집하다:불변 객체가 생성되는 빈도를 제한하려면 Mutable에서도 구현할 수 있는 BindingGroups 및 IEditableObject를 살펴볼 수도 있습니다.

이 문제를 해결하는 우아한 방법을 생각할 수 있습니까?

솔직히, 당신은 문제를 중심으로 춤을 추지 만 문제 자체를 언급하지 마십시오.).

내가 당신의 문제를 정확하게 추측한다면, 멀티 바인딩과 iMultivalueconverter의 조합이 트릭을 수행해야합니다.

HTH.

PS BTW, 가치 객체가 아닌 불변의 클래스 인스턴스가 있습니다. 값 객체 (다음에 의해 설명됩니다 struct 키워드) 셋터가 있든 없든 :).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top