MVVM은 잘못 설계된 데이터 바인딩 계층을위한 반창고입니다. 특히 WPF / XAML의 데이터 바인딩 제한으로 인해 WPF / silverlight / WP7 세계에서 많이 사용되었습니다.
이제부터는 WPF / XAML에 대해 이야기하고 있다고 가정하겠습니다. MVVM이 WPF / XAML에서 해결하기 위해 제시 한 몇 가지 단점을 살펴 보겠습니다.
데이터 형태와 UI 형태
MVVM의 'VM'은 C #에 정의 된 개체 집합을 만들어 XAML에 정의 된 프레젠테이션 개체 집합에 매핑합니다. 이러한 C # 개체는 일반적으로 프레젠테이션 개체의 DataContext 속성을 통해 XAML에 연결됩니다.
결과적으로, 뷰 모델 객체 그래프는 애플리케이션의 프리젠 테이션 객체 그래프에 매핑되어야합니다. 즉, 매핑이 일대일이어야한다고 말하지는 않지만 목록 컨트롤이 창 컨트롤에 포함되어 있으면 창의 DataContext 개체에서 해당 목록의 데이터를 설명하는 개체로 가져올 수있는 방법이 있어야합니다.
viewmodel 객체 그래프는 ui 객체 그래프에서 모델 객체 그래프를 성공적으로 분리하지만 추가로 작성하고 유지해야하는 추가 뷰 모델 레이어를 희생합니다.
화면 A에서 화면 B로 일부 데이터를 이동하려면 뷰 모델을 엉망으로 만들어야합니다. 비즈니스 사람을 위해 이것은 UI 변경입니다. 그것은 해야 XAML의 세계에서 순수하게 이루어집니다. 슬프게도, 거의 할 수 없습니다. 더 나쁜 것은 뷰 모델이 구성되는 방식과 데이터가 얼마나 활발하게 변경되는지에 따라이 변경을 수행하기 위해 약간의 데이터 재 라우팅이 필요할 수 있습니다.
표현력이없는 데이터 바인딩 문제 해결
WPF / XAML 바인딩의 표현이 충분하지 않습니다. 기본적으로 개체에 접근 할 수있는 방법, 트래버스 할 속성 경로 및 프레젠테이션 개체에 필요한 데이터 속성 값에 맞게 변환기를 바인딩하는 방법을 제공합니다.
C #의 속성을 그보다 복잡한 것에 바인딩 해야하는 경우 기본적으로 운이 좋지 않습니다. 바인딩 변환기가 없으면 WPF 앱을 본 적이 없습니다.이 변환기는 true / false를 Visible / Collapsed로 바꿨습니다. 많은 WPF 앱은 NegatingVisibilityConverter 또는 이와 유사한 것을 극성을 뒤집는 경향이 있습니다. 알람 벨을 설정해야합니다.
MVVM은이 한계를 극복하는 데 사용할 수있는 C # 코드를 구성하기위한 지침을 제공합니다. 뷰 모델에 SomeButtonVisibility라는 속성을 노출하고 해당 버튼의 가시성에 바인딩하면됩니다. 이제 XAML이 멋지고 예쁘지 만 점원이되었습니다. 이제 UI가 발전 할 때 두 위치 (UI 및 C #의 코드)에 바인딩 바인딩을 노출 + 업데이트해야합니다. 다른 화면에 동일한 버튼이 있어야하는 경우 해당 화면이 액세스 할 수있는 뷰 모델에 유사한 속성을 표시해야합니다. 더 나쁜 것은 XAML을보고 더 이상 버튼이 표시되는 시점을 볼 수 없다는 것입니다. 바인딩이 약간 사소하지 않게 되 자마자 C # 코드에서 형사 연구를해야합니다.
데이터에 대한 접근은 적극적으로 이루어집니다
데이터는 일반적으로 DataContext 속성을 통해 UI에 입력되므로 앱 전체에서 전역 또는 세션 데이터를 일관되게 표현하기가 어렵습니다.
'현재 로그인 한 사용자'라는 아이디어는 훌륭한 예입니다. 이는 종종 앱 인스턴스 내에서 실제로 전 세계에있는 것입니다. WPF / XAML에서는 현재 사용자에게 일관된 방식으로 전역 액세스를 보장하기가 매우 어렵습니다.
내가하고 싶은 것은 데이터 바인딩에서 "CurrentUser"라는 단어를 자유롭게 사용하여 현재 로그인 한 사용자를 참조하는 것입니다. 대신, 모든 DataContext가 현재 사용자 객체에 접근 할 수있는 방법을 제공해야합니다. MVVM은이를 수용 할 수 있지만 뷰 모델은 모두이 글로벌 데이터에 대한 액세스를 제공해야하기 때문에 혼란 스러울 것입니다.
MVVM이 넘어지는 예
사용자 목록이 있다고 가정 해보십시오. 각 사용자 옆에 "사용자 삭제"버튼을 표시하려고하지만 현재 로그인 한 사용자가 관리자 인 경우에만 가능합니다. 또한 사용자는 자신을 삭제할 수 없습니다.
모델 객체는 현재 로그인 한 사용자에 대해 알지 않아야합니다. 데이터베이스에있는 사용자 레코드 만 나타내지 만, 현재 로그인 한 사용자는 목록 행 내의 데이터 바인딩에 노출되어야합니다. MVVM은 현재 로그인 한 사용자를 해당 목록 행으로 표시되는 사용자로 구성하는 각 목록 행에 대해 뷰 모델 객체를 생성 한 다음 해당 느낌에 따라 해당 뷰 모델 객체에 "DeleteButtonVisibility"또는 "CanDelete"라는 속성을 노출해야합니다. 바인딩 변환기에 대해).
이 객체는 대부분의 다른 방법으로 User 객체와 끔찍하게 보일 것입니다. 모든 사용자 모델 객체의 속성을 반영하고 변경 될 때 해당 데이터로 업데이트를 전달해야 할 수도 있습니다. MVVM은 사용자와 유사한 객체를 유지 관리해야하므로 점원이됩니다.
데이터베이스, 모델 및 뷰에서 사용자의 속성을 나타내야 할 수도 있습니다. 데이터베이스와 API 사이에 API가 있으면 데이터베이스, API 서버, API 클라이언트, 모델 및 뷰에 표시됩니다. 속성을 추가하거나 변경할 때마다 터치해야하는 다른 레이어를 추가 한 디자인 패턴을 채택하는 것이 정말 주저합니다.
더 나쁜 것은이 계층은 데이터 모델의 복잡성이 아니라 UI의 복잡성에 따라 확장되는 것입니다. 동일한 데이터가 여러 장소와 UI에 표시되는 경우가 많습니다. 레이어를 추가 할뿐만 아니라 표면 영역이 많은 레이어를 추가합니다.
상황이 어땠 을까
위에서 설명한 경우에 다음과 같이 말하고 싶습니다.
<Button Visibility="{CurrentUser.IsAdmin && CurrentUser.Id != Id}" ... />
CurrentUser는 내 앱의 모든 XAML에 전 세계적으로 노출됩니다. ID는 내 목록 행에 대한 DataContext의 속성을 참조합니다. 가시성은 부울에서 자동으로 변환됩니다. Id, CurrentUser.IsAdmin, CurrentUser 또는 CurrentUser.Id를 업데이트하면이 단추의 가시성에 대한 업데이트가 트리거됩니다. 쉬워요.
대신 WPF / XAML은 사용자가 완전한 혼란을 만들도록합니다. 내가 알 수있는 한, 일부 창조적 인 블로거는 그 엉망에 이름을 쳤고 그 이름은 MVVM이었습니다. 속지 마십시오. GoF 디자인 패턴과 같은 클래스가 아닙니다. 이것은 추악한 데이터 바인딩 시스템을 해결하기위한 추악한 해킹입니다.
(이러한 접근 방식은 더 자세한 정보를 원할 경우 "기능적 반응성 프로그래밍"이라고도합니다.)
결론적으로
WPF / XAML에서 작업해야하더라도 여전히 MVVM을 권장하지 않습니다.
복잡한 데이터 바인딩 표현식 + 유연한 값 강요를 사용하여 코드가보기에 직접 노출 된 모델과 같이 "어떻게 할 수 있었는지"와 같이 구조화되기를 원합니다. 더 읽기 쉽고 쓰기 가능하며 유지 관리가 용이합니다.
MVVM은 코드를 좀 더 간결하고 유지 보수가 덜 쉬운 방식으로 구성하도록 지시합니다.
MVVM 대신 좋은 경험을 근사하는 데 도움이되는 몇 가지 사항을 작성하십시오. UI에 전역 상태를 일관되게 노출시키는 규칙을 개발하십시오. 보다 복잡한 바인딩 표현을 표현할 수있는 바인딩 변환기, 멀티 바인딩 등을 사용하여 툴링을 구축하십시오. 일반적인 강압 사례를 덜 고통스럽게 만들 수 있도록 바인딩 변환기 라이브러리를 구축하십시오.
XAML을보다 표현적인 것으로 대체하십시오. XAML은 C # 개체를 인스턴스화하기위한 매우 간단한 XML 형식으로,보다 표현적인 변형을 만드는 것은 어렵지 않습니다.
내 다른 권장 사항 : 이러한 종류의 타협을 강제하는 툴킷을 사용하지 마십시오. 문제 영역에 초점을 맞추지 않고 MVVM과 같은 크랩으로 밀어서 최종 제품의 품질을 떨어 뜨릴 수 있습니다.