c# DataGridView 自定义控件,使之实现行与行之间可以有层次关系,能像TreeView那样展开、合并

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c# DataGridView 自定义控件,使之实现行与行之间可以有层次关系,能像TreeView那样展开、合并相关的知识,希望对你有一定的参考价值。

最近一个项目用C#开发的,遇到了一个棘手的问题,望各位高手能帮帮我。我在项目中用到了 DataGridView 控件去显示数据,数据行之间有父子(层次)关系,希望显示的第一列数据有TreeView 样式 + 数据,通过点击这个数据项可以正行的展开或合并。
各位我现在只有25分,所以我最高只能给20,希望大家理解。今后大家可以成为朋友。呵呵....

参考技术A 用ListView代替DataGridView 显示数据,
ListView的group可以解决这个问题,
参考技术B 复杂表头?

winform的没注意

webform的有

C# 在 DataGridView 上显示我的自定义控件,即使不编辑

【中文标题】C# 在 DataGridView 上显示我的自定义控件,即使不编辑【英文标题】:C# show my custom control on DataGridView even if not editing 【发布时间】:2021-08-11 13:13:08 【问题描述】:

我正在使用以下类来创建一个带有数字上下控件的自定义列。这工作得很好,但我想一直显示数字上下控制(即使不编辑)。以下代码将字符串值放在控件上,单击单元格后将显示数字控件进行编辑。我认为我需要重写 Paint 方法但我不知道如何实现它

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Utilities.General.Classes

    public class NumericUpDownColumn : DataGridViewColumn
    
        public NumericUpDownColumn() : base(new NumericUpDownCell())
         
        public override DataGridViewCell CellTemplate
        
            get  return base.CellTemplate; 
            set
            
                //Ensure that the cell used for the template is a NumericUpDown
                if(value?.GetType().IsAssignableFrom(typeof(NumericUpDownCell)) == false)
                
                    throw new InvalidCastException("Must be a string");
                
                base.CellTemplate = value;
            
        
    

    public class NumericUpDownCell : DataGridViewTextBoxCell
    
        public override void InitializeEditingControl(int rowIndex, object initialFormattedValue,
            DataGridViewCellStyle dataGridViewCellStyle)
        
            base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
            if(DataGridView.EditingControl is NumericUpDown numeric)
            
                numeric.Value = Convert.ToDecimal(Value ?? DefaultNewRowValue);
                numeric.Minimum = MinValue;
                numeric.Maximum = MaxValue;
            
        

        protected override void OnEnter(int rowIndex, bool throughMouseClick)
        
            if(throughMouseClick)
            
                DataGridView.BeginEdit(false);
            
        

        public override Type EditType
        
            get  return typeof(NumericUpDownEditingControl); 
        

        public override Type ValueType
        
            get  return typeof(string); 
        

        public override object DefaultNewRowValue
        
            get  return 0; 
        

        private int MinValue  get; set; 
        private int MaxValue  get; set; 

        public void UpdateValues(int minValue, int maxValue)
        
            MinValue = minValue;
            MaxValue = maxValue;
            ReadOnly = MinValue == MaxValue;
            if(ReadOnly)
            
                Style.ForeColor = Color.DimGray;
            
        
    

    public class NumericUpDownEditingControl : NumericUpDown, IDataGridViewEditingControl
    
        public object EditingControlFormattedValue
        
            get => Value;
            set
            
                if(value is decimal number)
                
                    try
                    
                        Value = number;
                    
                    catch
                    
                        Value = 0;
                    
                
            
        

        public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
        
            if((context & DataGridViewDataErrorContexts.Parsing) != 0)
            
                return Value.ToString();
            
            return EditingControlFormattedValue;
        

        public decimal MinValue
        
            get => Minimum;
            set => Minimum = value;
        

        public decimal MaxValue
        
            get => Maximum;
            set => Maximum = value;
        

        public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
        
            Font = dataGridViewCellStyle.Font;
            ForeColor = dataGridViewCellStyle.ForeColor;
            BackColor = dataGridViewCellStyle.BackColor;
        

        public int EditingControlRowIndex  get; set; 

        public bool EditingControlWantsInputKey(Keys key, bool datagridviewWantsInputKey)
        
            switch(key & Keys.KeyCode)
            
                case Keys.Left:
                case Keys.Up:
                case Keys.Down:
                case Keys.Right:
                case Keys.Home:
                case Keys.End:
                case Keys.PageDown:
                case Keys.PageUp:
                    return true;
                default:
                    return !datagridviewWantsInputKey;
            
        

        public void PrepareEditingControlForEdit(bool selectAll)
        
        

        public bool RepositionEditingControlOnValueChange => false;

        public DataGridView EditingControlDataGridView  get; set; 

        public bool EditingControlValueChanged  get; set; 

        public Cursor EditingPanelCursor => base.Cursor;

        protected override void OnValueChanged(EventArgs eventargs)
        
            EditingControlValueChanged = true;
            EditingControlDataGridView.NotifyCurrentCellDirty(true);
            base.OnValueChanged(eventargs);
        
    

【问题讨论】:

【参考方案1】:

这似乎有效:

protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)

    if(decimal.TryParse(value.ToString(), out var val))
    
        var ctrl = new NumericUpDown()
        
            Value = val
        ;
        var img = new Bitmap(cellBounds.Width, cellBounds.Height);
        ctrl.DrawToBitmap(img, new Rectangle(0, 0, ctrl.Width, ctrl.Height));
        graphics.DrawImage(img, cellBounds.Location);
    
    else
    
        throw new InvalidCastException($"value is not decimal type");
    

【讨论】:

以上是关于c# DataGridView 自定义控件,使之实现行与行之间可以有层次关系,能像TreeView那样展开、合并的主要内容,如果未能解决你的问题,请参考以下文章

C# datagridview绑定集合,怎样点击列标题使之排序

C# Winform下,datagridview或者ListView能够自定义模板吗?

c# 用户自定义控件的问题 winform

C# .net不同版本中winform控件 dataGrid /DataGrid/DataGridView 有啥区别

c# winform datagridview怎么能达到如图的效果

C#中能不能用datagridview显示文件的内容?不用数据库