불행히도 모든 것을 수행하는 훌륭한 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에는 Item
ORM에서 작성된 클래스와 같이 모델을 보유 하는 특성이 있음).
<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에 대해 아무것도 모릅니다.
일반적으로 메서드 의 DialogResult
return 속성을 사용하지 않거나 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
대부분의 대화 상자가 비 차단 의사 모달 컨트롤이기 때문에이 방법을 선호하며이 방법을 사용하는 것이 문제를 해결하는 것보다 훨씬 간단 해 보입니다. 단위 테스트도 쉽습니다.