MVVM 템플릿의 좋은 예


141

현재 Microsoft MVVM 템플릿으로 작업하고 있으며 자세한 예제가 부족하다는 것을 알았습니다. 포함 된 ContactBook 예제는 매우 적은 Command 처리를 보여 주며 내가 찾은 다른 예제는 개념은 비슷하지만 약간 다른 접근법을 사용하지만 여전히 복잡성이 부족한 MSDN Magazine 기사에서 얻은 것입니다. 최소한 기본 CRUD 작업과 대화 상자 / 콘텐츠 전환을 보여주는 괜찮은 MVVM 예가 있습니까?


모든 사람의 제안이 정말 유용했으며 좋은 자료 목록을 작성하기 시작합니다.

프레임 워크 / 템플릿

유용한 기사

스크린 캐스트

추가 라이브러리


이 자료가 도움이 되었기 때문에 기쁩니다. 저는 현재 두 번째 프로덕션 MVVM 응용 프로그램을 사용 중이며 처음 시작할 때 도움이 될 내용을 계속 추가 할 예정입니다.
jwarzech

답변:


59

불행히도 모든 것을 수행하는 훌륭한 MVVM 예제 앱은 없으며 작업을 수행하는 다양한 방법이 있습니다. 첫째, 의존성 주입, 명령, 이벤트 집계 등과 같은 편리한 도구를 제공하여 자신에게 적합한 다양한 패턴을 쉽게 시도 할 수 있기 때문에 앱 프레임 워크 중 하나에 익숙해지고 싶을 수도 있습니다 (Prism은 적절한 선택입니다). .

프리즘 릴리즈 :
http://www.codeplex.com/CompositeWPF

꽤 작은 예제 앱 (주식 거래자)과 많은 작은 예제 및 방법이 포함되어 있습니다. 최소한 사람들이 MVVM을 실제로 작동시키는 데 사용하는 몇 가지 일반적인 하위 패턴에 대한 좋은 데모입니다. CRUD와 대화 상자에 대한 예가 있다고 생각합니다.

프리즘이 모든 프로젝트에 반드시 필요한 것은 아니지만 친숙해지는 것이 좋습니다.

CRUD : 이 부분은 매우 쉽습니다. WPF 양방향 바인딩을 사용하면 대부분의 데이터를 정말 쉽게 편집 할 수 있습니다. 실제 트릭은 UI를 쉽게 설정할 수있는 모델을 제공하는 것입니다. 최소한 ViewModel (또는 비즈니스 객체)이 INotifyPropertyChanged바인딩을 지원하도록 구현 하고 속성을 UI 컨트롤에 직접 바인딩 할 수 있지만 IDataErrorInfo유효성 검사 를 위해 구현할 수도 있습니다 . 일반적으로 일종의 ORM 솔루션을 사용하면 CRUD를 설정하는 것이 간단합니다.

이 기사는 간단한 crud 작업을 보여줍니다 : http://dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx

LinqToSql을 기반으로하지만 예제와 관련이 없습니다. 중요한 것은 비즈니스 오브젝트가 구현하는 것입니다 INotifyPropertyChanged(LinqToSql에 의해 생성 된 클래스가 수행함). MVVM은 그 예의 요점이 아니지만이 경우에는 중요하지 않다고 생각합니다.

이 문서에서는 데이터 유효성 검사를 보여줍니다.
http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx

또한 대부분의 ORM 솔루션은 이미 구현 한 클래스를 생성 IDataErrorInfo하며 일반적으로 사용자 지정 유효성 검사 규칙을 쉽게 추가 할 수있는 메커니즘을 제공합니다.

대부분의 경우 ORM이 생성 한 객체 (모델)를 가져 와서 저장 / 삭제 명령이있는 ViewModel에 래핑하여 UI를 모델 속성에 바로 바인딩 할 수 있습니다.

뷰는 다음과 같습니다 (ViewModel에는 ItemORM에서 작성된 클래스와 같이 모델을 보유 하는 특성이 있음).

<StackPanel>
   <StackPanel DataContext=Item>
      <TextBox Text="{Binding FirstName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
      <TextBox Text="{Binding LastName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
   </StackPanel>
   <Button Command="{Binding SaveCommand}" />
   <Button Command="{Binding CancelCommand}" />
</StackPanel>

대화 상자 : 대화 상자와 MVVM은 약간 까다 롭습니다. 대화 상자와 함께 다양한 Mediator 접근 방식을 사용하는 것을 선호합니다.이 StackOverflow 질문에서 조금 더 자세히 읽을 수 있습니다
.WPF MVVM 대화 상자 예제

꽤 고전적인 MVVM이 아닌 일반적인 방법은 다음과 같이 요약 할 수 있습니다.

커밋 및 취소 작업에 대한 명령을 표시하는 대화 상자 ViewModel의 기본 클래스, 대화 상자를 닫을 준비가되었음을 뷰에 알리는 이벤트 및 모든 대화 상자에 필요한 모든 항목.

대화 상자의 일반보기-창 또는 사용자 정의 "모달"오버레이 유형 제어 일 수 있습니다. 핵심은 뷰 모델을 덤프하는 컨텐츠 발표자이며 창을 닫기 위해 배선을 처리합니다. 예를 들어 데이터 컨텍스트 변경에 따라 새 ViewModel이 기본 클래스에서 상속되는지 여부와 관련 close 이벤트를 구독합니다 (핸들러가 대화 상자 결과를 할당합니다). 대체 범용 닫기 기능 (예 : X 버튼)을 제공하는 경우 ViewModel에서도 관련 닫기 명령을 실행해야합니다.

ViewModel에 데이터 템플릿을 제공해야하는 곳에서는 특히 별도의 컨트롤에 캡슐화 된 각 대화 상자에 대한보기가 있으므로 매우 간단 할 수 있습니다. ViewModel의 기본 데이터 템플릿은 다음과 같습니다.

<DataTemplate DataType="{x:Type vmodels:AddressEditViewModel}">
   <views:AddressEditView DataContext="{Binding}" />
</DataTemplate>

대화 상자보기는 이것에 액세스 할 수 있어야합니다. 그렇지 않으면 공유 대화 상자 UI를 제외하고 ViewModel을 표시하는 방법을 알 수 없으므로 내용은 기본적으로 다음과 같습니다.

<ContentControl Content="{Binding}" />

암시 적 데이터 템플릿은 뷰를 모델에 매핑하지만 누가 시작합니까?

이것은 vmvm이 아닌 부분입니다. 이를 수행하는 한 가지 방법은 글로벌 이벤트를 사용하는 것입니다. 내가 생각하기에 더 좋은 방법은 의존성 주입을 통해 제공된 이벤트 애그리 게이터 유형 설정을 사용하는 것입니다.이 방법으로 이벤트가 전체 앱이 아닌 컨테이너에 전역 적입니다. 프리즘은 컨테이너 의미론과 의존성 주입을 위해 유니티 프레임 워크를 사용하며 전반적으로 Unity를 좋아합니다.

일반적으로 루트 창이이 이벤트를 구독하는 것이 좋습니다. 대화 상자를 열고 데이터 컨텍스트를 발생한 이벤트와 함께 전달되는 ViewModel로 설정할 수 있습니다.

이러한 방식으로이를 설정하면 ViewModels는 애플리케이션에 UI를 전혀 몰라도 대화 상자를 열고 사용자 조치에 응답하도록 요청하므로 대부분 MVVM이 완성 된 상태로 유지됩니다.

그러나 UI가 대화 상자를 띄워야하는 경우가 있기 때문에 조금 까다로울 수 있습니다. 예를 들어, 대화 상자 위치가 대화 상자를 여는 버튼의 위치에 의존하는 경우를 고려하십시오. 이 경우 대화 상자를 열 때 UI 특정 정보가 필요합니다. 일반적으로 ViewModel과 관련 UI 정보를 보유하는 별도의 클래스를 만듭니다. 불행히도 일부 커플 링은 피할 수없는 것처럼 보입니다.

요소 위치 데이터가 필요한 대화 상자를 발생시키는 버튼 핸들러의 의사 코드 :

ButtonClickHandler(sender, args){
    var vm = DataContext as ISomeDialogProvider; // check for null
    var ui_vm = new ViewModelContainer();
    // assign margin, width, or anything else that your custom dialog might require
    ...
    ui_vm.ViewModel = vm.SomeDialogViewModel; // or .GetSomeDialogViewModel()
    // raise the dialog show event
}

대화 상자 뷰는 위치 데이터에 바인딩하고 포함 된 ViewModel을 inner에 전달합니다 ContentControl. ViewModel 자체는 여전히 UI에 대해 아무것도 모릅니다.

일반적으로 메서드 의 DialogResultreturn 속성을 사용하지 않거나 ShowDialog()대화 상자가 닫힐 때까지 스레드가 차단 될 것으로 예상합니다. 비표준 모달 대화 상자가 항상 그런 식으로 작동하는 것은 아니며 복합 환경에서는 실제로 이벤트 핸들러가 그런 식으로 차단하는 것을 원하지 않습니다. ViewModels 가이를 처리하도록하고 싶습니다 .ViewModel의 작성자는 관련 이벤트를 구독하고 커밋 / 취소 메소드를 설정할 수 있으므로이 UI 메커니즘에 의존 할 필요가 없습니다.

따라서이 흐름 대신 :

// in code behind
var result = somedialog.ShowDialog();
if (result == ...

나는 사용한다:

// in view model
var vm = new SomeDialogViewModel(); // child view model
vm.CommitAction = delegate { this.DoSomething(vm); } // what happens on commit 
vm.CancelAction = delegate { this.DoNothing(vm); } // what happens on cancel/close (optional)
// raise dialog request event on the container

대부분의 대화 상자가 비 차단 의사 모달 컨트롤이기 때문에이 방법을 선호하며이 방법을 사용하는 것이 문제를 해결하는 것보다 훨씬 간단 해 보입니다. 단위 테스트도 쉽습니다.


자세한 답변 주셔서 감사합니다! 최근에 가장 큰 문제는 MainViewModel이 다른 뷰 모델과 통신하여 응용 프로그램의 흐름을 처리해야 할 때입니다. 그러나 MVVM + 중재자가 널리 사용되는 것으로 보입니다.
jwarzech 2016

2
중개자는 이벤트 어 그리 게이터 패턴 (Prism의 구현이 우수함)이 확실히 도움이되며, 낮은 커플 링이 목표 일 때 매우 유용합니다. 또한 기본 뷰 모델에는 일반적으로 자체 뷰 모델이 있으며 통신하는 데 문제가 없어야합니다. 자식 뷰 모델이 앱에서 다른 모듈과 상호 작용해야하는 경우에는 UI를 포함하여 중재자 또는 이벤트 집계자를 사용해야합니다.
Egor

1
대화 상자 및 창 작업에 대한 지침이 실제로 도움이되었습니다. 그러나 몇 가지 문제가 있습니다. 1.보기에서 창 제목을 어떻게 설정합니까? 2. 소유자 창 설정을 어떻게 처리합니까?
djskinner

@ 다니엘 스키너 : 나는 당신이 대화에 대해 이야기하고 있다고 가정하고, 내가 틀렸다면 나를 바로 잡으십시오. 대화 제목은 다른 속성 일 뿐이며 원하는대로 바인딩 할 수 있습니다. 기본 대화 상자 viewmodel 클래스를 사용하여 내 접근 방식을 따르는 경우 (제목 속성이 있다고 가정하십시오) 모든 일반 대화 상자 창에서 UI 대 UI 바인딩을 사용하여 제목을 {Binding Path = DataContext.Title, ElementName = NameOfContentPresenter}. 소유자 창은 약간 까다 롭습니다. 즉, 실제로 대화 상자를 표시하는 중재자가 루트 앱보기에 대해 알아야합니다.
Egor

실제로 대화 상자를 실제로 표시하는 사람은 루트 앱 창 /보기에 대한 참조가 필요합니다. "일반적으로 루트 창에서이 이벤트를 구독하는 것이 좋습니다. 대화 상자를 열고 데이터 컨텍스트를 발생한 이벤트와 함께 전달되는 뷰 모델로 설정할 수 있습니다." 여기에서 소유자를 설정할 수 있습니다.
Egor

6

Jason Dolinger는 MVVM 의 훌륭한 스크린 캐스트 를 만들었습니다 . Egor가 언급 한 것처럼 좋은 예는 없습니다. 그들은 끝났습니다. 대부분 MVVM의 좋은 예이지만 복잡한 문제가 발생했을 때는 그렇지 않습니다. 누구나 자신의 길을 가지고 있습니다. Laurent Bugnion은 뷰 모델 간에도 통신 할 수있는 좋은 방법입니다. http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx Cinch도 좋은 예입니다. Paul Stovel은 자신의 Magellan 프레임 워크로 많은 것을 설명 하는 좋은 게시물 을 가지고 있습니다.


3

Caliburn을 보셨습니까 ? ContactManager 샘플에는 좋은 점이 많이 있습니다. 일반 WPF 샘플은 명령에 대한 개요도 제공합니다. 문서가 상당히 좋고 포럼이 활발합니다. 추천!





2

나는 또한 당신의 좌절감을 공유했습니다. 응용 프로그램을 작성 중이며 다음 3 가지 요구 사항이 있습니다.

  • 확장 가능
  • MVVM이 포함 된 WPF
  • GPL 호환 예

내가 찾은 것은 단지 조각과 조각 이었기 때문에 방금 최선을 다하기 시작했습니다. 약간의 정보를 얻은 후에는 참조 응용 프로그램을 사용할 수있는 다른 사람 (자신과 같은)이있을 수 있다는 사실을 깨달았으므로 일반적인 내용을 WPF / MVVM 응용 프로그램 프레임 워크로 리팩터링하여 LGPL로 배포했습니다. 나는 그것을 SoapBox Core 라고 명명했다 . 다운로드 페이지로 이동하면 작은 데모 응용 프로그램과 함께 제공되며 해당 데모 응용 프로그램의 소스 코드도 다운로드 할 수 있습니다. 도움이 되길 바랍니다. 또한 더 많은 정보를 원하시면 scott {at} soapboxautomation.com으로 이메일을 보내주십시오.

편집 : 또한 작동 방법을 설명하는 CodeProject 기사를 게시 했습니다.


2

코드 프로젝트에서 처음부터 간단한 MVVM 예제를 작성했습니다. 여기에는 단계별 MVVM WPF 링크가 있습니다. 간단한 3 레이어 아키텍처에서 시작하여 PRISM과 같은 프레임 워크를 사용하도록 졸업합니다.

여기에 이미지 설명을 입력하십시오


1

심지어 문제를 내 손에들 때까지 좌절감을 나누었습니다. IncEditor를 시작했습니다.

IncEditor ( http://inceditor.codeplex.com )는 개발자에게 WPF, MVVM 및 MEF를 소개하는 편집기입니다. 나는 그것을 시작하고 '테마'지원과 같은 기능을 얻었습니다. WPF, MVVM 또는 MEF 전문가가 아니기 때문에 많은 기능을 사용할 수 없습니다. 나는 당신과 같은 진지한 요청을하면 나 같은 귀찮은 사람들이 더 잘 이해할 수 있도록 그것을 더 좋게 만들어야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.