코드를 복제하지 않고 WPF에서 변경할 수 없는 개체를 편집하려면 어떻게 해야 합니까?
-
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# 개발자를 적합하게 만드는 것으로 알려진 역동적 인 물체를 포함하지 않는다고 베팅합니다. 그러나이 솔루션에 대한 구현도 약간 더 간단합니다. 유형 설명자가 약간 비밀 스럽기 때문입니다.
요청 된 개념 증명 / 예제 구현은 다음과 같습니다.
다른 팁
사용자 정의 유형 설명자를 사용하여 이 문제를 해결할 수 있습니다.위치에 바인딩하기 전에 유형 설명자가 시작되어 일시적으로 값을 작성하기 위한 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
키워드) 셋터가 있든 없든 :).