【问题标题】:How to paint inactive rows in DataGridViewComboBox column?如何在 DataGridViewComboBox 列中绘制非活动行?
【发布时间】:2015-07-16 11:30:22
【问题描述】:

我可以easily paint items in DataGridViewComboBox dropdown list。但我不知道如何在同一列中绘制非活动单元格

我已经看过、研究并尝试了许多经典 ComboBox 的示例,但我并不了解 DataGridViewComboBox 的所有方面。

目前我有从 DataGridViewComboBox 派生的 DataGridViewCustomPaintComboBox 类。要提供的最小覆盖集是多少?你能指出我正确的方向吗?

【问题讨论】:

    标签: c# .net winforms custom-controls datagridviewcombobox


    【解决方案1】:

    在没有焦点的情况下绘制非活动单元格所需的最小值似乎是CellTemplate 分配和Paint() 覆盖:

    public class DataGridViewCustomPaintComboBox : DataGridViewComboBoxColumn
    {
    
        public DataGridViewCustomPaintComboBox()
        {
            base.New();
            CellTemplate = new DataGridViewCustomPaintComboBoxCell();
        }
    
    }
    
    public class DataGridViewCustomPaintComboBoxCell : DataGridViewComboBoxCell
    {
    
        protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            // modify received arguments here
            base.Paint(...); // paint default parts (see paintParts argument)
            // add any custom painting here
    
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      更新

      自定义绘制DataGridViewComboBox 有点复杂。实际上它由四种不同的绘图案例组成:

      对于未聚焦的单元格,您需要编写CellPainting 事件:

      private void dataGridView1_CellPainting(object sender, 
                                              DataGridViewCellPaintingEventArgs e)
      {
         // drawstuff nr 1: draw the unfocused cell
      }
      

      当单元格具有焦点时,实际的DataGridViewComboBoxEditingControl(它是ComboBox 的直接后代)被创建并显示。

      您需要获取它的句柄(在 EditingControlShowing 事件中),然后应该在其 DrawItem 事件中再编写三个案例:

      void theBoxCell_DrawItem(object sender, DrawItemEventArgs e)
      {
          if (e.Index < 0)
          {
             // drawstuff 2: draw the undropped top portion
          }
          else
          {
             if ((e.State & DrawItemState.Selected) != DrawItemState.None
             {
                // drawstuff 3:  draw a selected item
             }
             else
             {
                // drawstuff 4:  draw an unselected item   
             }
          }
       }
      

      关于各种油漆代码的几点说明:

      • drawstuff 1:在这里您应该在绘制文本后绘制一个箭头。为此,最好使用ComboBoxRenderer.DrawDropDownButton 方法。您需要知道位置和大小,SystemInformation.VerticalScrollBarWidth 应该对此有所帮助。请注意,TextRenderer.DrawText 不仅可以让您使用漂亮的TextFormatFlags 来帮助对齐,还可以使用Backcolor

      • drawstuff 2:请注意,遗憾的是 ComboBox 没有拾取其单元格的 BackColor。它仍然有助于设置它,因此您可以将其称为目标颜色。就像在下面的 darw 代码中一样,您将需要使用 e.Graphics.DrawXxx 调用和 TextRenderer.DrawText 的组合。为了更方便地引用它所属的 DGV 单元,您可能希望在 EditingControlShowing 事件中设置 CurrentCell 时将其存储在引用 ComboBoxTag 中。

      • drawstuff 3:所选项目可能具有特殊的字体和背景颜色

      • drawstuff 4:常规项目就是这样:相当常规..


      下面的代码是我的答案的原始版本,只涵盖案例3&4:

      下面是一个简短的示例,向您展示如何绘制DataGridViewComboBox。请注意,我只展示了最低限度,并没有画彩色方块..:

      我们首先定义一个对单元格的类级引用:

      ComboBox theBoxCell = null;
      

      EditingControlShowing 中我们设置引用,添加事件处理程序并将其设置为所有者绘制模式:

      private void dataGridView1_EditingControlShowing(object sender,
                   DataGridViewEditingControlShowingEventArgs e)
      {
          theBoxCell = (ComboBox) e.Control;
          theBoxCell.DrawItem += theBoxCell_DrawItem;
          theBoxCell.DrawMode = DrawMode.OwnerDrawVariable;
      }
      

      最后我们添加绘制代码:

      void theBoxCell_DrawItem(object sender, DrawItemEventArgs e)
      {
          if (e.Index < 0) return;
          string t = theBoxCell.Items[e.Index].ToString();
          using (SolidBrush brush = new SolidBrush(
              (e.State & DrawItemState.Selected) != DrawItemState.None ?
                         Color.LightCyan : Color.LightGray))
              e.Graphics.FillRectangle(brush, e.Bounds);
          e.DrawFocusRectangle();
          e.Graphics.DrawString(t, Font, Brushes.DarkGoldenrod, e.Bounds.X + 6, e.Bounds.Y + 1);
      
      }
      

      我们也可以将 linq 中的绘制代码添加到事件挂钩中......

      结果如下:

      【讨论】:

      • 如果我的问题表述不当,我很抱歉。我已经可以画出你所展示的一切了。但是没有焦点的非活动 DataGridView 行呢?
      • 与此同时,我想我已经明白了。我添加了答案。
      • 好吧,这并没有回答问题,实际上要画什么。毕竟,用户应该会看到一个箭头,如果您希望它也被着色,那么您需要一些代码行,不是吗?
      • 哈,这些事情发生在 cmets - 双方都不太了解对方的意思。稍后我将更新我的答案,以一种很好的方式包括 DGVComboBoxCells 的绘画,但 atm 我正坐在 inisde heatwave ;-) - 我将涉及 DGV 的 CellPainting 事件和箭头的 ComboBoxRenderer .. - 也是DrawItem 代码的扩展,以便在e.Index==-1 时正确绘制
      • 我会对添加的建议感到满意,这也会为其他人创造价值。答案中提出的解决方案的最大缺点是该列绑定到DataGridView1.EditingControlShowing 事件。因此,您必须为每个 DataGridView 一次又一次地创建独特的 EditingControlShowing 方法 + DrawItem() 绘画。如果一个人像我一样有 50 多个网格,那不是很聪明。我认为更具创新性的方法是将自定义绘画绑定到 DGV 列的实例。你觉得可以help me with that?
      猜你喜欢
      • 2014-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-31
      • 2013-10-17
      • 2011-08-24
      • 2013-04-29
      相关资源
      最近更新 更多