页面(视图)之间的 C# WPF 导航
Posted
技术标签:
【中文标题】页面(视图)之间的 C# WPF 导航【英文标题】:C# WPF Navigation Between Pages (Views) 【发布时间】:2020-08-02 20:23:50 【问题描述】:我正在尝试创建一个可以在任何窗口和页面上使用的类和方法,以更改 MainWindow 窗口上显示的当前页面。
到目前为止,我得到了:
class MainWindowNavigation : MainWindow
public MainWindow mainWindow;
public void ChangePage(Page page)
mainWindow.Content = page;
主窗口本身:
public MainWindow()
InitializeComponent();
MainWindowNavigation mainWindow = new MainWindowNavigation();
mainWindow.ChangePage(new Pages.MainWindowPage());
不幸的是,这以 System.***Exception 告终。
创建它的主要原因是我希望能够从当前显示在 mainWindow.Content 中的页面更改 mainWindow.Content。
我已经审查过 MVVM,但我认为它不值得将它用于像这样的小型应用程序,因为我想要它做的只是在打开时显示一个欢迎页面,然后在侧面会有几个按钮。一旦按下 mainWindow.Content 正确更改为用户可以输入登录详细信息的页面,然后在登录页面上按下按钮,我想在成功验证输入的登录详细信息后将 mainWindow.Content 更改为不同的页面。
【问题讨论】:
【参考方案1】:使用 MVVM 绝对没问题,因为它将简化您的需求的实现。 WPF 是为与 MVVM 模式一起使用而构建的,这意味着大量使用数据绑定和数据模板。
任务很简单。为每个视图创建一个UserControl
(或DataTemplate
),例如WelcomePage
和LoginPage
及其对应的视图模型WelcomePageViewModel
和LoginPageViewModel
。
ContentControl
将显示页面。
主要技巧是,当使用隐式 DataTemplate
(未定义 x:Key
的模板资源)时,XAML 解析器将自动查找并应用正确的模板,其中 DataType
匹配 @ 的当前内容类型987654332@。这使导航变得非常简单,因为您只需从页面模型集合中选择当前页面并通过数据绑定将此页面设置为ContentControl
或ContentPresenter
的Content
属性:
用法
MainWindow.xaml
<Window>
<Window.DataContext>
<MainViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="x:Type WelcomePageviewModel">
<WelcomPage />
</DataTemplate>
<DataTemplate DataType="x:Type LoginPageviewModel">
<LoginPage />
</DataTemplate>
</Window.Resources>
<StackPanel>
<!-- Page navigation -->
<StackPanel Orientation="Horizontal">
<Button Content="Show Login Screen"
Command="Binding SelectPageCommand"
CommandParameter="x:Static PageName.LoginPage" />
<Button Content="Show Welcome Screen"
Command="Binding SelectPageCommand"
CommandParameter="x:Static PageName.WelcomePage" />
</StackPanel>
<!--
Host of SelectedPage.
Automatically displays the DataTemplate that matches the current data type
-->
<ContentControl Content="Binding SelectedPage" />
<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.csRelayCommand
的实现可以在Microsoft Docs:模式 - 具有模型-视图-视图模型设计模式的 WPF 应用程序 - Relaying Command Logic
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));
【讨论】:
每次我必须使用 WPF 做某事时,我都会一遍又一遍地回到这个问题上。这是一个非常好的起点教程。【参考方案2】:您可能希望将MainWindowNavigation
定义为一个静态类,其方法只需更改当前MainWindow
的Content
:
static class MainWindowNavigation
public static void ChangePage(Page page)
var mainWindow = Application.Current.Windows.OfType<MainWindow>().FirstOrDefault();
if (mainWindow != null)
mainWindow.Content = page;
然后您可以从任何类调用该方法,而无需引用MainWindow
:
MainWindowNavigation.ChangePage(new Pages.MainWindowPage());
【讨论】:
以上是关于页面(视图)之间的 C# WPF 导航的主要内容,如果未能解决你的问题,请参考以下文章