页面(视图)之间的 C# WPF 导航 [英] C# WPF Navigation Between Pages (Views)

查看:25
本文介绍了页面(视图)之间的 C# WPF 导航的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个类 &可以在任何窗口和页面上使用的方法来更改 MainWindow 窗口中显示的当前页面.

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 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.StackOverflowException 结束.

Unfortunately this ends up with System.StackOverflowException.

创建它的主要原因是我希望能够从当前显示在 mainWindow.Content 中的页面更改 mainWindow.Content.

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.

我已经审查了 MVVM,但我认为不值得将它用于像这样的小应用程序,因为我想要它做的就是在打开时显示一个欢迎页面,然后在侧面会有几个按钮.一旦按下 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. 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.

推荐答案

使用 MVVM 绝对没问题,因为它可以简化您的需求的实现.WPF 是为与 MVVM 模式一起使用而构建的,这意味着大量使用数据绑定和数据模板.

Using MVVM is absolutely fine as it will simplify the implementation of your requirement. WPF is build to be used with the MVVM pattern, which means to make heavy use of data binding and data templates.

任务很简单.为每个视图创建一个 UserControl(或 DataTemplate),例如 WelcomePageLoginPage 及其对应的视图模型 WelcomePageViewModelLoginPageViewModel.

The task is quite simple. Create a UserControl (or DataTemplate) for each view e.g., WelcomePage and LoginPage with their corresponding view models WelcomePageViewModel and LoginPageViewModel.

ContentControl 将显示页面.
主要技巧是,当使用隐式 DataTemplate(没有定义 x:Key 的模板资源)时,XAML 解析器将自动查找并应用正确的模板,其中DataType 匹配 ContentControl 的当前内容类型.这使导航变得非常简单,因为您只需从页面模型集合中选择当前页面,并通过数据绑定将此页面设置为 ContentControlContent 属性或ContentPresenter:

A ContentControl will display the pages.
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. 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:

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>

实施

  1. 创建页面控件.这可以是 ControlUserControlPage 或只是一个 DataTemplate
  1. Create the page controls. This can be a Control, UserControl, Page or simply a 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>

  1. 创建页面模型

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));
      }
    }

  1. 创建页面标识符的枚举(以消除 XAML 和 C# 中的魔法字符串)

PageName.cs

    public enum PageName
    {
      Undefined = 0, WelcomePage, LoginPage
    }

  1. 创建将管理页面及其导航的 MainViewModel

MainViewModel.cs
RelayCommand 的实现可以在
Microsoft Docs:模式 - 具有模型-视图-视图模型设计模式的 WPF 应用程序 - 中继命令逻辑

MainViewModel.cs
An implementation of RelayCommand can be found at
Microsoft Docs: Patterns - WPF Apps With The Model-View-ViewModel Design Pattern - 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));
    }

这篇关于页面(视图)之间的 C# WPF 导航的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆