WPF多页面切换的实现方法

摘要

C/S端软件,左侧导航菜单+右侧页面切换的布局很常见。
这篇文章介绍下使用ContentControl控件和TabControl控件如何实现基础的页面切换。

一、使用ContentControl实现页面切换

页面使用UserControl来实现。

基于MVVM框架的思想,利用数据绑定机制,将控件集合绑定到ContentControl的数据源中。

ViewModel中定义UIElement类型变量和OpenPageCommand触发命令,代码如下:

public  class MainViewModel:INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;
        public Dictionary<string, UIElement> PageDict { get; set; } = new Dictionary<string, UIElement>();
        public UIElement MainContent { get; set; }
        public Command OpenPageCommand { get; set; }
        public MainViewModel()
        {
            OpenPageCommand = new Command(OpenPage);
        }
        private void OpenPage(object o)
        {
            //反射创建
            Type type=Assembly.GetExecutingAssembly().GetType("WpfApp1.Pages."+o.ToString());
            //避免重复创建UIElement实例
            if (!PageDict.ContainsKey(o.ToString()))
            {
                PageDict.Add(o.ToString(), (UIElement)Activator.CreateInstance(type));
            }
            MainContent = PageDict[o.ToString()];
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MainContent"));
        }
        public void DoCloseCommand(object obj)
        {
            Pages.Remove(obj as PageModel);
        }
        public ObservableCollection<PageModel> Pages { get; set; } = new ObservableCollection<PageModel>();
        public int PageSelectedIndex { get; set; }
    }

XAML中ContentControl绑定MainContent数据源,代码如下:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition  Width="100"/>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <StackPanel Grid.Column="0">
        <Button Content="pageA" Command="{Binding OpenPageCommand}" CommandParameter="PageA" />
        <Button Content="pageB" Command="{Binding OpenPageCommand}" CommandParameter="PageB" />
    </StackPanel>
    <ContentControl Grid.Column="1" Content="{Binding MainContent}" >        
    </ContentControl>    
</Grid>

效果如下

img

二、使用TabControl切换页面

TabControl控件可以在XAML中直接配置TabItem子控件,但是这种方式不适合工程实践。
更合理的方式是使用数据动态绑定的方式,来实现页面的切换。

TabItem样式改造

TabItem控件有Header属性,还有内容属性。其中Header属性默认为Text文本,实际应用中往往还需要关闭按钮,图标按钮等。

因此TabItem样式需要改造,以增加一个关闭按钮为例。

首先创建一个TabItem实体类PageModel.cs:

public  class PageModel
    {
        public string Key { get; set; }
        public string Text { get; set; }
        public UIElement Content { get; set; }
        public Command CloseCommand { get; set; }
    }

XAML中增加样式Resource

 <Window.Resources>
        <StackPanel Orientation="Horizontal" x:Key="headerObject" x:Shared="False">
            <TextBlock Text="{Binding Text}"/>
            <Button Content="X" Command="{Binding CloseCommand}" CommandParameter="{Binding}" />
        </StackPanel>
        <Style TargetType="TabItem">
            <Setter Property="Header" Value="{StaticResource headerObject}"/>
            <Setter Property="Content" Value="{Binding Content}"/>
        </Style>
    </Window.Resources>

XAML中TabControl调用:

<TabControl Grid.Column="2" ItemsSource="{Binding Pages}" SelectedIndex="{Binding PageSelectedIndex}">
</TabControl>

ViewModel中使用ObservableCollection集合作为TabItem数据集

    public ObservableCollection<PageModel> Pages { get; set; } = new ObservableCollection<PageModel>();
    public int PageSelectedIndex { get; set; }
    public MainViewModel()
    {
        OpenPageCommand = new Command(OpenPage);
    }
    private void OpenPage(object o)
    {
        Type type=Assembly.GetExecutingAssembly().GetType("WpfApp1.Pages."+o.ToString());
        //避免重复创建实例
        if (!Pages.ToList().Exists(x=>x.Text==o.ToString()))
        {
            Pages.Add(new PageModel() {
                Key = o.ToString(), Text = o.ToString(), Content = (UIElement)Activator.CreateInstance(type),
                CloseCommand=new Command(DoCloseCommand)
            });
        }
        PageSelectedIndex = Pages.ToList().FindIndex(x => x.Text == o.ToString());
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PageSelectedIndex"));
    }
    public void DoCloseCommand(object obj)
    {
        Pages.Remove(obj as PageModel);
    }

实现效果如下

img

三、总结

上面两种页面切换的方式,适合工程实践中需要设计单页面应用时使用。

源码地址https://github.com/cyberneo666/wpf_demo

posted @ 2022-11-13 21:04  cyberneo666  阅读(324)  评论(0编辑  收藏  举报