[英]How do I go to another view from a view in MVVM WPF?
這里我有一個 WPF 應用程序,它是用 MVVM 結構制作的。 我是 C# WPF 的新手,不熟悉這個概念。 我試圖通過按下按鈕在一個視圖中通過 function 切換到另一個視圖。
按下登錄按鈕后,將觸發 function 以驗證輸入,如果有效則切換到另一個視圖。 看起來像這樣,
文件結構
我怎樣才能切換視圖? 下面是一些代碼供參考。
主窗口.xaml
<Window x:Class="QuizAppV2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:QuizAppV2"
xmlns:viewModel="clr-namespace:QuizAppV2.MVVM.ViewModel"
mc:Ignorable="d"
Height="600" Width="920"
WindowStartupLocation="CenterScreen"
WindowStyle="None"
ResizeMode="NoResize"
Background="Transparent"
AllowsTransparency="True">
<Window.DataContext>
<viewModel:MainViewModel/>
</Window.DataContext>
<Border Background="#272537"
CornerRadius="20">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75"/>
<RowDefinition/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Online Quiz"
Grid.Column="1"
FontSize="20"
Foreground="White"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<StackPanel Grid.Column="2"
Margin="30,20"
Orientation="Horizontal"
HorizontalAlignment="Right"
VerticalAlignment="Top">
<Button Content="–"
Background="#00CA4E"
Style="{StaticResource UserControls}"
Click="Minimise"/>
<Button Content="▢"
Background="#FFBD44"
Style="{StaticResource UserControls}"
Click="Restore"/>
<Button Content="X"
Background="#FF605C"
Style="{StaticResource UserControls}"
Click="Exit"/>
</StackPanel>
</Grid>
<ContentControl Grid.Column="1"
Grid.Row="1"
Margin="20,10,20,50"
Content="{Binding CurrentView}"/>
</Grid>
</Border>
</Window>
MainViewModel.cs
using QuizAppV2.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QuizAppV2.MVVM.ViewModel
{
class MainViewModel : ObservableObject
{
public RelayCommand LoginViewCommand { get; set; }
public RelayCommand SubjectSelectionViewCommand { get; set; }
public RelayCommand QuizViewCommand { get; set; }
public RelayCommand ResultViewCommand { get; set; }
public LoginViewModel LoginVM { get; set; }
public SubjectSelectionViewModel SubjectSelectVM { get; set; }
public QuizViewModel QuizVM { get; set; }
public ResultViewModel ResultVM { get; set; }
private object _currentView;
public object CurrentView
{
get { return _currentView; }
set
{
_currentView = value;
onPropertyChanged();
}
}
public MainViewModel()
{
LoginVM = new LoginViewModel();
SubjectSelectVM = new SubjectSelectionViewModel();
QuizVM = new QuizViewModel();
ResultVM = new ResultViewModel();
CurrentView = SubjectSelectVM;
LoginViewCommand = new RelayCommand(o =>
{
CurrentView = LoginVM;
});
SubjectSelectionViewCommand = new RelayCommand(o =>
{
CurrentView = SubjectSelectVM;
});
}
}
}
登錄查看.xaml
using QuizAppV2.MVVM.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace QuizAppV2.MVVM.View
{
/// <summary>
/// Interaction logic for LoginView.xaml
/// </summary>
public partial class LoginView : UserControl
{
public LoginView()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (UsrId.Text == "" || UsrName.Text == "")
{
UsrIDErrMsg.Visibility = Visibility.Visible;
UsrNameErrMsg.Visibility = Visibility.Visible;
}
else
{
UsrIDErrMsg.Visibility = Visibility.Hidden;
UsrNameErrMsg.Visibility = Visibility.Hidden;
MainWindow.currentUser = new Student(UsrId.Text, UsrName.Text);
}
}
}
}
謝謝
我建議使用“Datatemplate”。 放入主要的 window 資源如下:
<DataTemplate DataType="{x:Type viewmodel:QuizViewModel}">
<local:QuizView/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodel:LoginViewModel}">
<local:LoginView/>
</DataTemplate>
等等... WPF 正在為您完成所有工作,它檢查“CurrentView”屬性和 select 如何根據合適的 DataTemplate 查看它。
導航是一個棘手的話題,有幾種方法可以做到這一點,但由於您是 WPF 的新手,我試圖概述一種簡單的技術,根據您提供的示例,要求必須逐頁 go,這是一個簡單的想法將是換出內容。 我的意思是,當用戶單擊“登錄”時,我們對用戶進行身份驗證並將 LoginPage 與其他頁面交換,在您的情況下是測驗頁面,當用戶選擇任何選項時,我們將視圖換成下一個視圖等等在。
我用 Shell 機制編寫了一個簡單的解決方案。 本質上,我們在 MainWindow 中創建一個空的 shell(即它沒有 UI),我們使用 NavigationService/Helper 將頁面加載到這個空的 shell 中。 為了簡單起見,我在這里使用了 singleton class,其中有 3 種主要方法,
RegisterShell:這必須是交換將發生的 Window,理想情況下需要設置一次。
加載視圖:用新視圖交換舊視圖的方法,我為此使用了用戶控件,因為大多數子視圖都可以是 WPF 中的用戶控件。
LoadViewWithCustomData:與上面類似,但具有更多的靈活性,因為它允許您提供額外的數據。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace Navigation
{
class NavigationService
{
/// <summary>
/// Singleton so we keep on shell which views can use this to navigate to different pages.
/// </summary>
public static NavigationService Instance = new NavigationService();
private MainWindow myShell;
private NavigationService()
{
}
/// <summary>
/// Register the main shell so this service know where to swap the data out and in of
/// </summary>
/// <param name="theShell"></param>
public void RegisterShell(MainWindow theShell)
{
this.myShell = theShell;
}
/// <summary>
/// Swaps out any view to the shell.
/// </summary>
/// <typeparam name="T"></typeparam>
public void LoadView<T>() where T : UserControl, new()
{
myShell.TheShell = new T();
}
/// <summary>
/// Swaps out any view to the shell with custom data, here the user responsible to create UserControl with all the reqired data for the view.
/// We can automate this via reflection if required.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="theNewControl"></param>
public void LoadViewWithCustomData<T>(UserControl theNewControl) where T : UserControl, new()
{
myShell.TheShell = theNewControl;
}
}
現在這是我的登錄頁面的樣子,這里重要的一行是NavigationService.Instance.LoadView<_4OptionQuizPage>()這實質上將用戶發送到 _4OptionQuizPage。
public partial class LoginPage : UserControl
{
public ICommand LoginClicked { get; }
public LoginPage()
{
InitializeComponent();
this.DataContext = this;
LoginClicked = new SimpleCommand(OnLoginClicked);
}
private void OnLoginClicked()
{
// TODO : Authenticate user here.
// Send the user to Quiz Page
NavigationService.Instance.LoadView<_4OptionQuizPage>();
}
}
在 _4OptionQuizPage 中,我們可以有這樣的東西,這是大部分業務邏輯可能駐留的地方,我在這里有 4 個按鈕,其中 2 個顯示消息框,但按鈕 1 將您發送回登錄頁面,按鈕 2 重新加載同一頁面不同的數據(即將用戶發送到下一個問題)
public partial class _4OptionQuizPage : UserControl, INotifyPropertyChanged
{
public ICommand Option1Clicked { get; }
public ICommand Option2Clicked { get; }
public ICommand Option3Clicked { get; }
public ICommand Option4Clicked { get; }
private string myQuestion;
public event PropertyChangedEventHandler PropertyChanged;
public string Question
{
get { return myQuestion; }
set
{
myQuestion = value;
NotifyPropertyChanged();
}
}
public _4OptionQuizPage() : this($"Question Loaded At {DateTime.Now}, this can be anything.")
{
}
public _4OptionQuizPage(string theCustomData)
{
InitializeComponent();
Question = theCustomData;
this.DataContext = this;
this.Option1Clicked = new SimpleCommand(OnOption1Clicked);
this.Option2Clicked = new SimpleCommand(OnOption2Clicked);
this.Option3Clicked = new SimpleCommand(OnOption3Clicked);
this.Option4Clicked = new SimpleCommand(OnOption4Clicked);
}
private void OnOption4Clicked()
{
MessageBox.Show("Option 4 selected, Store the results");
}
private void OnOption3Clicked()
{
MessageBox.Show("Option 3 selected, Store the results");
}
private void OnOption1Clicked()
{
NavigationService.Instance.LoadView<LoginPage>();
}
private void OnOption2Clicked()
{
NavigationService.Instance.LoadViewWithCustomData<LoginPage>(new _4OptionQuizPage("A custom question to emulate custom data"));
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
最后,您的 MainWindow 將注冊 shell 並將用戶發送到 LoginPage,它的 XAML 文件中不應包含任何內容
public partial class MainWindow : Window, INotifyPropertyChanged
{
private object myShell;
public object TheShell
{
get { return myShell; }
set
{
myShell = value;
this.NotifyPropertyChanged();
}
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
NavigationService.Instance.RegisterShell(this);
NavigationService.Instance.LoadView<LoginPage>();
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
MainWindow.xaml 應該是空的,本質上是一個 shell 用於其他所有內容。
<Window x:Class="Navigation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Navigation"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Content="{Binding TheShell}">
</Window>
如何讓視圖 model 參與頁面導航有很多方法。
一般情況下,每個參與導航的class都必須訪問你的導航API。
例如,您可以將導航邏輯移動到專用的 class NavigationService
並提供對每個應該能夠導航到不同視圖的 class 的共享引用。
或者(推薦),您可以使用您在MainWindow
上處理的路由命令,然后將命令委托給MainViewModel
。
在這種情況下,每個按鈕都必須將目標作為CommandParameter
傳遞。 該解決方案允許特定視圖模型不直接參與導航。 您不需要用導航詳細信息污染您的視圖 model 類。
以下示例顯示如何使用RoutedCommand
從QuizView
導航到ResultView
。
MainViewModel.cs
MainViewModel
是唯一知道如何導航和了解相關細節的視圖 model class。
這實現了可擴展性,同時保持視圖 model 類的實現簡單。
通常,要啟用數據驗證,讓視圖模型實現INotifyDataErrorInfo
。
然后,您可以在允許離開頁面之前查詢INotifyDataErrorInfo.HasErrors
屬性。
class MainViewModel : ObservableObject
{
public object CurrentView { get; set; }
private Dictionary<Type, INotifyPropertyChanged> ViewModelMap { get; }
public MainViewModel()
{
this.ViewModelMap = new Dictionary<Type, INotifyPropertyChanged>
{
{ typeof(QuizVm), new QuizVm() },
{ typeof(ResultVm), new ResultVm() },
};
}
// Check if destination type is valid.
// In case the navigation source implements INotifyDataErrorInfo,
// check if the source is in a valid state (INotifyDataErrorInfo.HasEWrrors returns 'false').
// This method is called by the view. It will delegate its ICommand.CanExecute to this method
// If this method returns 'false' the command source e.g. Button will be disabled.
public bool CanNavigate(Type navigationSourceType, Type navigationDestinationType)
=> CanNavigateAwayFrom(navigationSourceType)
&& CanNavigateTo(navigationDestinationType);
private bool CanNavigateAwayFrom(Type navigationSourceType)
=> this.ViewModelMap.TryGetValue(navigationSourceType, out INotifyPropertyChanged viewModel)
&& viewModel is INotifyDataErrorInfo notifyDataErrorInfo
? !notifyDataErrorInfo.HasErrors
: true;
private bool CanNavigateTo(Type navigationDestinationType)
=> this.ViewModelMap.ContainsKey(navigationDestinationType);
// This method is called by the view. It will delegate its ICommand.Execute to this method
public void NavigateTo(Type destinationType)
{
if (this.ViewModelMap.TryGetValue(destinationType, out INotifyPropertyChanged viewModel))
{
this.CurrentView = viewModel;
}
}
}
MainWindow.xaml.cs
partial class MainWindow : Window
{
public static RoutedCommand NavigateCommand { get; } = new RoutedUICommand(
"Navigate to view command",
nameof(NavigateCommand),
typeof(MainWindow));
private MainViewModel MainViewModel { get; }
public MainWindow()
{
InitializeComponent();
this.MainViewModel = new MainViewModel();
this.DataContext = this.MainViewModel;
var navigateCommandBinding = new CommandBinding(MainWindow.NavigateCommand, ExecuteNavigateCommand, CanExecuteNavigateCommand);
this.CommandBindings.Add(navigateCommandBinding);
}
private void CanExecuteNavigateCommand(object sender, CanExecuteRoutedEventArgs e)
{
if (e.Source is not FrameworkElement commandSource)
{
return;
}
Type navigationSourceType = commandSource.DataContext.GetType();
Type navigationDestinationType = (Type)e.Parameter;
e.CanExecute = this.MainViewModel.CanNavigate(navigationSourceType, navigationDestinationType);
}
private void ExecuteNavigateCommand(object sender, ExecutedRoutedEventArgs e)
{
var destinationViewModelType = (Type)e.Parameter;
this.MainViewModel.NavigateTo(destinationViewModelType);
}
}
主窗口.xaml
要實際呈現視圖(例如自定義控件),您需要定義一個隱式DataTemplate
(沒有x:Key
指令),它具有關聯視圖 model class 作為DataType
。 然后, ContentControl
將自動選擇與ContentControl.Content
屬性值的類型相匹配的正確類型。
<Window>
<Window.Resources>
<DataTemplate DataType="{x:Type local:QuizVM}">
<QuizView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ResultVM}">
<ResultView />
</DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding CurrentView}" />
</Window>
如果視圖需要導航,它必須使用 static 路由命令(在MainWindow
中定義和處理)並將目標視圖 model 的Type
作為CommandParameter
傳遞。
這樣,導航就不會污染視圖模型並停留在視圖內。
QuizView.xaml
<QuizView>
<Button Content="Next"
Command="{x:Static local:MainWindow.NextPageCommand}"
CommandParameter="{x:Type local:ResultVM}"/>
</QuizView>
結果視圖.xaml
<ResultView>
<Button Content="Back"
Command="{x:Static local:MainWindow.NextPageCommand}"
CommandParameter="{x:Type local:QuizVM}"/>
</ResultView>
因為視圖model類一般不直接參與導航,
他們不必執行任何相關命令或依賴任何導航服務。
導航完全由MainWindow
及其MainViewModel
控制。
對於可選的數據驗證,讓他們實施INotifyDataErrorInfo
。
QuizVM.cs
class QuizVM : INotifyPropertyChnaged, INotifyDataErrorInfo
{
}
結果VM.cs
class ResultVM : INotifyPropertyChnaged, INotifyDataErrorInfo
{
}
此示例演示了兩種導航方法。 通常很有用,因為您說要從登錄開始,但在用戶登錄之前不顯示任何菜單等。然后一旦他們登錄,您需要某種菜單或視圖列表,他們可以導航到仍然是 static。
我的主窗口純粹是一個包含所有內容的 shell。
它的標記是:
<Window ......
Title="{Binding Title}"
Content="{Binding}"
/>
此示例首先對所有導航使用 viewmodel。 視圖模型被模板化到 UI 中。
后面的代碼還有更多。
public partial class LoginNavigationWindow : Window
{
public Type ParentViewModel
{
get { return (Type)GetValue(ParentViewModelProperty); }
set { SetValue(ParentViewModelProperty, value); }
}
public static readonly DependencyProperty ParentViewModelProperty =
DependencyProperty.Register(name: "ParentViewModel",
propertyType: typeof(Type),
ownerType: typeof(LoginNavigationWindow),
typeMetadata: new FrameworkPropertyMetadata(
defaultValue: null,
propertyChangedCallback: new PropertyChangedCallback(ParentViewModelChanged)
));
private static void ParentViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var vm = Activator.CreateInstance((Type)e.NewValue);
((Window)d).DataContext = vm;
Task.Run(((IInitiatedViewModel)vm).Initiate);
}
public LoginNavigationWindow()
{
InitializeComponent();
WeakReferenceMessenger.Default.Register<ParentNavigate>(this, (r, pn) =>
{
this.SetValue(LoginNavigationWindow.ParentViewModelProperty, pn.ParentViewModelType);
});
}
Messenger 注冊將使用依賴屬性切換出窗口的數據上下文。 該消息只是一個 class 具有傳遞類型的屬性
public class ParentNavigate
{
public Type ParentViewModelType { get; set; }
}
回調 ParentViewModelChanged 采用一個類型,將其實例化並在 window 上設置數據上下文。
通常,您對保留 window 或父級視圖的 state 不感興趣。 您已經登錄。如果您想重新登錄,您將重新開始並輸入用戶名和密碼。
入口點有點不尋常,因為我處理應用程序啟動並依賴於該依賴屬性回調。
private void Application_Startup(object sender, StartupEventArgs e)
{
var mw = new LoginNavigationWindow();
mw.Show();
mw.SetValue(LoginNavigationWindow.ParentViewModelProperty, typeof(LoginViewModel));
}
而不是一個充滿菜單等的主窗口,我當然什么也沒有。
我有一個 LoginUC 是您將在啟動時看到的第一件事。 這只是說明性的。
在真正的應用程序中導航之前,我們將從用戶那里獲取輸入並對其進行驗證。 我們只是對這里的導航感興趣,所以這個版本只有一個按鈕可以導航到 MainViewModel:
<Grid>
<StackPanel>
<TextBlock Text="Log in"/>
<Button Content="Go"
Command="{Binding LoadMainCommand}"/>
</StackPanel>
</Grid>
</UserControl>
我的 LoginViewModel 有命令、標題和任務。
public partial class LoginViewModel : BaseParentViewModel
{
[RelayCommand]
private async Task LoadMain()
{
var pn = new ParentNavigate{ ParentViewModelType = typeof(MainViewModel) };
WeakReferenceMessenger.Default.Send(pn);
}
public LoginViewModel()
{
Title = "Please Log In first";
}
public override async Task Initiate()
{
// Get any data for login here
}
}
基礎父視圖模型
public partial class BaseParentViewModel : ObservableObject, IInitiatedViewModel
{
[ObservableProperty]
private string title = string.Empty;
virtual public async Task Initiate() { }
}
界面
public interface IInitiatedViewModel
{
Task Initiate();
}
此接口的目的是為我們提供一種通用方法,讓任何視圖模型都能獲取所需的任何數據。 通過設置數據上下文,然后啟動一個后台線程來獲取該數據,視圖將快速出現,然后填充它需要的任何數據。 如果獲取該數據需要一段時間,那么至少在任務仍在繼續工作的同時視圖是“向上”並且快速可見的。
在一個更完整的示例中,我們將在基礎視圖模型中使用 IsBusy,它將從 true 開始並更改為 false。 這將在視圖中驅動一個“throbber”或總線指示器。
資源字典使用數據類型將視圖模型數據模板與用戶控件相關聯:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LoginNavigation"
>
<DataTemplate DataType="{x:Type local:MainViewModel}">
<local:MainUC/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:LoginViewModel}">
<local:LoginUC/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:SubjectsViewModel}">
<local:SubjectsView/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ResultViewModel}">
<local:ResultView/>
</DataTemplate>
</ResourceDictionary>
即合並到 app.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources/ViewDataTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
登錄后,window 的全部內容將被替換。 數據上下文從 LoginViewModel 更改為 MainViewModel,然后模板化到 MainUC 中:
public partial class MainViewModel : BaseParentViewModel
{
[ObservableProperty]
private object currentChildViewModel;
[ObservableProperty]
private List<ChildViewModel> childViewModelList;
[RelayCommand]
private async Task ChildNavigation(ChildViewModel cvm)
{
if (cvm.Instance == null)
{
cvm.Instance = Activator.CreateInstance(cvm.ViewModelType);
if (cvm.Instance is IInitiatedViewModel)
{
Task.Run(((IInitiatedViewModel)cvm.Instance).Initiate);
}
}
CurrentChildViewModel = cvm.Instance;
}
public override async Task Initiate()
{
ChildViewModelList = new List<ChildViewModel>()
{
new ChildViewModel{ DisplayName="Subjects", ViewModelType= typeof(SubjectsViewModel) },
new ChildViewModel{ DisplayName="Results", ViewModelType= typeof(ResultViewModel) }
};
}
public MainViewModel()
{
Title = "Quiz";
}
}
當然,您可能希望有更多視圖並選擇一個最初顯示,這將在 Initiate 中設置。
主要UC:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding ChildViewModelList}"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Content="{Binding DisplayName}"
Command="{Binding DataContext.ChildNavigationCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"
CommandParameter="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ContentPresenter Content="{Binding CurrentChildViewModel}"
Grid.Column="1"/>
</Grid>
</UserControl>
在視圖中,您會在左列中獲得一個按鈕列表,這些按鈕將允許在右列中導航。 但當然要保留 MainUC。
這可以是菜單或選項卡控件,而不是列表框。
單擊按鈕會調用 MainViewModel 中的命令,並將 ChildViewModel 的實例作為參數傳遞。
然后用於實例化視圖模型、設置 CurrentChildViewmodel 並緩存實例。
CurrentChildViewmodel 本身當然會被模板化到 MainUC 中的用戶控件中。
public partial class ChildViewModel : ObservableObject
{
public string DisplayName { get; set; }
public Type ViewModelType { get; set; }
public object Instance { get; set; }
}
這是一種相當簡單的方法,在現實世界中,您可能需要依賴注入、工廠等大量應用程序。 但這已經是 Stack Overflow 答案的相當多的代碼了。
其余的視圖模型和視圖只是簡單的實現,以證明它一切正常。 例如
public partial class SubjectsViewModel : ObservableObject, IInitiatedViewModel
{
public async Task Initiate()
{
// Get any data for Subjects here
}
}
和
<Grid>
<TextBlock Text="Subjects"/>
</Grid>
</UserControl>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.