2011-04-09 2 views
4

두 개의 서로 다른 뷰 모델에서 동일한 명령을 호출하려고하는데이를 설계하는 동안 (명령 및 뷰 모델 모두) 멈추었습니다. 나는 것을 깨달았을 때 나는 두 번째 뷰 모델 클래스 ViewModel2을 만든 다음WPF : MVVM의 명령 및 ViewModels 관계

public class ProcessMyString : ICommand 
{ 
    private ViewModel1 viewModel; 

    public ProcessMyString(ViewModel1 viewModel) 
    { 
     this.viewModel = viewModel; 
    } 

    public bool CanExecute(object parameter) 
    { 
     return true; 
    } 

    public event EventHandler CanExecuteChanged 
    { 
     add { CommandManager.RequerySuggested += value; } 
     remove { CommandManager.RequerySuggested -= value; } 
    } 

    public void Execute(object parameter) 
    { 
     viewModel.ProcessMyString(); 
    } 
} 

:하지만,

public class ViewModel1 : DependencyObject 
{ 
    ... 

    // The command property 
    public ProcessMyString ProcessMyStringCommand { get; set; } 

    public ViewModel1() 
    { 
     // Command gets instantiated 
     this.ProcessMyStringCommand = new ProcessMyString(this); 
    } 

    internal void ProcessMyString() 
    { 
     // This is where the actual processing method is called 
     // somewhere from the business logic... 
     ... 
    } 

그리고 ProcessMyString 명령 클래스 :

첫째, 나는 ViewModel1 뷰 모델 클래스를 생성 이 뷰 모델 도 동일한 명령을 사용해야합니다., 명령의 생성자

public ProcessMyString(ViewModel1 viewModel) 

ViewModel1 매개 변수를 사용하기 때문에 작동하지 않으며 두 모델 모두를 전달할 수 있어야합니다. 그런 다음 ViewModelBase 클래스를 만들고 두 모델을 모두 확장하도록 결정했습니다. 나는 물론,뿐만 아니라 명령의 생성자를 수정 :

// Constructor's parameter is now ViewModelBase 
public ProcessMyString(ViewModelBase viewModel) 

하지만 지금은 ViewModelBase에서하는 방법이라고 Execute(object parameter) 해당 명령의 방법을 의미했다. ViewModel의 ProcessMyString()에 대한 호출은 이 및 ViewModel2 클래스의 경우에만으로 예약되어야하기 때문에 좋은 appproach가 아닙니다. 만약 내가 ViewModel3 클래스를 가지고 있다면 나는 ProcessMyString()을 호출하는 것을 원하지 않을 것이고, 그것을 ViewModelBase에서 연장하지 않는다면 괜찮을 것이다.

그러나 ViewModel2ViewModel3 사이에 공유되는 명령이 필요한 경우 어떻게됩니까?

요약 질문은 다음과 같습니다.보기 명령 모델을 구성하여보기 모델이 동일한 명령을 공유하도록하려면 어떻게해야합니까?

답변

1

이 대답은 ProcessMyString 클래스가 필요하지 않으므로 일반 명령으로 대체해야합니다.

우선 MVVM Light 라이브러리를 다운로드하십시오. 그 곳을 풀고이 라이브러리에 대한 참조를 추가 한 후 :

(라이브러리와 폴더) \ MVVM 빛 툴킷은 바이너리 \ WPF4 \ GalaSoft.MvvmLight.WPF4.dll

그것은 포함 \ RelayCommand 클래스가 필요합니다.

은 먼저 명령이 포함 된 기본 클래스 생성 :

public abstract class ProcessStringViewModel : DependencyObject 
{ 
    // The command property 
    public RelayCommand ProcessMyStringCommand { get; set; } 
} 

내가 DependencyObject 클래스에서 상속을 제거하는 것입니다,하지만 어쩌면 당신은 어떻게 든 그것을 사용, 그래서하자.

ViewModel1 클래스는이 방법으로 다시 작성할 수 있습니다 :

public class ViewModel1 : ProcessStringViewModel 
{ 
    public ViewModel1() 
    { 
     // Command gets instantiated 
     this.ProcessMyStringCommand = new RelayCommand(() => this.ProcessMyString()); 
    } 

    internal void ProcessMyString() 
    { 
    } 
} 

ViewModel2 클래스가 다른 함수를 호출 할 수 있지만,이 명령은 동일합니다

public class ViewModel2 : ProcessStringViewModel 
{ 
    public ViewModel2() 
    { 
     this.ProcessMyStringCommand = new RelayCommand(SomeOtherFunction); 
    } 

    private void SomeOtherFunction() 
    { 
     MessageBox.Show("Call of some function"); 
    } 
} 

당신은 사용하지하기로 결정하는 경우 기본 클래스와 상속 - 기본 클래스를 제거하고 각 파생 클래스에 속성을 복사하면 작동합니다.

+0

: 여기

단지 내가이 시나리오를 접근하는 방법의 빠른 실행 다운입니까? 이 프레임 워크에서 가능합니까? (실제로'CanExecute'에 어떤 내용을 가지고 있고'ProcessMyString' 명령에서 보았 듯이 항상'true'를 리턴하지는 않는 다른 명령들을 가지고 있습니다.) – Boris

+0

@Boris 예, 가능하며이 대리자는 두 번째로 전달됩니다 매개 변수. 내 예제에서는 아무 것도 전달하지 않았으며 내재 된 값'() => true'를가집니다. 또한 MVVM Light에는 CommandParameter를 사용하는 다른 명령 클래스가 있습니다. 이 프레임 워크를 다운로드 한 후에 직접 확인할 수 있습니다. – vorrtex

+0

감사합니다. – Boris

6

먼저 개인적인 취향과 마찬가지로 필자는 자신의 ViewModel에서 사용하는 상속의 양을 최소화하는 경향이 있습니다. 복잡하지 않은 애플리케이션의 복잡한 UI 코드는 원저자 외에 누구나 따라야 할 까다로운 작업 일 수 있습니다. 마지막으로 복잡한 객체 모델을 포함 시키면 더 어려워집니다.

ICommand 인터페이스를 사용하는 WPF의 장점은 상속 모델보다는 구성 적 방식을 선호하고 공용 속성을 공유하는 인터페이스를 사용할 수 있어야한다는 것입니다. 내가 명령의`CanExecute` 방법을 설계 할 경우 발생하는, 내가 MVVM 빛을 사용하는 경우

public class ProcessStringCommand : ICommand 
{ 
    private readonly IProcessStringViewModel m_viewModel; 

    public ProcessStringCommand(IProcessStringViewModel vm) 
    { 
     m_viewModel = vm; 
    } 

    public void Execute(object param) 
    { 
     ProcessString(m_viewModel.ProcessString); 
    } 

    public bool CanExecute(object param) 
    { 
     return true; 
    } 

    private void ProcessString(string processString) 
    { 
     // Put logic here 
    } 
} 

public interface IProcessStringViewModel 
{ 
    public string ProcessString { get; } 
} 

public class ViewModel1 : ViewModelBase, IProcessStringViewModel 
{ 
    private readonly ICommand m_command; 
    private readonly string m_processString; 

    public ViewModel1() 
    { 
     m_command = new ProcessStringCommand(this); 
    } 

    public string ProcessString 
    { 
     get { return m_processString; } 
    } 

    public ICommand ProcessStringCommand 
    { 
     get { return m_command; } 
    } 
} 

public class ViewModel2 : ViewModelBase, IProcessStringViewModel 
{ 
    private readonly ICommand m_command; 
    private readonly string m_processString;  

    public ViewModel2() 
    { 
     m_command = new ProcessStringCommand(this); 
    } 

    public string ProcessString 
    { 
     get { return m_processString; } 
    } 

    public ICommand ProcessStringCommand 
    { 
     get { return m_command; } 
    } 
} 

public class ViewModel3 : ViewModelBase 
{ 
    // Whatever you need here. 
} 
+0

이것은 매우 멋지고 깔끔합니다. MVVM Light 프레임 워크를 지금 제공 할 예정입니다. 대답 해 주셔서 감사합니다. – Boris

+0

문제 없으니 기꺼이 도와 드리겠습니다. 그냥 제쳐두고, 나는 두 가지 해결책이 상호 배타적이라고 생각하지 않는다. 이 프레임 워크는 많은 응용 프로그램에서 공유되는 몇 가지 공통 기능을 제공하는 반면, 제 응답은 응용 프로그램의 전체 구조를 더 많이 처리합니다. 그래서 나는 당신이 양쪽 모두로부터 이익을 얻을 수 있다고 생각합니다. 어느 쪽이든, 그것은 당신이 옳은 길을 가고있는 것처럼 들립니다. 행운을 빕니다! – jeremyalan

+0

두 가지 해결책이 상호 배타적이지 않다는 귀하의 관찰에 대해서는 더 이상 동의 할 수 없습니다. 나는이 모든 것에 뛰어 들고 싶어한다. 모든 최선 .. – Boris