主要讲一下如何通过点击菜单,实现动态加载TabControl的功能,准确来说应该是动态加载TabItem,要实现这个功能,我们需要解决两个问题:

  1. 点击菜单的时候,需要传进来一个你要加载的UserControl控件的名称,让程序知道你要加载的是哪个控件。
  2. 通过传进来的UserControl控件名实例化UserControl控件(利用反射来实例化UserControl控件)。

关于第一点,我通过在数据库菜单表加一个字段Code,用来保存UserControl控件的名称,然后在加载菜单的时候,给菜单的Name赋上Code的值,关于动态加载菜单可以看我上一篇博客。

在xaml添加一个 Name ="TabControl" TabControl

CS后台代码:

我们在添加菜单的时候,根据菜单的Name值是否为空,给菜单添加点击事件

        /// <summary>
        /// 添加菜单的点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Item_Click(object sender, RoutedEventArgs e)
            MenuItem item = sender as MenuItem;
            bool isExist = false;
            foreach (TabItem tab in this.TabControl.Items)
                //如果已经存在这个TabItem,就把焦点设置到这个TabItem上
                if (tab.Header == item.Header)
                    isExist = true;
                    tab.Focus();
            //如果不存就添加一个TabItem
            if (!isExist)
                //获取命名空间名称(这个名称一定要完整)
                string str = string.Format("WPFTest.{0}", item.Name);
                UserControl userControl = ReflectionHelper.CreateInstance<UserControl>(str, "WPFTest");//程序集名称
                TabItem tabItem = new TabItem()
                    Header = item.Header,
                    Name = item.Name
                tabItem.Content = userControl;
                this.TabControl.Items.Add(tabItem);
                tabItem.Focus();

添加一个反射帮助类ReflectionHelper,在里面添加一个创建对象实例的方法CreateInstance:

        /// <summary>
        /// 创建对象的实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fullName">命名空间.类名</param>
        /// <param name="assemblyName">程序集名称</param>
        /// <returns></returns>
        public static T CreateInstance<T>(string fullName, string assemblyName)
            //命名空间.类名,程序集名称
            string path = fullName + "," + assemblyName;
            //获取加载类型
            Type o = Type.GetType(path);
            //根据类型创建实例
            object obj = Activator.CreateInstance(o, true);
            //类型转换并返回
            return (T)obj;

这样我们就可以动态的实例化UserControl控件对象,实现动态加载TabItem的功能了。

为了方便理解,补上完整代码:

        public MainWindow()
            InitializeComponent();
            LoadSystemMenu();
        /// <summary>
        /// 加载菜单
        /// </summary>
        public void LoadSystemMenu()
            //查询出数据库所有的菜单数据
            DataTable dataTable = model.GetSystemMenu();
            //筛选出上级ID为空的数据(一级菜单)
            DataRow[] dataRows = dataTable.Select("SuperiorID is null");
            //用来存放一级菜单
            List<MenuItem> menuItems = new List<MenuItem>();
            foreach (DataRow item in dataRows)
                MenuItem menu = new MenuItem();
                menu.Header = item["Name"].ToString();
                menu.Name = item["Code"].ToString();//UserControl控件名称
                menu.RenderSize = new Size(100, 25);
                //如果Code不为空,就添加点击事件
                if (!string.IsNullOrWhiteSpace(item["Code"].ToString())) menu.Click += Item_Click;
                //添加子菜单
                AddChildMenu(menu, item["ID"].ToString(), dataTable);
                menuItems.Add(menu);
            //把一级菜单绑定到菜单栏
            foreach (MenuItem item in menuItems)
                this.SystemMenu.Items.Add(item);
        /// <summary>
        /// 添加子菜单
        /// </summary>
        /// <param name="menu"></param>
        /// <param name="superiorId"></param>
        /// <param name="dataTable"></param>
        private void AddChildMenu(MenuItem menu, string superiorId, DataTable dataTable)
            //筛选出上级菜单ID等于传进来的菜单ID的数据(子菜单)
            DataRow[] dataRows = dataTable.Select("SuperiorID =" + superiorId);
            foreach (DataRow item in dataRows)
                MenuItem menuItem = new MenuItem();
                menuItem.Header = item["Name"].ToString();
                menuItem.Name = item["Code"].ToString();//UserControl控件名称
                menuItem.RenderSize = new Size(100, 25);
                if (!string.IsNullOrWhiteSpace(item["Code"].ToString())) menuItem.Click += Item_Click;
                //绑定子菜单
                menu.Items.Add(menuItem);
                AddChildMenu(menuItem, item["ID"].ToString(), dataTable);
        /// <summary>
        /// 添加菜单的点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Item_Click(object sender, RoutedEventArgs e)
            MenuItem item = sender as MenuItem;
            bool isExist = false;
            foreach (TabItem tab in this.TabControl.Items)
                //如果已经存在这个TabItem,就把焦点设置到这个TabItem上
                if (tab.Header == item.Header)
                    isExist = true;
                    tab.Focus();
            //如果不存就添加一个TabItem
            if (!isExist)
                //获取命名空间名称(这个名称一定要完整)
                string str = string.Format("WPFTest.{0}", item.Name);
                UserControl userControl = ReflectionHelper.CreateInstance<UserControl>(str, "WPFTest");//程序集名称
                TabItem tabItem = new TabItem()
                    Header = item.Header,
                    Name = item.Name
                tabItem.Content = userControl;
                this.TabControl.Items.Add(tabItem);
                tabItem.Focus();
                                    这些控件都是用于在WPF应用程序中呈现数据的控件。它们之间的主要区别在于其用途、功能、视觉外观和自定义选项。可以根据的需求和数据类型来选择适当的控件:如果需要简单地显示一个数据项集合,则可以使用ItemsControl或ListView;如果需要支持选择功能,则可以使用ListBox;如果需要以表格形式查看或编辑数据,则应该使用DataGrid;如果需要显示具有层次结构的数据,则应该使用TreeView;如果需要将不同视图放在不同选项卡页面上,则应该使用TabControl。
<DataGrid x:Name="dataGrid" Margin="0,52,0,65" AutoGenerateColumns="False" LoadingRow="dataGrid_LoadingRow"...
                                    原因:切换选项卡时会卸载TabItem内的用户控件,再次点击时会重新加载用户控件,如果主要的逻辑代码位于用户控件的Loaded事件中,将会再执行一遍,导致缓慢。
解决方案:将Loaded事件内的代码移至初始化控件中
言归正传,所谓动态加载DataGrid就是说表头和数据都是动态生成出来的,不是预先设置好的值。
在网上也找了很久这方面的资料,然后功夫不负有心人还是找到了,然后写一下自己在做的过程中的一些方法和心得。
先说明我没有用WPF的MVVM模式做。
首先需要先在页面上放一个空的DataGrid
 <DataGrid x:Name="DataGrids" >
          <DataGrid.Columns>
                                    //tCLayerParaSet为tableControl
 string pageTitle = "工艺" + showlayerIDs[iLayer].ToString();
 TabPage curTabPage = new TabPage(pageTitle);
 curTabPage.Name = pageTitle;
 tCLayerParaSet.TabPages.Add(curTabPage);
 //要添加的TAB页页面form,需在设计窗口设置formbodorStyle为None..