WPF控件之DataGrid扩展应用(一)

发布于:2022-12-30 ⋅ 阅读:(496) ⋅ 点赞:(0)

一、分析

        这次的需求是:有一所学校,为了方便了解学校里所有班级的情况(这里就看各位想定义哪些情况了),故需要设计出一个在界面上既能查看每个班级中每个学生的信息,又能展示每个班级的总体情况。

        我分析的是:结合前面所讲述的知识点,查看每个班级用TreeView,展示总体情况用DataGrid。那就动手看看吧

二、实现

        先看项目结构(注意个模块得统一:要么用core,要么用Framework)

 接下来逐一讲述

(1)common模块

        枚举(Enums):就一个枚举(节点类型)

    public enum NodeType
    {
        [Description("班级")]
        Grade,

        [Description("学生")]
        Student,
    }

        转换器(Converts):从枚举的值判断后返回是否显示(上代码)

    public class EnumToVisibilityConvert : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is Enum enumValue)
            {
                switch (enumValue)
                {
                    case NodeType.Grade:
                        return Visibility.Collapsed;
                    case NodeType.Student:
                        return Visibility.Visible;
                    default:
                        return Visibility.Collapsed;
                }
            }
            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
        }
    }

         命令(DelegateCommand),这个就不做概述了,之前用的都是它,不知道的可以看我前面的文章

        对象(Models):就一个主体对象,树结构加附属对象——学生结构(看代码,BindableObject不讲述了,跟命令一样的,前面文章有)

    public abstract class BaseModel : BindableObject
    {
        public virtual string Name { get;  set; }

        public virtual Guid Guid { get;  set; }

        public virtual NodeType Node { get;  set; } = NodeType.Grade;
    }

    public class TreeModel : BaseModel
    {
        private ObservableCollection<StudentInfo> student = new ObservableCollection<StudentInfo>();

        public ObservableCollection<StudentInfo> Student
        {
            get => student;
            set
            {
                student = value;
                OnPropertyChanged();
            }
        }

    }

 public class StudentInfo : BaseModel
    {
        private string gender;

        public string Gender
        {
            get => gender;
            set
            {
                gender = value;
                OnPropertyChanged();
            }
        }

        private int age;

        public int Age
        {
            get => age;
            set
            {
                age = value;
                OnPropertyChanged();
            }
        }

        private string address;

        public string Address
        {
            get => address;
            set
            {
                address = value;
                OnPropertyChanged();
            }
        }

        private string number;

        public string Number
        {
            get => number;
            set
            {
                number = value;
                OnPropertyChanged();
            }
        }

    }

        管理者(TreeViewManager):管理整个TreeView的逻辑交互(这次的封装不太好,大部分的逻辑,ViewModel那里就实现了,都没到这管理库来——哈哈哈,应该是我想偷懒,不想提取了)

 

public class TreeViewManager : TreeViewInterface
    {
		private static ObservableCollection<TreeModel> treeModels = new ObservableCollection<TreeModel>();

		public static ObservableCollection<TreeModel> TreeModels
        {
			get => treeModels;
			set
			{
                treeModels = value;
                OnTreeModelsChanged();
			}
		}

        public static event EventHandler TreeModelsChanged;
        public static void OnTreeModelsChanged()
        {
            TreeModelsChanged?.Invoke(TreeModels, new EventArgs());
        }

        public void InitTree()
        {
            TreeModel treeModel = new TreeModel()
            {
                Guid = Guid.NewGuid(),
                Name = "三年级二班",
                Node = Enums.NodeType.Grade
            };

            StudentInfo student = new StudentInfo()
            {
                Name = "小红",
                Guid = treeModel.Guid,
                Age = 8,
                Gender = "女",
                Address = "天河路",
                Node = Enums.NodeType.Student,
                Number = "111111"
            };

            treeModel.Student.Add(student);

            student = new StudentInfo()
            {
                Name = "小明",
                Guid = treeModel.Guid,
                Age = 8,
                Gender = "男",
                Address = "尧新路",
                Node = Enums.NodeType.Student,
                Number = "222222"
            };

            treeModel.Student.Add(student);

            student = new StudentInfo()
            {
                Name = "小黑",
                Guid = treeModel.Guid,
                Age = 7,
                Gender = "男",
                Address = "水西路",
                Node = Enums.NodeType.Student,
                Number = "333333"
            };

            treeModel.Student.Add(student);

            TreeModels.Add(treeModel);
        }

    }

(2)interface模块

        就一个,目录树的接口,对应一些方法(我这就只有一个方法。。。哈哈哈)

    public interface TreeViewInterface
    {
        void InitTree();
    }

(2)VM-V模块

        VM模块:一个是表格的,一个是目录树的,直接看代码吧

    public class DataGridViewModel : BindableObject
    {
		private TreeModel treeModel;

		public TreeModel TreeModel
        {
			get => treeModel;
			set
			{
                treeModel = value;
				OnPropertyChanged();
			}
		}

		public DataGridViewModel(TreeModel model)
        {
			this.TreeModel = model;
        }
    }

 public class TreeViewModel : BindableObject
    {
        private readonly TreeViewInterface @interface;

        public ObservableCollection<TreeModel> TreeModels => TreeViewManager.TreeModels;

        private TreeModel treeModel;

        public TreeModel TreeModel
        {
            get => treeModel;
            set
            {
                treeModel = value;
                OnPropertyChanged();
            }
        }


        private StudentInfo student;

        public StudentInfo Student
        {
            get => student;
            set
            {
                student = value;
                OnPropertyChanged();
            }
        }

        private BaseModel baseModel;

        public BaseModel BaseModel
        {
            get => baseModel;
            set
            {
                baseModel = value;
                OnPropertyChanged();
            }
        }

        public DelegateCommand<TreeView> SelectChangeCommand { get; private set; }

        public DelegateCommand<TreeModel> OpenTableCommand { get; private set; }

        public TreeViewModel(TreeViewInterface @interface)
        {
            this.@interface = @interface;
            this.SelectChangeCommand = new DelegateCommand<TreeView>(SelectChange);
            OpenTableCommand = new DelegateCommand<TreeModel>(OpenTable);
            InitTree();
        }

        #region 命令
        public void OpenTable(TreeModel model)
        {
            var win = new DataGridView(model);
            win.Show();
        }
        #endregion

        #region 事件
        public void SelectChange(TreeView tree)
        {
            BaseModel = (BaseModel)tree.SelectedItem;
            JudgeNode();
        }
        #endregion

        #region 方法
        private void InitTree()
        {
            this.@interface.InitTree();
            BaseModel = TreeModels[0];
        }

        private void JudgeNode()
        {
            switch (BaseModel.Node)
            {
                case TreeViewChangeDataGrid.Common.Enums.NodeType.Grade:
                    TreeModel = (TreeModel)BaseModel;
                    break;
                case TreeViewChangeDataGrid.Common.Enums.NodeType.Student:
                    Student = (StudentInfo)BaseModel;
                    break;
                default:
                    break;
            }
        }
        #endregion

        V模块:一个是表格的,一个是目录树的(记得安装之前讲过的behavior的包)

                a、树的界面,这次我用了之前没讲过的方法,这次树不是递归的结构,所有要么用我第一篇文章那样绑定(那方法有点老套了),要么就换一种方法(看图)

 这就是新的绑定方法,跟之前很像,只是多了一个DataType,用来指定绑定的结构类型的(看代码)

<Window
    x:Class="TreeViewChangeDataGrid.Views.TreeView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:convert="clr-namespace:TreeViewChangeDataGrid.Common.Converts;assembly=TreeViewChangeDataGrid.Common"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
    xmlns:local="clr-namespace:TreeViewChangeDataGrid.Views"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:model="clr-namespace:TreeViewChangeDataGrid.Common.Models;assembly=TreeViewChangeDataGrid.Common"
    Title="MainView"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Window.Resources>

        <convert:EnumToVisibilityConvert x:Key="enumToVisibilityConvert" />

        <!--  右键菜单  -->
        <ContextMenu x:Key="Custom">
            <MenuItem Header="表格查看">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <i:InvokeCommandAction Command="{Binding DataContext.OpenTableCommand, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}" CommandParameter="{Binding}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </MenuItem>
        </ContextMenu>
        <!--  右键菜单  -->

        <HierarchicalDataTemplate DataType="{x:Type model:TreeModel}" ItemsSource="{Binding Student}">
            <Grid>
                <TextBlock Text="{Binding Name}" />
                <Grid.Style>
                    <Style TargetType="Grid">
                        <Setter Property="ContextMenu" Value="{StaticResource Custom}" />
                    </Style>
                </Grid.Style>
            </Grid>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type model:StudentInfo}">
            <Grid>
                <TextBlock Text="{Binding Name}" />
            </Grid>
        </HierarchicalDataTemplate>
    </Window.Resources>
    <Grid Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <TreeView x:Name="tree" ItemsSource="{Binding TreeModels}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectedItemChanged">
                    <i:InvokeCommandAction Command="{Binding DataContext.SelectChangeCommand, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}" CommandParameter="{Binding ElementName=tree}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </TreeView>
        <StackPanel
            Grid.Column="1"
            VerticalAlignment="Center"
            Visibility="{Binding BaseModel.Node, Converter={StaticResource enumToVisibilityConvert}}">
            <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
                <Label Margin="0,0,20,0" Content="姓名:" />
                <TextBox
                    Width="100"
                    VerticalContentAlignment="Center"
                    Text="{Binding Student.Name}" />
            </StackPanel>
            <StackPanel
                Margin="0,20"
                HorizontalAlignment="Center"
                Orientation="Horizontal">
                <Label Margin="0,0,20,0" Content="年龄:" />
                <TextBox
                    Width="100"
                    VerticalContentAlignment="Center"
                    Text="{Binding Student.Age}" />
            </StackPanel>
            <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
                <Label Margin="0,0,20,0" Content="性别:" />
                <TextBox
                    Width="100"
                    VerticalContentAlignment="Center"
                    Text="{Binding Student.Gender}" />
            </StackPanel>
            <StackPanel
                Margin="0,20"
                HorizontalAlignment="Center"
                Orientation="Horizontal">
                <Label Margin="0,0,20,0" Content="地址:" />
                <TextBox
                    Width="100"
                    VerticalContentAlignment="Center"
                    Text="{Binding Student.Address}" />
            </StackPanel>
            <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
                <Label Margin="0,0,20,0" Content="电话:" />
                <TextBox
                    Width="100"
                    VerticalContentAlignment="Center"
                    Text="{Binding Student.Number}" />
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>

                b、表格的界面,从外到里设置,一次是DataGrid、Column、Row、Cell的样式,而对于列数据的绑定,我用的是DataGridTemplateColumn,直接看代码

 

 

    <Grid>
        <ScrollViewer
            Margin="10"
            HorizontalScrollBarVisibility="Auto"
            PreviewMouseWheel="PreviewMouseWheel"
            VerticalScrollBarVisibility="Auto">
            <DataGrid
                HorizontalAlignment="Center"
                AutoGenerateColumns="False"
                Background="#fff"
                BorderBrush="Transparent"
                CanUserAddRows="False"
                GridLinesVisibility="None"
                HorizontalScrollBarVisibility="Hidden"
                IsReadOnly="True"
                ItemsSource="{Binding DataContext.TreeModel.Student, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}">

                <!--#region 设置列的个数-->
                <DataGrid.Style>
                    <Style TargetType="DataGrid">
                        <Setter Property="HeadersVisibility" Value="Column" />
                    </Style>
                </DataGrid.Style>
                <!--#endregion-->

                <!--#region 数据网格的列标题样式属性-->
                <DataGrid.ColumnHeaderStyle>
                    <!--  样式类型:DataGridColumnHeader(数据网格列标题)  -->
                    <Style TargetType="{x:Type DataGridColumnHeader}">
                        <Setter Property="Height" Value="74" />
                        <Setter Property="BorderThickness">
                            <Setter.Value>
                                <Thickness
                                    Bottom="1"
                                    Left="1"
                                    Right="1"
                                    Top="1" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Background" Value="Orange" />
                        <Setter Property="BorderBrush" Value="Green" />
                        <Setter Property="HorizontalContentAlignment" Value="Center" />
                        <Setter Property="FontFamily" Value="微软雅黑" />
                        <Setter Property="FontWeight" Value="Black" />
                        <Setter Property="FontSize" Value="14" />
                    </Style>
                </DataGrid.ColumnHeaderStyle>
                <!--#endregion-->

                <!--#region DataGrid的RowStyle属性-->
                <DataGrid.RowStyle>
                    <Style TargetType="DataGridRow">
                        <Setter Property="Background" Value="LightBlue" />
                    </Style>
                </DataGrid.RowStyle>
                <!--#endregion-->

                <!--#region DataGrid的CellStyle属性(数据表格的单元格样式)-->
                <DataGrid.CellStyle>
                    <Style TargetType="DataGridCell">
                        <Setter Property="BorderThickness">
                            <Setter.Value>
                                <Thickness
                                    Bottom="1"
                                    Left="1"
                                    Right="1" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="BorderBrush" Value="Green" />
                        <Style.Triggers>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="Background">
                                    <Setter.Value>
                                        <SolidColorBrush Opacity="0.9" Color="AntiqueWhite" />
                                    </Setter.Value>
                                </Setter>
                                <Setter Property="Foreground" Value="Red" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </DataGrid.CellStyle>
                <!--#endregion-->

                <DataGrid.Columns>
                    <!--#region 姓名-->
                    <DataGridTemplateColumn Header="姓名">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel
                                    Margin="20"
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center"
                                    Orientation="Horizontal">
                                    <TextBlock Text="{Binding Name}" />
                                </StackPanel>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <!--#endregion-->

                    <!--#region 年龄-->
                    <DataGridTemplateColumn Header="年龄">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel
                                    Margin="20"
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center"
                                    Orientation="Horizontal">
                                    <TextBlock Text="{Binding Age}" />
                                </StackPanel>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <!--#endregion-->

                    <!--#region 性别-->
                    <DataGridTemplateColumn Header="性别">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel
                                    Margin="20"
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center"
                                    Orientation="Horizontal">
                                    <TextBlock Text="{Binding Gender}" />
                                </StackPanel>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <!--#endregion-->

                    <!--#region 地址-->
                    <DataGridTemplateColumn Header="地址">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel
                                    Margin="20"
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center"
                                    Orientation="Horizontal">
                                    <TextBlock Text="{Binding Address}" />
                                </StackPanel>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <!--#endregion-->

                    <!--#region 地址-->
                    <DataGridTemplateColumn Header="电话">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel
                                    Margin="20"
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center"
                                    Orientation="Horizontal">
                                    <TextBlock Text="{Binding Number}" />
                                </StackPanel>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <!--#endregion-->
                </DataGrid.Columns>
            </DataGrid>
        </ScrollViewer>
    </Grid>

三、总结

        总体思路是目录树显示个体信息,右键打开表格看总体信息,运行效果看图

四、补充

        (1)这次的案例并不算是典型案例,我自己随意想的,只是为了扩展下思路;

        (2)目录树我没有添加其他的功能,感兴趣的可以自行看我之前的文章扩展功能;

        (3)这次的案例需求简单,所以实现起来简单,如果是项目上,会有动态添加新的列,添加按钮,右键菜单等等;(后面感兴趣的可以跟我交流)

        (4)下次我想换个玩法了,从数据库中提取数据来渲染,不想每次的造数据,具体容我想想

        (5)这次案例的源码:GitHub - TQtong/TreeViewChangeDataGrid

五、结束

        这次的文章就到这了, 那么我继续闯荡江湖了,希望各位指出不足之处,

本文含有隐藏内容,请 开通VIP 后查看