MVVM 애플리케이션에서 내비게이션을 누가 제어해야합니까?


33

예제 # 1 : MVVM 애플리케이션에 뷰가 표시되고 (토론 목적으로 Silverlight를 사용하겠습니다) 새 페이지로 이동해야하는 버튼을 클릭합니다.

예 # 2 : 동일한보기에는 클릭 할 때 하위 창 (대화 상자)에서 세부 사항보기를 열어야하는 다른 단추가 있습니다.

우리는 ViewModel에 의해 노출 된 Command 객체가 사용자의 클릭에 반응하는 메소드를 사용하여 버튼에 바인딩 될 것임을 알고 있습니다. 그러나 그때는 무엇입니까? 우리는 어떻게 행동을 완료합니까? 우리가 소위 NavigationService를 사용하더라도 무엇을 말하고 있습니까?

좀 더 구체적으로 말하자면, 웹이나 SL 내장 탐색 프레임 워크와 같은 URL 기반 탐색 체계와 같은 기존의 View-first 모델에서 Command 객체는 다음에 표시 할 View를 알아야합니다. 그것은 패턴에 의해 촉진 된 우려의 분리와 관련하여 선을 넘어가는 것처럼 보입니다.

반면에 버튼이 Command 객체에 연결되어 있지 않고 하이퍼 링크처럼 동작하면 탐색 규칙을 마크 업에 정의 할 수 있습니다. 그러나 뷰가 애플리케이션 흐름을 제어하고 다른 유형의 비즈니스 로직 만 탐색하도록 하시겠습니까? (어떤 경우에는 예라고 말할 수 있고 다른 경우에는 아니오라고 말할 수 있습니다.)

나에게 MVVM 패턴의 유토피아 적 구현 (및 다른 사람들이 이것을 고백한다고 들었다)은 응용 프로그램이 헤드리스 (예 : 뷰 없음)로 실행될 수있는 방식으로 ViewModel을 유선으로 연결하는 것입니다. 이는 코드 기반 테스트를위한 가장 표면적을 제공하고 뷰를 응용 프로그램에서 실제 스킨으로 만듭니다. 그리고 내 ViewModel이 기본 창, 부동 패널 또는 자식 창에 표시되는지 신경 쓰지 않아야합니까?

이 apprach에 따르면 런타임마다 각 ViewModel에 대해 표시해야 할 View를 '바인딩'하는 것은 다른 메커니즘에 달려 있습니다. 그러나 View를 여러 ViewModel과 공유하거나 그 반대로 공유하려면 어떻게해야합니까?

따라서 View-ViewModel 관계를 관리해야하므로 자식 창 / 대화 상자 표시를 포함하여보기 사이를 탐색해야 할 필요가있을 때 무엇을 표시 해야하는지 알 수 있습니다.이를 MVVM 패턴에서 어떻게 실제로 달성합니까?

답변:


21

탐색은 항상 ViewModel에서 처리해야합니다.

MVVM 디자인 패턴을 완벽하게 구현하면 뷰없이 응용 프로그램을 완전히 실행할 수 있으며 뷰가 내비게이션을 제어하는 ​​경우에는 그렇게 할 수 없다고 생각하면 올바른 길을 가고 있습니다.

나는 보통이 ApplicationViewModel, 또는 ShellViewModel내 응용 프로그램의 전반적인 상태를 처리하는. 여기에는 CurrentPage(ViewModel) 및 처리 코드가 포함 ChangePageEvents됩니다. (현재 사용자 또는 ErrorMessages와 같은 다른 응용 프로그램 전반의 개체에도 사용됩니다)

어떤 뷰 모델은 어디서나하는 방송 그래서 경우 ChangePageEvent(new SomePageViewModel)ShellViewModel의지 메시지가 픽업은 전환 CurrentPage메시지에 지정된 어떤 페이지로 이동합니다.

실제로 관심이 있다면 MVVM으로 탐색에 대한 블로그 게시물을 작성했습니다.


2
재미있는 접근법. 4 가지 의견 : 1) Silverlight는 DataTemplate에서 DataType 속성을 지원하지 않으므로 SL에서 DataTemplate을 ViewModel에 매핑 할 수 없습니다. 2) 이것은 뷰와 뷰 모델 사이의 다 대다 가능성을 다루지 않습니다. 3) 자식 창을 처리하지 못합니다 (또는 적어도 방법을 보지 못합니다). 4) 응용 프로그램 / 셸 ViewModel과 자식 (손자 등) 간의 긴밀한 연결이 필요합니다. 내 응용 프로그램에 40 페이지가있는 경우이 ViewModel은 관리하기가 성 가실 수 있습니다.
SonOfPirate

그것은 분명히 고려해야 할 사항입니다.
SonOfPirate

@SonOfPirate 1) Silverlight는 암시 적 DataTemplate 매핑 (아직)을 지원하지 않지만 DataTemplateSelectorSilverlight 앱에 일반적으로 사용하는을 지원 합니다. 2) 나는 이것을 다 대다 상황에서 사용했습니다. 예를 들어 하나의 ViewModel에 여러 개의 View가 있거나 하나의 View가 여러 개의 ViewModel과 연관 될 수 있습니다. 전자의 예는 rachel53461.wordpress.com/2011/05/28/…를 참조하십시오 . 나중에 여러 DataModel이 DataTemplateSelector의 동일한 뷰에 매핑되도록 지정하면됩니다.
Rachel

3) 이것은 기본적인 예일뿐입니다. 응용 프로그램이 여러 개의 창이 될 것이라는 것을 알고 있다면 ShellViewModel을 여러 CurrentPages개로 처리하도록 분명히 변경해야합니다. 4) 다시 한 번, 이것은 기본 예제 일뿐입니다. 실제로 내 PageViewModel은 모두 기본 클래스를 기반으로하므로 ShellViewModel은 기본 클래스 또는 인터페이스와 만 작동합니다 IPageViewModel. 실제로 가장 복잡한 지저분한 매핑은 40 개의 뷰를 40 개의 ViewModel에 매핑해야하는 DataTemplateSelector입니다.
Rachel

@SonOfPirate 나는 당신의 질문에 대답하기를 바랍니다. 다른 사람이 있다면 채팅에서 저를 찾아보세요 :)
Rachel

6

폐쇄를 위해, 나는 마침내이 문제를 해결하기 위해 선택한 방향을 게시 할 것이라고 생각했습니다.

첫 번째 결정은 기본 제공되는 Silverlight Page Navigation 프레임 워크를 활용하는 것입니다. 이 결정은 Microsoft에서이 탐색 유형이 Windows 8 Metro 앱으로 이월되고 Phone 7 앱의 탐색과 일치한다는 지식을 포함하여 몇 가지 요소를 기반으로합니다.

작동시키기 위해 ASP.NET MVC가 컨벤션 기반 탐색으로 수행 한 작업을 살펴 ​​보았습니다. Frame 컨트롤은 URI를 사용하여 표시 할 '페이지'를 찾습니다. 유사성은 Silverlight 앱에서 유사한 컨벤션 기반 접근 방식을 사용할 수있는 기회를 제공했습니다. 그 트릭은 MVVM 방식으로 모두 함께 작동하도록하는 것이 었습니다.

해결책은 NavigationService입니다. 이 서비스는 ViewModels가 페이지 변경을 시작하는 데 사용할 수있는 몇 가지 방법 (예 : NavigateTo 및 Back)을 제공합니다. 새 페이지가 요청되면 NavigationService는 MVVMLight Messenger 기능을 사용하여 CurrentPageChangedMessage를 보냅니다.

Frame 컨트롤이 포함 된 뷰에는이 메시지를 수신하는 DataContext로 설정된 자체 ViewModel이 있습니다. 수신되면 새보기의 이름은 컨벤션 규칙을 적용하고 CurrentPage 속성으로 설정되는 매핑 기능을 통해 전달됩니다. Frame 컨트롤의 Source 속성은 CurrentPage 속성에 바인딩됩니다. 결과적으로 속성을 설정하면 소스가 업데이트되고 탐색이 트리거됩니다.

NavigationService로 돌아갑니다. NavigateTo 메소드는 대상 페이지의 이름을 승인합니다. ViewModel에 UI 관련 사항이 없는지 확인하기 위해 사용되는 이름은 표시 할 ViewModel의 이름입니다. 실제로 탐색 가능한 각 ViewModel에 대한 필드를 도우미로 사용하고 앱 전체에서 마법의 문자열을 제거하는 열거 형을 만들었습니다. 위에서 언급 한 매핑 함수는 이름에서 "ViewModel"접미사를 제거하고 이름에 "Page"를 추가하고 전체 이름을 "Views {Name} Page.xaml"로 설정합니다.

예를 들어 고객 세부 정보보기로 이동하려면 다음을 호출하면됩니다.

NavigationService.NavigateTo(ViewModels.CustomerDetails);

CustomerDetails의 값은 "Views \ CustomerDetailsPage.xaml"에 매핑 된 "CustomerDetailsViewModel"입니다.

이 접근 방식의 장점은 UI가 ViewModel과 완전히 분리되어 있지만 전체 탐색을 지원한다는 것입니다. 그러나 이제는 코드를 변경하지 않고도 응용 프로그램을 다시 스키닝 할 수 있습니다.

설명이 도움이 되길 바랍니다.


2

Rachel의 말과 유사하게, 대부분의 VMVM 응용 프로그램에는 Presenter창 또는 페이지 간 스위치를 처리 하는 기능 이 있습니다. Rachel은 이것을이라고 부르지 ApplicationViewModel만 제 경험상 일반적으로 메시지 수신, Windows 작성 등과 같은 바인딩 대상 이상을 수행해야하므로 기술적으로 전통적인 Presenter또는 Controller.

내 응용 프로그램에서 내 Presenter시작은 CurrentViewModel입니다. 는 Presenter사이의 모든 통신을 차단 View하고을 ViewModel. (가) 것들 중 하나 ViewModel상호 작용하는 동안 할 수있는 새로운 돌려 주어 ViewModel새로운 페이지를 의미하거나 새가있는 Window표시되어야합니다. 을 Presenter만들거나 덮어 쓰기를 돌봐 View새로운 것을 ViewModel하고 설정 DataContext.

작업의 결과는 a ViewModel가 "완료" 된 결과 일 수 있으며 ,이 경우이를 Presenter감지하여 창을 닫거나 ViewModelVM 스택에서 이를 팝 하고 이전 페이지를 다시 표시합니다.


발표자는 표시 할 View를 어떻게 알 수 있습니까?
SonOfPirate

1
@SonOfPirate-이것은 일반적으로 WPF 메커니즘을 통해 수행됩니다. Presenter단지 스틱 반환 된 ViewModel시각적 트리에, 그리고 WPF 적절한를 잡고 View, 위로 후크 DataContext가 시각적 트리에 대신하고, 풋. 렌더링 DataTemplate하는 ViewModel유형 을 선언하는 s를 사용하여이를 수행 하거나 사용자 정의 데이터 템플리트 선택기를 작성할 수 있습니다. 그것은 여전히 ​​WPF 기능의 영역 안에 있습니다.
Scott Whitlock
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.