vb.net - 如何使自定义ComboBox(OwnerDrawFixed)看起来像标准ComboBox的3D?

标签 vb.net visual-studio-2010 combobox custom-controls ondrawitem

我正在制作一个自定义的ComboBox,它继承自Winforms的标准ComboBox。对于我的自定义ComboBox,我将DrawMode设置为OwnerDrawFixed,并将DropDownStyle设置为DropDownList。然后,我编写自己的OnDrawItem方法。但是我最终却是这样的:

如何使我的自定义组合框看起来像标准组合框?

更新1:ButtonRenderer
到处搜索后,我发现了 ButtonRenderer class。它提供了DrawButton静态/共享方法,顾名思义,该方法绘制了正确的3D按钮。我现在正在尝试。

更新2:什么覆盖了我的控件?
我尝试使用可以想到的各种对象的Graphics属性,但是我总是失败。最后,我尝试了表单的“图形”,显然是某些内容覆盖了我的按钮。
这是代码:

Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
  Dim TextToDraw As String = _DefaultText
  __Brush_Window.Color = Color.FromKnownColor(KnownColor.Window)
  __Brush_Disabled.Color = Color.FromKnownColor(KnownColor.GrayText)
  __Brush_Enabled.Color = Color.FromKnownColor(KnownColor.WindowText)
  If e.Index >= 0 Then
    TextToDraw = _DataSource.ItemText(e.Index)
  End If
  If TextToDraw.StartsWith("---") Then TextToDraw = StrDup(3, ChrW(&H2500)) ' U+2500 is "Box Drawing Light Horizontal"
  If (e.State And DrawItemState.ComboBoxEdit) > 0 Then
    'ButtonRenderer.DrawButton(e.Graphics, e.Bounds, VisualStyles.PushButtonState.Default)
  Else
    e.DrawBackground()
  End If
  With e
    If _IsEnabled(.Index) Then
      .Graphics.DrawString(TextToDraw, Me.Font, __Brush_Enabled, .Bounds.X, .Bounds.Y)
    Else
      '.Graphics.FillRectangle(__Brush_Window, .Bounds)
      .Graphics.DrawString(TextToDraw, Me.Font, __Brush_Disabled, .Bounds.X, .Bounds.Y)
    End If
  End With
  TextToDraw = Nothing
  ButtonRenderer.DrawButton(Me.Parent.CreateGraphics, Me.ClientRectangle, VisualStyles.PushButtonState.Default)

  'MyBase.OnDrawItem(e)
End Sub
结果如下:

Me.Parent.CreateGraphics替换e.Graphics得到了这个:

并执行以上操作,用Me.ClientRectangle替换e.Bounds后,我得到了这一点:

谁能指出我必须为ButtonRenderer.DrawButton方法使用的图形?
PS:蓝色边框是由于我使用PushButtonState.Default而不是PushButtonState.Normal

我找到答案了! (见下文)

最佳答案

我忘记了找到答案的地方...当我记得时,我将编辑此答案。

但显然,我需要设置Systems.Windows.Forms.ControlStyles标志。特别是ControlStyles.UserPaint标志。

因此,我的New()现在看起来像这样:

Private _ButtonArea as New Rectangle

Public Sub New()
  ' This call is required by the designer.
  InitializeComponent()
  ' Add any initialization after the InitializeComponent() call.
  MyBase.SetStyle(ControlStyles.Opaque Or ControlStyles.UserPaint, True)
  MyBase.DrawMode = Windows.Forms.DrawMode.OwnerDrawFixed
  MyBase.DropDownStyle = ComboBoxStyle.DropDownList
  ' Cache the button's modified ClientRectangle (see Note)
  With _ButtonArea
    .X = Me.ClientRectangle.X - 1
    .Y = Me.ClientRectangle.Y - 1
    .Width = Me.ClientRectangle.Width + 2
    .Height = Me.ClientRectangle.Height + 2
  End With
End Sub

现在,我可以加入OnPaint事件:
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
  If Me.DroppedDown Then
    ButtonRenderer.DrawButton(Me.CreateGraphics, _ButtonArea, VisualStyles.PushButtonState.Pressed)
  Else
    ButtonRenderer.DrawButton(Me.CreateGraphics, _ButtonArea, VisualStyles.PushButtonState.Normal)
  End If
  MyBase.OnPaint(e)
End Sub

注意:是的,_ButtonArea矩形必须在所有方向(向上,向下,向左,向右)放大1个像素,否则ButtonRenderer周围将有一个1像素的“周长”,显示为垃圾。让我发疯了一段时间,直到我读了I must enlarge the Control's rect for ButtonRenderer.

关于vb.net - 如何使自定义ComboBox(OwnerDrawFixed)看起来像标准ComboBox的3D?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5864633/

相关文章:

.net - 使用Visual Studio 2010 开发.net 3.5 sp1 产品有什么危险吗?

vb.net - 将 Stack 的所有内容推送到另一个堆栈?

c# - 如何手动触发 Datagridview.cellValidating?

.net - 人们期待 .Net 4.0 - 4.1 中的哪些功能

javascript - 使用 JavaScript 使用来自 PHP 数组的选项填充动态创建的下拉列表

wpf - 如何使用 WPF 创建分层组合框?

javascript - IE 组合框使用,选择时卡住

mysql - 使用 dotnet String.Format 将数据保存到数据库失败

vb.net - 如何在 vb.net 中使用 TextRenderer DrawText 换行长字

c++ - printf 字符串输出 "Dz↕"getch() C++