使用MVVM是完全可以的,因为它将简化您对需求的实现。WPF是设计用来配合MVVM模式的,这意味着要大量使用数据绑定和数据模板。
任务相当简单。为每个视图创建一个(或),例如和,以及它们对应的视图模型和。
将显示网页。
主要的技巧是,在使用隐式(没有定义的模板资源)时,XAML解析器会自动查找并应用正确的模板,其中匹配的当前内容类型。这使得导航非常简单,因为您只需要从页面模型集合中选择当前页面并将此页面通过数据绑定设置到或的属性中:
用法
MainWindow.xaml
<Window>
<Window.DataContext>
<MainViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="">
<WelcomPage />
</DataTemplate>
<DataTemplate DataType="">
<LoginPage />
</DataTemplate>
</Window.Resources>
<StackPanel>
<!-- Page navigation -->
<StackPanel Orientation="Horizontal">
<Button Content="Show Login Screen"
Command=""
CommandParameter="" />
<Button Content="Show Welcome Screen"
Command=""
CommandParameter="" />
</StackPanel>
<!--
Host of SelectedPage.
Automatically displays the DataTemplate that matches the current data type
-->
<ContentControl Content="" />
<StackPanel>
</Window>
实现
- 创建单个页面控件(承载页面内容的控件)。可以使用
Control
、UserControl
、Page
或者简单的 DataTemplate
:
WelcomePage.xaml
<UserControl>
<StackPanel>
<TextBlock Text="{Binding PageTitle}" />
<TextBlock Text="{Binding Message}" />
</StackPanel>
</UserControl>
LoginPage.xaml
<UserControl>
<StackPanel>
<TextBlock Text="{Binding PageTitle}" />
<TextBox Text="{Binding UserName}" />
</StackPanel>
</UserControl>
- 创建页面模型:
IPage.cs
interface IPage : INotifyPropertyChanged
{
string PageTitel { get; set; }
}
WelcomePageViewModel.cs
class WelcomePageViewModel : IPage
{
private string pageTitle;
public string PageTitle
{
get => this.pageTitle;
set
{
this.pageTitle = value;
OnPropertyChanged();
}
}
private string message;
public string Message
{
get => this.message;
set
{
this.message = value;
OnPropertyChanged();
}
}
public WelcomePageViewModel()
{
this.PageTitle = "Welcome";
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
LoginPageViewModel.cs
class LoginPageViewModel : IPage
{
private string pageTitle;
public string PageTitle
{
get => this.pageTitle;
set
{
this.pageTitle = value;
OnPropertyChanged();
}
}
private string userName;
public string UserName
{
get => this.userName;
set
{
this.userName = value;
OnPropertyChanged();
}
}
public LoginPageViewModel()
{
this.PageTitle = "Login";
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
- 创建页面标识符的枚举(用于消除XAML和C#中的魔法字符串):
PageName.cs
public enum PageName
{
Undefined = 0, WelcomePage, LoginPage
}
- 创建
MainViewModel
,用于管理页面和导航:
MainViewModel.cs
可以在Microsoft Docs:模式-WPF应用程序使用模型-视图-视图模型设计模式- 中找到RelayCommand
的实现。
class MainViewModel
{
public ICommand SelectPageCommand => new RelayCommand(SelectPage);
private Dictionary<PageName, IPage> Pages { get; }
private IPage selectedPage;
public IPage SelectedPage
{
get => this.selectedPage;
set
{
this.selectedPage = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
this.Pages = new Dictionary<PageName, IPage>
{
{ PageName.WelcomePage, new WelcomePageViewModel() },
{ PageName.LoginPage, new LoginPageViewModel() }
};
this.SelectedPage = this.Pages.First().Value;
}
public void SelectPage(object param)
{
if (param is PageName pageName
&& this.Pages.TryGetValue(pageName, out IPage selectedPage))
{
this.SelectedPage = selectedPage;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}