2013-05-23 5 views
0

최근에 나는 MVVM 솔루션이라고 생각했던 질문으로 How to Bind to window's close button the X-button에 답변했습니다. 실제 질문에 집중하지 마세요. 그게 저를 괴롭히는 것이 아니기 때문입니다. 나는 심지어 거기에 내 솔루션을 사용하지 않을 것이라고 그 특별한 경우에. 나는 확실히 @ ChrisW의 솔루션을 사용할 것이다.ViewModel이 창을 닫을 수 있습니까?

그런 다음 @SpikeX의 응답이 나타나고 이제는 혼란 스럽습니다. 하지만 그에게 감사해야합니다. 지금까지는 MVVM에 대해 잘못된 생각을하고 있었기 때문에 생각을 멈출 수는 없습니다. 그래서

Close Window from ViewModel

Basic concepts of MVVM— what should a ViewModel do?

및 ...

당신은 내가에서 창을 닫을 우주에서 유일한 사람이 아니에요 볼 수 있듯이 :

그래서 나는 연구를 시작 ViewModel. 그러나 나는 그것을 정말로 할 수 있냐? 또는 ViewModel에 창을 사용해서는 안된다는 것이 사실입니다. MVVM은 이것에 대해 정말로 엄격합니까? 실제로 내 솔루션 MVVM 패턴을 어기는거야?

답변

1

글쎄, 내 의견으로는 뷰 모델은 그것이 사용되는 클라이언트 기술과 완전히 격리되어야한다.

실제 Window 인스턴스에서 close 메서드를 호출하므로 클라이언트 전용 어셈블리 (이 경우 WPF)에 대한 참조가 필요합니다. 따라서이 뷰 모델을 다른 용도로 재사용하는 것은 거의 불가능합니다.

WPF, Silverlight, Windows Phone, Windows Store App 등의 클라이언트를 만들고 싶다면 Windows Phone에서 WPF가 무엇인지 모를 수도 있기 때문에 동일한보기 모델을 모두 사용할 수는 없습니다. 창이 있습니다.

또한 실제 뷰 요소에 대한 참조가있을 때 단위 테스트 뷰 모델이 더 복잡해집니다.

그래서 직접 창을 참조하는 대신, 어떤 종류의보기 어댑터에서 창을 직접 추상화 할 수 있습니다. 뷰 모델은이 같은 인터페이스에 대해 알고있는 경우

:

public interface IView 
{ 
    void Show(); 
    void Close(); 
} 

가에 옳은 일을하지 ... 그래서 각 클라이언트는 자신의 구현을 작성하고 뷰 모델에 주입 할 수 있습니다 주어진 클라이언트.

요점은 viewmodel에는 실제보기에 대한 지식이 없다는 것입니다. 모든 것은 인터페이스 구현에 숨겨져 있습니다.

1

글쎄, 네 솔루션은 패턴을 깨고있다. 가장 큰 단점은 윈도우 닫는 것을 방해하는 VM과 로직을 완전히 테스트 할 수 없다는 것입니다. 그러나 대안을 구현하려는 노력이 필요하다면 언제나 그렇듯이 고려해야합니다.

MVVM을 계속 사용하려면 먼저 연결된 SO post에 게시 된 솔루션을 사용할 수 있습니다. 내 게시물의 필수 부분을 여기에 복사했습니다.당신이 볼 수 있듯이

견적

<Window x:Class="AC.Frontend.Controls.DialogControl.Dialog" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:DialogControl="clr-namespace:AC.Frontend.Controls.DialogControl" 
     xmlns:hlp="clr-namespace:AC.Frontend.Helper" 
     MinHeight="150" MinWidth="300" ResizeMode="NoResize" SizeToContent="WidthAndHeight" 
     WindowStartupLocation="CenterScreen" Title="{Binding Title}" 
     hlp:AttachedProperties.DialogResult="{Binding DialogResult}" WindowStyle="ToolWindow" ShowInTaskbar="True" 
     Language="{Binding UiCulture, Source={StaticResource Strings}}"> 
     <!-- A lot more stuff here --> 
</Window> 

, 나는 xmlns:hlp="clr-namespace:AC.Frontend.Helper" 제 나중에 hlp:AttachedProperties.DialogResult="{Binding DialogResult}" 바인딩 네임 스페이스를 선언하고있다.

[...]

public class AttachedProperties 
{ 
    #region DialogResult 

    public static readonly DependencyProperty DialogResultProperty = 
     DependencyProperty.RegisterAttached("DialogResult", typeof (bool?), typeof (AttachedProperties), new PropertyMetadata(default(bool?), OnDialogResultChanged)); 

    private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var wnd = d as Window; 
     if (wnd == null) 
      return; 

     wnd.DialogResult = (bool?) e.NewValue; 
    } 

    public static bool? GetDialogResult(DependencyObject dp) 
    { 
     if (dp == null) throw new ArgumentNullException("dp"); 

     return (bool?)dp.GetValue(DialogResultProperty); 
    } 

    public static void SetDialogResult(DependencyObject dp, object value) 
    { 
     if (dp == null) throw new ArgumentNullException("dp"); 

     dp.SetValue(DialogResultProperty, value); 
    } 

    #endregion 
} 

/견적

당신이 필요로하는 유일한 것은 내 솔루션 작업을하기 위해이 같은 VM이다.

public class WindowVm : ViewModelBase // base class implementing INotifyPropertyChanged 
{ 
    private bool? _dialogResult; 
    public bool? DialogResult 
    { 
     get { return _dialogResult; } 
     set 
     { 
      _dialogResult = value; 
      RaisePropertyChanged(() => DialogResult); 
     } 
    } 

    //... many other properties 
} 
관련 문제