[英]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.