简体   繁体   English

C# WPF 页面导航 Class

[英]C# WPF Page Navigation Class

I'm attempting to create a class & method which could be used on any window and page to change the current page displayed on the MainWindow window.我正在尝试创建一个 class & 方法,该方法可用于任何 window 和页面以更改 MainWindow window 上显示的当前页面。

So far I got:到目前为止,我得到了:

class MainWindowNavigation : MainWindow
{
    public MainWindow mainWindow;

   public void ChangePage(Page page)
    {
        mainWindow.Content = page;
    }
}

The main window itself:主要的 window 本身:

public MainWindow()
    {
        InitializeComponent();
        MainWindowNavigation mainWindow = new MainWindowNavigation();
        mainWindow.ChangePage(new Pages.MainWindowPage());
    }

Unfortunately this ends up with System.StackOverflowException.不幸的是,这以 System.StackOverflowException 告终。

The main reason for creating this is that I want to be able to change the mainWindow.Content from a page which is currently displayed in mainWindow.Content.创建它的主要原因是我希望能够从当前显示在 mainWindow.Content 中的页面更改 mainWindow.Content。

I have already reviewed MVVM but I don't think it is worth using it for a small application like this as all I want it to do is Display a Welcome Page on open, then on the side there will be few buttons.我已经审查了 MVVM,但我认为它不值得将它用于像这样的小型应用程序,因为我想要它做的只是在打开时显示一个欢迎页面,然后在侧面会有几个按钮。 Once pressed the mainWindow.Content correctly changes to a page where a user can enter login detail and then on the button press on the login page I want to change the mainWindow.Content to a different page on successful validation of the login details entered.一旦按下 mainWindow.Content 正确更改为用户可以输入登录详细信息的页面,然后在登录页面上按下按钮,我想在成功验证输入的登录详细信息后将 mainWindow.Content 更改为不同的页面。

Using MVVM is absolutely fine as it will simplify the implementation of your requirement.使用 MVVM 绝对没问题,因为它将简化您的需求的实现。 WPF is build to be used with the MVVM pattern, which means to make heavy use of data binding and data templates. WPF 是为与 MVVM 模式一起使用而构建的,这意味着大量使用数据绑定和数据模板。

The task is quite simple.任务很简单。 Create a UserControl (or DataTemplate ) for each view eg, WelcomePage and LoginPage with their corresponding view models WelcomePageViewModel and LoginPageViewModel .为每个视图创建一个UserControl (或DataTemplate ),例如WelcomePageLoginPage及其对应的视图模型WelcomePageViewModelLoginPageViewModel

A ContentControl will display the pages. ContentControl将显示页面。
The main trick is that, when using an implicit DataTemplate (a template resource without an x:Key defined), the XAML parser will automatically lookup and apply the correct template, where the DataType matches the current content type of a ContentControl .主要技巧是,当使用隐式DataTemplate (未定义x:Key的模板资源)时,XAML 解析器将自动查找并应用正确的模板,其中DataTypeContentControl的当前内容类型匹配。 This makes navigation very simple, as you just have to select the current page from a collection of page models and set this page via data binding to the Content property of the ContentControl or ContentPresenter :这使得导航非常简单,因为您只需从页面模型集合中 select 当前页面,并通过数据绑定到ContentControlContentPresenterContent属性设置此页面:

Usage用法

MainWindow.xaml主窗口.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>

Implementation执行

  1. Create the page controls.创建页面控件。 This can be a Control , UserControl , Page or simply a DataTemplate这可以是ControlUserControlPage或只是一个DataTemplate

    WelcomePage.xaml WelcomePage.xaml

     <UserControl> <StackPanel> <TextBlock Text="{Binding PageTitle}" /> <TextBlock Text="{Binding Message}" /> </StackPanel> </UserControl>

    LoginPage.xaml登录页面.xaml

     <UserControl> <StackPanel> <TextBlock Text="{Binding PageTitle}" /> <TextBox Text="{Binding UserName}" /> </StackPanel> </UserControl>
  2. Create the page models创建页面模型

    IPage.cs网页文件

    interface IPage: INotifyPropertyChanged { string PageTitel { get; set; } }

    WelcomePageViewModel.cs 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 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)); } }
  3. Create an enumeration of page identifiers (to eliminate magic strings in XAML and C#)创建页面标识符的枚举(以消除 XAML 和 C# 中的魔术字符串)

    PageName.cs页面名称.cs

     public enum PageName { Undefined = 0, WelcomePage, LoginPage }
  4. Create the MainViewModel which will manage the pages and their navigation创建将管理页面及其导航的MainViewModel

    MainViewModel.cs主视图模型.cs
    An implementation of RelayCommand can be found at RelayCommand的实现可以在以下位置找到
    Microsoft Docs: Patterns - WPF Apps With The Model-View-ViewModel Design Pattern - Relaying Command Logic Microsoft Docs:模式 - WPF 具有模型-视图-视图模型设计模式的应用程序 - 中继命令逻辑

    class MainViewModel { public ICommand SelectPageCommand => new RelayCommand(SelectPage); public 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)); } }

You probably want to define MainWindowNavigation as a static class with a method that simply changes the Content of the current MainWindow :您可能希望使用简单地更改当前MainWindowContent的方法将MainWindowNavigation定义为 static class :

static class MainWindowNavigation
{
    public static void ChangePage(Page page)
    {
        var mainWindow = Application.Current.Windows.OfType<MainWindow>().FirstOrDefault();
        if (mainWindow != null)
            mainWindow.Content = page;
    }
}

You can then call the method from any class without having a reference to the MainWindow :然后,您可以从任何 class 调用该方法,而无需引用MainWindow

MainWindowNavigation.ChangePage(new Pages.MainWindowPage());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM