2011-04-09 74 views
4

我想打電話從兩個不同的視圖模式相同的命令,但在他們的設計(包括命令和視圖模型)我被困命令和的ViewModels關係。WPF:在MVVM

首先,我創建了一個ViewModel1視圖模型類:

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命令類:

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(); 
    } 
} 

然後,我所創建的第二視圖模型類ViewModel2,但是當我意識到該視圖模型還需要使用相同的命令,該命令的構造

public ProcessMyString(ViewModel1 viewModel) 

不會工作,因爲它需要ViewModel1參數,我需要能夠通過兩種視圖模式。然後,我決定創建ViewModelBase類,並使兩個視圖模型都從中擴展。我修改了命令的構造,以及,當然:

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

但是,這意味着該命令的方法Execute(object parameter)ViewModelBase稱爲方法了。這不是一個好appproach因爲視圖模型對ProcessMyString()調用應該是保留只有ViewModel1ViewModel2類。如果我有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'方法會發生什麼?這個框架有可能嗎? (我有一堆其他命令實際上有'CanExecute'中的一些內容,並不總是返回'true',如我的'ProcessMyString'命令所示。) – Boris 2011-04-09 15:36:54

+0

@Boris是的,這是可能的,這個委託作爲第二個參數。我沒有在我的例子中傳遞任何東西,它有隱含的值'()=> true'。此外,MVVM Light還有另一個使用CommandParameter的命令類。您可以在下載此框架後自行檢查。 – vorrtex 2011-04-09 17:13:47

+0

明白了,謝謝! – Boris 2011-04-09 17:19:48

6

首先,我個人偏好,我傾向於最小化我用ViewModel的繼承數量。複雜的UI代碼在非平凡的應用程序中可能會非常棘手,除了原作者之外,任何人都可以遵循,最後要做的事情是通過包含複雜的對象模型使其更難。

使用ICommand接口的WPF的美妙之處在於,您應該能夠支持更多的組合方法,而不是繼承模型,並使用接口來共享公共屬性。

這裏只是我會如何處理這種情況下一個快速破敗:如果我使用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 2011-04-09 18:22:55

+0

沒問題,很高興我可以幫忙。就像旁白一樣,我不認爲這兩種解決方案是相互排斥的。該框架提供了許多應用程序共享的一些常用功能,而我的迴應則更多地處理應用程序的整體結構。所以我認爲你可以從這兩方面受益。無論哪種方式,這聽起來像你在正確的軌道上。祝你好運! – jeremyalan 2011-04-09 21:59:30

+0

對於你的觀察,我不能完全同意這兩種解決方案並不相互排斥。我很想深入瞭解這一切。所有最好.. – Boris 2011-04-09 22:32:57