2013-08-26 49 views
5

我有一個由2個視圖(AddClientView和SuggestedAddressesView)引用的AddClientViewModel。 AddClientView是一個具有地址字段的表單。該表單有一個驗證按鈕,可使用地理編碼驗證輸入的地址。如果返回多個地址,則會打開SuggestedAddressesView。從ViewModel打開/關閉視圖

這裏如何我目前做的是:

AddClientViewModel:

private void ValidateExecute(object obj) 
    { 
     SuggestedAddresses = new ObservableCollection<DBHelper.GeocodeService.GeocodeResult>(GeoCodeTest.SuggestedAddress(FormattedAddress)); 

     .... 

     if (SuggestedAddresses.Count > 0) 
     { 
      var window = new SuggestedAddressesView(this); 
      window.DataContext = this; 
      window.Show(); 
     } 
    } 

這裏是SuggestedAddressesView構造,其中AddClientViewModel從ViewModelBase

繼承
public SuggestedAddressesView(ViewModelBase viewModel) 
    { 
     InitializeComponent(); 
     viewModel.ClosingRequest += (sender, e) => this.Close(); 
    } 

我遇到的另一個問題是當我從AddClientViewModel調用OnClosingRequest()時,AddClientView和SuggestedAddressesView都會關閉。我知道發生這種情況是因爲兩個視圖引用了相同的ViewModel。這不是我想要的行爲。我希望能夠獨立關閉任一窗口。

從ViewModel適當的MVVM結構打開一個視圖,我將如何去關閉獨立關閉窗口?

回答

5

只要你指的UI元素(在這種情況下,視圖)從虛擬機,你要對建議MVVM指南。正因爲如此,我們可以知道在虛擬機中創建Window對象是錯誤的。

所以現在在糾正這種:

  • 首先儘量保持1查看< - 在你的應用程序> 1 VM。它更乾淨,並允許您輕鬆地使用相同的邏輯來切換View實現。即使不是「突破性」,也可以將多個視圖添加到同一個虛擬機上,這隻會讓它變得笨拙。
  • 所以現在你得到了AddClientViewSuggestedAddressesView與他們自己的虛擬機。大!

實現視圖打開/關閉從VM:

  • 既然我們無法直接從我們的VM(符合標準),我們可以使用的方法,例如使用Messenger(MVVM訪問查看Light),EventAggregator(PRISM)等等,當你需要打開/關閉視圖並在視圖中執行實際操作時,從VM向視圖發送「消息」。
  • 這種方式VM只是啓動消息,並可以單元測試罰款相同的操作,並沒有引用任何用戶界面元素。

使用「使者」的方式來處理視圖開放

  • 按照您的邏輯,它是AddClientViewModel將必須索要SuggestedAddressesView被打開。
  • 因此當您檢測到SuggestedAddresses.Count > 0時,您會發送一條消息至AddClientView,要求它打開SuggestedAddressesView
  • AddClientView.xaml.cs收到此消息後,您將執行您當前在VM中執行的操作。創建一個SuggestedAddressesView的對象並在其上調用.Show()
  • 您在上述步驟的過程中添加的一個額外步驟是將的SuggestedAddressesView指定爲SuggestedAddressesViewModel

就是這樣。現在你有什麼,當AddClientViewModel想要SuggestedAddressesView顯示,它發送一條消息到它自己的視圖和視圖輪流創建並顯示SuggestedAddressesView。這樣虛擬機就不會引用任何視圖,而且我們一直持有MVVM標準。

使用 「使者」 的方式來處理視圖接近

  • 關閉一個View是非常簡單的。再次,當您需要關閉虛擬機中的視圖時,您會向其自己的視圖發送一條消息,要求將其關閉。
  • 收到此消息後,View幾乎通過.Hide()/.Close()或其他您想要擺脫它的方式自行關閉。

在這個每個虛擬機處理它自己的視圖關閉,你沒有任何互聯的依賴關係。

您可以使用this作爲起點,指導您處理此方法的「消息」。它有一個附加的下載,你可以看到Messenger的工作原理。這是MVVM Light,如果您不使用它或使用其他/您自己的MVVM實現,請將其用作指導以幫助您實現所需。

+0

好吧,這很有道理! 我遇到的問題是,我想從** SuggestedAddressesView **收集的信息被傳遞給** AddClientViewModel **(因此爲什麼我使用2個視圖的虛擬機)。我這樣做的原因是因爲在** SuggestedAddressesView **中選擇的地址被分配給在** AddClientViewModel **中定義的客戶端。 – francisg3

+1

@ francisg3看看我發佈的示例鏈接。如果你在那裏得到例子,打開的第二個「窗口」模式/非模態傳遞信息返回到MainWindow。這也是您將用於您的需求的過程。您幾乎可以使用Messenger發送消息(這裏的消息是您想要從SuggestedAddressViewModel發送到AddClientViewModel的數據) – Viv

0

您可以使用RelayCommand讓你發送的參數如下:

Command="{Binding CloseWindowCommand, Mode=OneWay}" 
CommandParameter="{Binding ElementName=TestWindow}" 

通過使用這個你可以關閉個人意見。

例子:

public ICommand CloseCommand 
    { 
     get 
     { 
      return new RelayCommand(OnClose, IsEnable); 
     } 
    } 

public void OnClose(object param) 
    { 
     AddClientView/SuggestedAddressesView Obj = param as AddClientView/SuggestedAddressesView; 
     obj.Close(); 
    } 
0

從視圖模型打開的窗口:

創建打開的窗口NavigationService.cs類: 讓NavigationService.cs

現在把下面在類文件的代碼。

public void ShowWindow1Screen(Window1ViewModel window1ViewModel) 
     { 
      Window1= new Window1(); 
      Window1.DataContext = window1ViewModel; 
      Window1.Owner = Window1View; 
      Window1.ShowDialog(); 
     } 

然後。 創建NavigationService.cs類MainWindowViewModel文件的實例。 然後

Window1ViewModel window1ViewModel = new Vindow1ViewModel(); 
window1ViewModel.Name = MainWindowTextValue; 
NavigationService navigationService = new NavigationService(); 
navigationService.ShowWindow1Screen(window1ViewModel);