DateTimePicker和UserPaint ...缺少文本和按钮

时间:2009-10-20 15:29:07

标签: .net vb.net datetimepicker

我有一个DateTimePicker,我动态'分配了Paint-Event,不幸的是,只要分配了这个事件,文本和DropDown-Button都没有被渲染(但是正在工作)。

我写了一个组件,它采取了另一种控制并在其上绘制了一些东西

Public Sub New(Byval parent As Control)
    Me._parent = parent
    Me._setStyle = Me._parent.GetType().GetMethod("SetStyle", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
    Me._setStyle.Invoke(Me._parent, New Object() {ControlStyles.UserPaint, True})
    Me._setStyle.Invoke(Me._parent, New Object() {ControlStyles.OptimizedDoubleBuffer, True})

    AddHandler Me._parent.Paint, AddressOf RemotePaintHandler
End Sub

Private Sub RemotePaintHandler(ByVal sender As Object, ByVal e As PaintEventArgs)
    'draw something here'
End Sub

在处理组件时,我正在移除处理程序并重置样式。但只要分配了Handler,DateTimePicker就会像没有内容的普通文本框一样呈现,但按钮正常工作,我也可以输入值。如果我已经覆盖了OnPaint()方法,我只需要调用MyBase.OnPaint()或者类似的......但这是一个事件处理程序......我现在完全无能为力。

2 个答案:

答案 0 :(得分:2)

DateTimePicker没有OnPaint方法来绘制自己。它实际上是一个围绕windows控件SysDateTimePick32的包装器,所以当你设置UserPaint = true时,控件(真实的)不再绘制自己,只有你的绘图。

您可以继承DateTimePicker,覆盖WndProc,通过执行WM_PAINT订阅者来回复Paint event消息。这是一个例子:

Public Class DTP
    Inherits DateTimePicker

    ' Events '
    Public Event Paint2 As PaintEventHandler

    ' Methods '
    Protected Overrides Sub WndProc(ByRef m As Message)

        MyBase.WndProc((m))

        If ((m.Msg = &HF) AndAlso (Not Me.Paint2 Is Nothing)) Then

            Dim g As Graphics = MyBase.CreateGraphics
            Me.Paint2.Invoke(Me, New PaintEventArgs( _
                                       g, _
                                       Rectangle.Round(g.VisibleClipBounds) _
                                     ) _
                            )
        End If

    End Sub

End Class

然后使用此新控件而不是常规DateTimePicker&订阅它的Paint2事件来绘制你需要的东西:

(您无需设置UserPaint = True,无论如何都要抓取WM_PAINT

Public Sub New(Byval parent As Control)
    Me._parent = parent
    Me._setStyle = Me._parent.GetType().GetMethod("SetStyle", _
                               Reflection.BindingFlags.Instance _
                               Or Reflection.BindingFlags.NonPublic)
    'Me._setStyle.Invoke(Me._parent, New Object(){ControlStyles.UserPaint,True})'
    Me._setStyle.Invoke(Me._parent,  _
                        New Object() {ControlStyles.OptimizedDoubleBuffer, True})

    AddHandler Me._parent.Paint2, AddressOf RemotePaintHandler
End Sub

Private Sub RemotePaintHandler(ByVal sender As Object, ByVal e As PaintEventArgs)
    'draw something here'
End Sub

希望这有帮助,

答案 1 :(得分:0)

我想出了什么。因为看起来UserPaint发生在底层控件内而不是在DateTimePicker本身中,'导致它呈现错误。只要设置了Style UserPaint,就会发生这种情况。

一个解决方法是让它在Paint-Event中呈现正确...这不是我担心的那么容易,但可能:

Private Sub RemotePaintHandler(ByVal sender As Object, ByVal e As PaintEventArgs)
    RemoveHandler Me._parent.Paint, AddressOf RemotePaintHandler
    Me._setStyle.Invoke(Me._parent, New Object() {ControlStyles.UserPaint, False})

    Me._parent.Refresh()
    ' now draw something '

    Me._setStyle.Invoke(Me._parent, New Object() {ControlStyles.UserPaint, True})
    AddHandler Me._parent.Paint, AddressOf RemotePaintHandler
End Sub

我们删除Handler和Paint-Event的样式,刷新控件('使其正确渲染),然后在新渲染的控件上绘制我们的东西,然后重新添加Style和Paint-事件处理程序。 缺点是,我们绘制的所有内容都会在某人输入某些信息时消失(如果您使用日历框则会在那里显示),并且在some_one_刷新控件之前可能不会返回。所以这似乎是一个丑陋的黑客,然后是一个真正的解决方法甚至解决方案[1]。

尽管如此,我只使用DateTimePicker对此进行了测试,并且不知道这是否也适用于其他控件(但似乎如此)。

[1]我的意思是,我知道解决方案,在框架内重写控件......