2010-01-18 2 views
60

MVVM을 좋아합니다. 나는 그것을 좋아하지 않지만 그것을 좋아한다. 대부분은 의미가 있습니다. 그러나 XAML을 작성하고 코드 숨김에 코드를 작성할 필요가 없도록 많은 코드를 작성하도록 권장하는 기사를 계속 읽습니다.MVVM Madness : Commands

예를 들어 설명해 드리겠습니다.

최근 내 ViewModel의 명령을 ListView MouseDoubleClickEvent에 연결하려고했습니다. 어떻게하는지 잘 모르겠습니다. 다행히도 Google은 모든 것에 대한 해답을 가지고 있습니다. 나는 다음과 같은 기사를 발견

를 솔루션이 명령에 대한 이해에 도움이되는 동안, 문제가 있었다. 앞서 언급 한 솔루션 중 일부는 종속성 속성 뒤에 "내부"를 추가하는 일반적인 해킹 때문에 WPF 디자이너를 사용할 수 없게 만들었습니다. WPF 디자이너는 찾을 수 없지만 CLR은 찾을 수 있습니다. 일부 솔루션은 동일한 컨트롤에 대해 여러 명령을 허용하지 않았습니다. 일부 솔루션은 매개 변수를 허용하지 않았습니다.

몇 시간 동안 실험 후 난 그냥이 작업을 수행하기로 결정

private void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) { 
    ListView lv = sender as ListView; 
    MyViewModel vm = this.DataContext as MyViewModel; 

    vm.DoSomethingCommand.Execute(lv.SelectedItem); 
} 

그래서, MVVM 순수 주의자는,이 뭐가 잘못 말해주십시오? 나는 아직도 나의 명령을 단위 테스트 할 수있다. 이것은 매우 실용적이지만 "ZOMG ...의 지침을 위반하는 것 같습니다. 코드 숨김 코드가 있습니다 !!!!" 생각을 공유하십시오. 사전에

감사합니다.

+1

나는 이걸 직접 해냈다. 아무 문제가 없다. – Schneider

+7

ZOMFG CODE BEHIND !!!!!!! – Pierreten

+1

@Schneider에 동의 할 것입니다. 이것이 완벽한 의미입니다. 실제로 소위 코드 숨김 파일 사용을 피하기 위해 필요한 배관 코드의 양은 여전히 ​​저의 머리를 회전시킵니다. –

답변

37

결점은 순도 요구 사항에 있다고 생각합니다. MVVM이 포함 된 디자인 패턴은 툴박스에있는 도구이지 결코 끝내지는 못합니다. 잘 고려 된 케이스에 대한 모델의 순도를 깨는 것이 더 합리적이라면 (그리고이 케이스를 고려한 것처럼 보입니다.) 모델과 분리하십시오.

그게 효과가 있고 과도한 유지 관리 부담이라고 생각하지 않는다면, 내가 한 일에 아무런 문제가 없다고 말할 수 있습니다. 필자는 순수 MVVM 구현이 무엇인지에도 불구하고 이것이 문제에 대한 합리적인 해결책이라는 것을 보여주는 증거의 부담을 분명히 만났다고 생각합니다.

(필자는이 주장을 다중 패러다임 언어에 대한 논의와 비슷하다고 생각합니다 .Pure OO 접근법을 적용 할 수 있지만 때로는보다 기능적인 방식으로 일을하는 것이 더 적절합니다. 순전히 기능적 접근법을 적용 할 수 있지만 때때로 offs는 OO 기술이 가치있는 것 이상임을 보여줍니다.)

+9

MVVM 또는 기타 패턴과 상관없이 과도한 순도는 비생산적입니다. 뷰 모델이 모든 작업을 수행해야하기 때문에 값 변환기를 사용하지 않아야한다고 말하는 사람들을 보았습니다. 꽉 조이는 커플 링 및 아키텍처 실패에 대한 확실한 방법입니다. MVVM은 WPF에서 * 생각하는 방법에 대한 (매우) 유용한 지침 원리이므로 코드를 단순하고 분리 할 수 ​​있습니다. 그것은 당신의 코드를 뒤틀린 복잡성의 부 자연스러운 혼란으로 이끄는 막대기가되어서는 안됩니다. – itowlson

+1

원래의 질문은 순수한 MVVM을하려고하는 내 자신의 좌절을 반영합니다. 그러나 저는 여러분의 답을 좋아합니다. 그러나 새로운 패턴, 특히 MVVM과 같은 othello와 같은 것을 배울 때 (배우기 쉽고 마스터하기가 어렵다는 것을 지적하고 싶습니다.), 학습에 접근하는 가장 좋은 방법은 패턴 순결을 강요하기 위해 할 수있는 모든 일을하는 것입니다. 하드 레슨을 배운 후에 만 ​​패턴을 언제, 어떻게 깨야하는지 알 수있는 경험을 얻을 수 있습니다. – Randolpho

+1

@Randolpho : 당신은 매우 훌륭하고도 적절한 견해를 가지고 있으며, 나는 완전히 동의합니다. 나는 내 개인적인 프로젝트의 대부분에서 패턴에 대한 나의 이해의 순결함, 그리고 분명히 작은 것을 위해 노력한다. MVVM은 까다로운 부분이라 생각합니다. 왜냐하면보기 영역에 속한 영역과보기 영역에 속하는 영역이 너무 많기 때문입니다. 개인적 견해로는 애플리케이션 상태에 영향을주지 않는 모든 것이 VM 및 뷰 (어쩌면 코드 비하인드!)에 머물러 있지만, 나는 MVP와 비슷한 것을 작성하고 있는가? 던노. 매우 미묘한 물건! –

13

많은 MVVM-Command 솔루션이 너무 복잡하다는 데 동의합니다. 개인적으로, 필자는 혼합 된 접근법을 사용하고 ViewModel의 메서드와 속성을 사용하여 ViewModel보다는 View에서 명령을 정의합니다.

XAML :

<Window.Resources> 
    <RoutedCommand x:Key="LookupAddressCommand" /> 
</Window.Resources> 
<Window.CommandBindings> 
    <CommandBinding Command="{StaticResource LookupAddressCommand}" x:Name="cmdLookupAddress" /> 
</Window.CommandBindings> 

코드 (보기) :

Private Sub cmdLookupAddress_CanExecute(ByVal sender As System.Object, ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs) Handles cmdLookupAddress.CanExecute 
    e.CanExecute = myViewModel.SomeProperty OrElse (myViewModel.SomeOtherProperty = 2) 
End Sub 

Private Sub cmdLookupAddress_Executed(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs) Handles cmdLookupAddress.Executed 
    myViewModel.LookupAddress() 
End Sub 

그것은 순수하지 MVVM하지만 간단, 작동, 그것은 특별한 MVVM-명령 클래스를 필요로하지 않으며이 있습니다 비 MVVM 전문가 (= 내 동료)를 위해 코드를 훨씬 쉽게 읽을 수 있습니다.

+0

그건 영리한거야. – cwap

5

"코드 숨김에 코드가 없습니다"라는 목표는 정확히 도달하는 목표입니다. 절대적인 교리로 받아 들여서는 안되는 것이 아닙니다. 보기에 코드를위한 적절한 장소가 있습니다 - 그리고 이것은 대체 방법보다 코드가 더 간단하거나 간단 할 수있는 나쁜 예가 될 필요는 없습니다.

첨부 된 속성이나 연결된 이벤트를 포함하여 나열한 다른 접근법의 장점은 다시 사용할 수 있다는 것입니다. 이벤트를 직접 연결 한 다음 수행 한 작업을 수행하면 응용 프로그램 전체에 해당 코드를 복제하는 것이 매우 쉽습니다. 해당 배선을 처리하기 위해 하나의 연결된 속성이나 이벤트를 작성하여 배관에 몇 가지 추가 코드를 추가합니다. 그러나 이중 클릭 처리를 원하는 ListView에서 재사용 할 수있는 코드입니다.

내가 말했듯이 나는 더 "순수 주의적"접근법을 선호하는 경향이있다. 보기에서 모든 이벤트 처리를 유지하면 테스트 시나리오 (구체적으로 다루는)에 영향을 미치지 않지만 전반적인 디자인 가능성 및 유지 관리성에 영향을 미칩니다. 코드 뒤에 코드를 삽입하면 뷰를 코드에 묶고 디자이너가 다시 디자인 할 수있는 유연성을 제한하는 이벤트 처리기를 유선으로 사용하여 항상 ListView를 사용하여 뷰를 제한 할 수 있습니다.

10

MVVM 패턴을 사용할 때 코드 숨김을 쓰지 않는 편이 좋지만 코드가 UI와 완전히 관련되어있는 한 그 코드를 사용하는 것이 좋습니다.

그러나 이것은 여기에 해당하지 않습니다. 코드 숨김에서 뷰 모델 명령을 호출하므로 순수하게 UI와 관련이 없으며 뷰와 뷰 모델 명령 사이의 관계는 직접적으로 아닙니다. XAML에서 분명합니다.

XAML에서는 attached command behavior을 사용하면 쉽게 할 수 있다고 생각합니다. 그런 식으로 할 수 있습니다 "바인딩"뷰 모델의 명령에 MouseDoubleClick 이벤트 :

<ListView ItemSource="{Binding Items}"> 
    <local:CommandBehaviorCollection.Behaviors> 
     <local:BehaviorBinding Event="MouseDoubleClick" Action="{Binding DoSomething}" /> 
    </local:CommandBehaviorCollection.Behaviors> 

    ... 
</ListView> 

당신은 또한 쉽게 ICollectionView 인터페이스를 사용하여, 직접 참조하지 않고 ListView의 선택된 항목에 액세스 할 수 있습니다

private ICommand _doSomething; 

public ICommand DoSomething 
{ 
    get 
    { 
     if (_doSomething == null) 
     { 
      _doSomething = new DelegateCommand(
       () => 
       { 
        ICollectionView view = CollectionViewSource.GetDefaultView(Items); 
        object selected = view.CurrentItem; 
        DoSomethingWithItem(selected); 
       }); 
     } 
     return _doSomething; 
    } 
} 
+0

나는이 링크도 넣으려고했다. 그러나 이것은 WPF 디자이너를 사용할 수 없게 만드는 요소 중 하나입니다. 적어도 그것은 나를 위해했다. 어쩌면 내가 뭔가 잘못한거야? –

+5

<기본값으로 사용할 수없는 WPF 디자이너에 대한 의무적 인 농담을 삽입하십시오.> –

+0

아, 그래도 디자이너가 해체됩니다 ... 잊어 버렸습니다. 어쨌든 그렉 D가 유머러스하게 지적한 것처럼이 디자이너는 거의 작동하지 않습니다.). 결코 사용하지 않고, XAML 만 쓰면됩니다. –

1

명령은 혼란에 대한 것입니다. 진짜 남자들은 자신의 전체 UI를 코드 숨김으로 이벤트에 연결합니다.

+4

아니요, REAL *의 남성은 XAML에서 알고리즘을 작성합니다. –

+5

필수 프로그래머에 대한 xkcd 만화의 일러스트레이션 : http://xkcd.com/378/ – dthrasher

2

원래의 질문에서 @JP가 묘사 한 것은 무엇이며 @Heinzi는 대답은 어려운 명령을 처리하는 실용적인 접근이라고 언급합니다. 코드를 처리하는 작은 이벤트 처리 코드를 사용하면 명령을 호출하기 전에 약간의 UI 작업을해야 할 때 특히 편리합니다.

OpenFileDialog의 고전적인 사례를 생각해보십시오. 버튼에서 클릭 이벤트를 사용하고 대화 상자를 표시 한 다음 MVVM 툴킷에서 사용하는 복잡한 메시징 루틴을 채택하는 것보다 ViewModel의 명령에 결과를 보내는 것이 훨씬 쉽습니다.당신의 XAML에서

:

<Button DockPanel.Dock="Left" Click="AttachFilesClicked">Attach files</Button> 

뒤에 코드에서는 :

private void AttachFilesClicked(object sender, System.Windows.RoutedEventArgs e) 
    { 
     // Configure open file dialog box 
     Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog(); 
     dlg.FileName = "Document"; // Default file name 
     dlg.DefaultExt = ".txt"; // Default file extension 
     dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension 

     // Show open file dialog box 
     bool? result = dlg.ShowDialog(); 

     // Process open file dialog box results 
     if (result == true) 
     { 
      string filename = dlg.FileName; 

      // Invoke the command. 
      MyViewModel myViewModel = (MyViewModel)DataContext; 
      if (myViewModel .AttachFilesCommand.CanExecute(filename)) 
      { 
       noteViewModel.AttachFilesCommand.Execute(filename); 
      } 
     } 
    } 

컴퓨터 프로그래밍은 유연성이다. 프로그래머는이를 처리하기 위해 유연해야합니다.

2

디커플링은 MVVM의 주요 기능 중 하나입니다. 말보기 또는 바인딩 된 모델을 변경하려고한다고 가정하십시오. 귀하의 응용 프로그램에 대해 얼마나 쉬울까요?

View1과 View2가 모두 동일한 ViewModel을 공유하는 경우를 예로 들어 보겠습니다. 이제 코드 숨김 메소드를 구현할 것입니다. 이 때문에 널 코드의 충돌을 반환 뷰 모델 변경으로 실패하고 문

MyViewModel vm = this.DataContext as MyViewModel; 

얻을 것이다 나중에 명령을 무대에 뷰의 뷰 모델을 변경해야하는 경우도

는 가정합니다. 따라서 코드를 변경하는 데 추가 부담이 따른다. 이러한 방식의 시나리오는 이런 식으로 발생합니다.

물론 프로그래밍 할 때 동일한 것을 달성하는 방법은 많지만 최선의 방법은 최선의 방법이 될 것입니다.