簡體   English   中英

在按鈕上打開新窗口,單擊WPF MVVM

[英]Opening a new window on button click WPF MVVM

我正在學習WPF MVVM,並希望在從主窗口單擊按鈕時打開一個新窗口。

我知道每個View必須具有一個等效的ViewModel,而MVVM的基本原理之一是ViewModel必須不了解任何有關View的信息。

因此,請任何人為我提供一個簡單干凈的示例,該示例在創建兩個具有以下功能的View和兩個ViewModel時不違反任何MVVM原理:

通過單擊主視圖中的按鈕來顯示新視圖。

您可以創建單獨的服務以將視圖啟動為對話框,以便可以在整個應用程序中以通用方式使用它。 並將通過構造器將該服務注入到ViewModel中,該構造器要啟動任何對話框。

public interface IDialogWindowService<T>
{
    void Show();
    void ShowDialog();
}

public class DialogWindowService<T> : IDialogWindowService<T> where T : Window
{
    public void Show()
    {
        container.Resolve<T>().Show();
    }

    public void ShowDialog()
    {
        container.Resolve<T>().ShowDialog();
    }
}

現在,只需將此服務注入到各自的ViewModel中即可。

public class YourViewModel
{
    //commands
    public ICommand someCommand { get; set; }

    private IDialogWindowService<BookingView> _dialogService;
    public YourViewModel(IDialogWindowService<YourView > dialogService)
    {
        _dialogService = dialogService
        someCommand = new RelayCommand(someCommandDoJob, () => true);
    }

    public void someCommandDoJob(object obj)
    {
        //Since you want to launch this view as dialog you can set its datacontext in its own constructor.    
        _dialogService.ShowDialog();
    }
}

要么

您可以使用DataTemplates更改視圖。 它允許根據ViewModel動態切換Views

<Window>
   <Window.Resources>
      <DataTemplate DataType="{x:Type ViewModelA}">
         <localControls:ViewAUserControl/>
      </DataTemplate>
      <DataTemplate DataType="{x:Type ViewModelB}">
         <localControls:ViewBUserControl/>
      </DataTemplate>
   <Window.Resources>
  <ContentPresenter Content="{Binding CurrentView}"/>
</Window>

如果Window.DataContext是ViewModelA的實例,則將顯示ViewA並

Window.DataContext是ViewModelB的實例,然后將顯示ViewB。

我見過和讀過的最好的例子是雷切爾·林(Rachel Lim)。 參見示例。

根據您的使用情況,從視圖的后台代碼中打開視圖沒有任何問題。 畢竟它仍然是查看代碼

MyView view = new MyView();
view.Show();

否則,如果需要從ViewModel或使用ICommand打開窗口,則可以查看我在GitHub上編寫的“在MVVM中打開窗口和對話框”庫。 這將演示如何通過使用MVVM設計模式單擊按鈕來打開Window

過去我取得的一些成功是創建了一個基本上就是View Factory的視圖工廠,該工廠構造了一個視圖並為其分配了一個視圖模型。 這給了我一站式服務,可以進行視圖搜索,就像使用IoC一樣。

這樣做可能有優缺點,所以我很想知道是否還有其他/更好的方法,但是到目前為止,這是我發現痛苦最小的做法。

Window newWindow = new Window();
Window.Show(); 

或者如果您想禁用上一個窗口

Window newWindow = new Window();
Window.ShowDialog();

要使MVVM更純凈,可以使用工廠或為每個視圖編寫一個接口驅動的控制器,以處理a)顯示內容和b)如何將其綁定到數據。 因此對於控制器:FormAlpha具有FormAlphaViewModel和FormAlpha.VPS。 該接口非常適合此操作,因為每個實現都不同。

因此,創建一個標准,使每個視圖都具有以vps-或可視表示服務結尾的界面驅動類。 您想在該按鈕單擊上觸發FormAlpha。 您將使用反射或工廠將FormAlpha.vps加載為IVisualPresentor並調用IVisualPrentor.Display(parms);。

每個VPS都有加載特定表單,將數據綁定與與該表單關聯的視圖模型(沒有提供很多解決方案)綁定的工作,並且第一個參數始終具有Show()或ShowDialog()的必需參數。

而且...當然...您的視圖模型首先要獲取的是傳遞的參數。 因此,VPS將分解這些參數並確認已傳遞正確的參數。 通過這種方式(從您的示例中),您可以擁有按鈕代表的功能並想要部署。 VPS處理完成此任務所需的數據和視覺效果。 呼叫者只知道VPS將處理任何功能。 現在,我只是從內存中弄亂了下面的代碼,所以它不是完美的。 但是在上面提出我正在談論的想法。

public interface IVisualPresentor
{ void Display(params object[] parms) };

public class FormAlpha.VPS : IVisualPresentor
{  
     public void Display(params object[] parms)
     {
       //validate parms if needed and cast to type specific data
       //for example it needs session data parms[1] and customer parms[2]
       var form = new FormAlpha();
       var model = new FormAlphaViewModel( sessionData, customer );
       form.DataBinding = model;
       if ((bool)parms[0])
          form.Show(); 
       else 
          form.ShowDialog();
    }
 }

假設Form1是您的主窗體,而Form2是您要打開的窗體:您可以使用以下代碼(將其插入Form1中):

Form2 frm = new Form2();
frm.Show();

另外,如果要關閉主窗體,則可以使用this.Close(); (它將關閉當前表單)。 此外,如果您只想打開Form2,但仍然要以Form1為主,則可以使用:

Form2 frm = new Form2();
frm.Show();
this.Focus();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM