C#— —[Winforms]自定义DataGridView和ComboBox


本解决方案包括三个项目:

  • CLCDataGridView:自定义的DataGridView,实现了自动生成列样式以及保存加载列顺序;
  • CLCComboBox:自定义的ComboBox,实现了自定义下拉项;
  • user-control:针对自定义控件的测试项目;

1. CLCDataGridView 介绍

1.1 自动生成列样式规则介绍

当改变CLCDataGridView中的数据源(DataSoource)时,会利用c#中的反射机制,根据实体中的属性自动生成列样式。

默认情况下,对于一个正常的属性,例如:

public string Name{get;set;}

会生成如下的列样式:

格式为DataGridViewTextBoxColumn

Name、HeaderText、DataPropertyName默认为属性名

DisplayIndex默认为属性在实体中的声明次序

Visible默认为true

其余未指明的DataGridView列属性,按照DataGridView中的默认值进行确定

为了更改默认的列属性,我们可以在属性上标注自定义的特性[ColumnStyle],例如:

[ColumnStyle(
    HeaderText = "姓名",
    ColumnType = ColumnStyleEnum.ButtonColumn)]
public string Name { get; set; }

表示属性Name对应的列,他的HeaderText为“姓名”,格式为DataGridViewButtonColumn。

完整的ColumnStyleAttribute定义如下:

public class ColumnStyleAttribute : System.Attribute
{
    public string Name { get; set; }           
    public string HeaderText { get; set; }     
    public int Width { get; set; }

    private int displayIndex;
    public int DisplayIndex
    {
        get => displayIndex;
        set
        {
            if (value <= 0)
            {
                displayIndex = -1;
                return;
            }

            displayIndex = value;
        }
    }
    public string DataPropertyName { get; set; }
    public string Visible { get; set; }
    public ColumnStyleEnum ColumnType { get; set; }
    public DataGridViewAutoSizeColumnMode AutoSizeMode { get; set; }
}

public enum ColumnStyleEnum
{
    TextBoxColumn,
    ButtonColumn,
    CheckBoxColumn,
    ComboBoxColumn,
    ImageColumn,
    LinkColumn
}

如果我们不想再CLCDataGridView中生成对应属性的列,那么我们可以在属性上标注[Ignore]

[Ignore]
public int Age { get; set; }

1.2 列顺序的自动保存与加载

在CLCDataGridView中,我们提供了两个属性:

  • EnableSave:指示是否保存列顺序
  • SaveModel:指示列顺序的保存方式,有两种模式,模式一表示在程序的运行目录下以XML格式保存,模式二表示在一用户电脑缓存中以JSON格式保存;

演示:启动测试项目,加载数据源,然后更改列的属性,再次加载同样的数据源时,列顺序保持用户更改后的样子。

首先将列顺序保存属性置为true,然后选择保存模式一:

在这里插入图片描述

当切换数据源或关闭程序时,会保存当前的列顺序,模式一的保存路径和XML格式如下:

在这里插入图片描述

<?xml version="1.0" standalone="yes"?>
<DocumentElement>
  <clcDataGridView1>
    <Name>Tag</Name>
    <DisplayIndex>2</DisplayIndex>
  </clcDataGridView1>
  <clcDataGridView1>
    <Name>Name</Name>
    <DisplayIndex>1</DisplayIndex>
  </clcDataGridView1>
  <clcDataGridView1>
    <Name>Gender</Name>
    <DisplayIndex>0</DisplayIndex>
  </clcDataGridView1>
    ......省略

如果我们将保存模式切换为模式二:

在这里插入图片描述

那么列顺序的保存路径为:

C:\Users\Administrator\AppData\Local\user_control\user-control.exe_Url_yjbhv1k2vle1gqa3obi1vjsego23avin\1.0.0.0

JSON保存样式为:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="ColumnStyles" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <userSettings>
        <ColumnStyles>
            <setting name="DataTablesJsonString" serializeAs="String">
                <value>{"clcDataGridView1-Com.Lee.Model.Student":[{"Name":"Tag","DisplayIndex":"1"},{"Name":"Name","DisplayIndex":"2"},{"Name":"Gender","DisplayIndex":"0"},{"Name":"Age","DisplayIndex":"3"},{"Name":"School","DisplayIndex":"4"},{"Name":"Address","DisplayIndex":"5"},{"Name":"Phone","DisplayIndex":"6"}],"clcDataGridView1-Com.Lee.Model.User":[{"Name":"Tag","DisplayIndex":"1"},{"Name":"Name","DisplayIndex":"2"},{"Name":"Password","DisplayIndex":"3"},{"Name":"Address","DisplayIndex":"0"}]}</value>
            </setting>
        </ColumnStyles>
    </userSettings>
</configuration>

1.3 关于数据源

CLCDataGridView可接受的数据源(DataSource)的格式为列表(List<T>)或实体数组。

例如,以下两类数据都是合法的数据源:

public static List<Student> Students = new List<Student>()
{
    new Student("张三", "男", 20, "中山大学", "广州", "18909880099"),
    new Student("小红", "女", 21, "厦门大学", "厦门", "19093222099"),
    new Student("肖华", "男", 20, "重庆大学", "重庆", "16743746759")
};
public static Student[] StudentArray = new[]
{
    new Student("张三数组", "男", 20, "中山大学", "广州", "18909880099"),
    new Student("小红数组", "女", 21, "厦门大学", "厦门", "19093222099"),
    new Student("肖华数组", "男", 20, "重庆大学", "重庆", "16743746759")
};

但是,以下类型的数据是不合法的:

  • 非列表或非数组类型,如string 、int 等,当给CLCDataGridView赋值如下时,会提示如下:

在这里插入图片描述

  • object类型列表:

    List<object> objects = new List<object>()
    {
        new User("name","pwd",12),
        new Student("张三", "男", 20, "中山大学", "广州", "18909880099"),
        new Student("肖华", "男", 20, "重庆大学", "重庆", "16743746759")
    };
    

    上面的声明是正确的,但是无法从object中解析出列样式,所以无法赋值给CLCDataGridView:

在这里插入图片描述

2. CLCComboBox 介绍

2.1 CLCComboBox的基础使用

CLCComboBox提供了让您自定义下拉面板的灵活性,只需要在我们的项目中引入CLCComboBox相关的库文件,然后继承BaseDropDownItem实现定义您自己的下拉面板,最后通过以下代码指定下拉面板:

clcComboBox.DropDownItem = new xxxDropDownItem();

我们提供了两种下拉面板:

  • ListDropDownItem:带搜索的列表展示

在这里插入图片描述

  • CategoryDropDownItem:分类的列表展示

在这里插入图片描述

2.2 数据源、显示成员、值成员

数据源(DataSource),显示成员(DisplayMember)、值成员(ValueMember)的语义与ComboBox相同。

当需要给CLCComboBox设置数据源时,我们提供了以下方法:

public void SetDataSource(object dataSource){ }

public void SetDataSource(object dataSource,string displayMember,string valueMember){}

注意:

  • 我们不能通过clcComboBox.DataSource = xxx;来设置数据源;
  • 我们可以通过clcComboBox.DisplayMember = xxx;clcComboBox.ValueMember = xxx;来设置显示成员和值成员;

2.3 不同下拉面板的数据源要求

2.3.1 ListDropDownItem

由于ListDropDownItem仅仅包含了CLCDataGridView,所以对于下拉内容为ListDropDownItem的CLCComboBox来说,数据源要求与CLCDataGridView的数据源要求相同。此处不再赘述。

2.3.2 CategoryDropDownItem

由于CategoryDropDownItem是用作分类显示的,所以合法的数据源有以下两类:

  • List<T>:其中的T的某个属性标注了[Typed]特性;
  • Dictionary<object,List<T>>:object表示分类对象,List<T>表示该分类下的详细列表;

案例一:Lsit<Student>

List<Student> Students = new List<Student>()
{
    new Student("张三", "男", 20, "中山大学", "广州", "18909880099"),
    new Student("小红", "女", 21, "厦门大学", "厦门", "19093222099"),
    new Student("肖华", "男", 20, "重庆大学", "重庆", "16743746759")
};

clcComboBox.SetDataSource(Students,"Name","Tag");

其中Student的Gender属性标注了[Typed]特性,表示将该学生列表按照性别属性进行分类:

public class Student
{
    ...
    [Typed]
    [ColumnStyle(
        HeaderText = "性别")]
    public string Gender { get; set; }
    
    ...
}

在这里插入图片描述

案例二:Dictionary<Gender, List<Student>>

Dictionary<Gender, List<Student>> dictionary = new Dictionary<Gender, List<Student>>()
{
    {
        new Gender("01", "男"), new List<Student>()
        {
            new Student("张三", "男", 20, "中山大学", "广州", "18909880099"),
            new Student("李四", "男", 18, "中山大学", "广州", "13509722122"),
        }
    },
    {
        new Gender("02", "女"), new List<Student>()
        {
            new Student("小花", "女", 19, "厦门大学", "厦门", "19988661232"),
            new Student("小红", "女", 21, "厦门大学", "厦门", "19093222099")
        }
    }
};

clcComboBox.SetDataSource(dictionary,"Name","Tag");

以Gender对象为分类对象:

在这里插入图片描述

Gender对象作为分类对象,我们可以指定Gender的属性为DisplayMember,只需要在对应的属性上标注[DisplayMember]特性即可:

public class Gender
{
    public string Code { get; set; }

    [DisplayMember]
    public string Value { get; set; }

    public Gender(string code, string value)
    {
        Code = code;
        Value = value;
    }
}

案例三:List<Employee> employees,分类对象为自定义对象

Gender male = new Gender("01", "男");
Gender female = new Gender("02", "女");

List<Employee> employees = new List<Employee>()
{
    new Employee() {Name = "员工1", Gender = male, Phone = "2891"},
    new Employee() {Name = "员工2", Gender = female, Phone = "1891"},
    new Employee() {Name = "员工3", Gender = female, Phone = "3891"},
    new Employee() {Name = "员工4", Gender = male, Phone = "6891"},
};

clcComboBox2.SetDataSource(employees,"Name","Tag");

在这里插入图片描述

2.4 关于自定义属性

在CLCComboBox中,我们自定义了两个属性:

  • EnableColumnSort:指示下拉内容中的CLCDataGridView中的行是否可以排序
  • EnableResiveDropDownItem:指示下拉面板是否可以改变大小。如果为false,则下拉面板为默认大小;只有该项为true,DropDownHeight和DropDownWidth才起作用。不过不建议使用该项,否则会导致下拉面板中的控件布局不美观。

2.5 关于搜索、选择、获取选择项

当我们在搜索框输入搜索条件时,会实时在下面的列表中显示符合条件的实体,找到符合的实体后,可以点击确认关闭下拉面板,也可以双击选中的实体进行关闭面板:

在这里插入图片描述

当我们选择了目标内容后,可以通过CLCComboBotxSelectedValue获取目标值。

在这里插入图片描述

3. 项目地址

github:https://github.com/Lee-0o0/CSharp-user-control

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值