How to create partially client area in UserControl?

后端 未结 1 486
耶瑟儿~
耶瑟儿~ 2021-01-15 05:30

In my previous question I have sorted out how to create container dependent control. Now, I am getting problem in that control. the design of control is little bit confusing

1条回答
  •  無奈伤痛
    2021-01-15 06:11

    The easy way

    The easiest way is to recalculate the bounds of the XWizardPage whenever the size of its parent changes.

    Public Class XWizardPage
        Inherits DevExpress.XtraEditors.XtraPanel
        Implements IComparable(Of XWizardPage)
    
        Protected Overrides Sub OnResize(e As System.EventArgs)
            MyBase.OnResize(e)
            If (Not Me.positioningInternal) Then Me.Position()
        End Sub
    
        Protected Overrides Sub SetBoundsCore(x As Integer, y As Integer, width As Integer, height As Integer, specified As System.Windows.Forms.BoundsSpecified)
            MyBase.SetBoundsCore(x, y, width, height, specified)
            If (Not Me.positioningInternal) Then Me.Position()
        End Sub
    
        Protected Overrides Sub OnParentChanged(e As System.EventArgs)
            MyBase.OnParentChanged(e)
            If (Not Me.cachedParent Is Nothing) Then
                RemoveHandler Me.cachedParent.SizeChanged, AddressOf Me.OnParentSizeChanged
            End If
            Me.cachedParent = If(((Not Me.Parent Is Nothing) AndAlso (TypeOf Me.Parent Is XWizardControl)), Me.Parent, Nothing)
            If (Not Me.cachedParent Is Nothing) Then
                AddHandler Me.cachedParent.SizeChanged, AddressOf Me.OnParentSizeChanged
            End If
        End Sub
    
        Private Sub OnParentSizeChanged(sender As Object, e As EventArgs)
            Me.Position()
        End Sub
    
        Private Sub Position()
            If (Not Me.cachedParent Is Nothing) Then
                Dim r As Rectangle = Me.cachedParent.ClientRectangle
                r.Y += 10
                r.Height -= (10 * 2)
                If (Me.Bounds <> r) Then
                    Me.positioningInternal = True
                    Me.Bounds = r
                    Me.positioningInternal = False
                End If
            End If
        End Sub
    
        Private cachedParent As Control
        Private positioningInternal As Boolean
    
    End Class
    

    The hard way

    The hard way requires native calls. I cannot append a complete solution as this is pretty complex, though doable. The term you're looking for is nonclient area. There are many tutorials on the web, and you should do a search.

    The following code is just an example to show you where to start and is not a final solution. For this to work perfect, you'll need to handle Window redraw, Mouse events etc.

    Public Class XWizardControl
        Inherits DevExpress.XtraEditors.XtraUserControl
    
         _
        Private Shared Function GetDCEx(ByVal hWnd As IntPtr, ByVal hrgnClip As IntPtr, ByVal flags As Integer) As IntPtr
        End Function
    
        Private Sub WmNcCalcSize(ByRef m As Message)
            If (m.WParam.ToInt32() = 0) Then
                Dim ncRect As RECT = DirectCast(m.GetLParam(GetType(RECT)), RECT)
                ncRect.top += 10
                ncRect.bottom -= 10
                Marshal.StructureToPtr(ncRect, m.LParam, False)
                m.Result = IntPtr.Zero
            ElseIf (m.WParam.ToInt32() = 1) Then
                Dim ncParams As NCCALCSIZE_PARAMS = DirectCast(m.GetLParam(GetType(NCCALCSIZE_PARAMS)), NCCALCSIZE_PARAMS)
                ncParams.rectProposed.top += 10
                ncParams.rectProposed.bottom -= 10
                Marshal.StructureToPtr(ncParams, m.LParam, False)
                m.Result = IntPtr.Zero
            Else
                MyBase.WndProc(m)
            End If
        End Sub
    
        Private Sub WmNcPaint(ByRef m As Message)
            Dim hDC As IntPtr = GetDCEx(m.HWnd, m.WParam, (DCX.WINDOW Or DCX.INTERSECTRGN Or DCX.CACHE Or DCX.CLIPSIBLINGS))
            If (hDC.ToInt32() <> 0) Then
                Using g As Graphics = Graphics.FromHdc(hDC)
                    g.Clear(Color.Red)
                End Using
                m.Result = IntPtr.Zero
            Else
                MyBase.WndProc(m)
            End If
        End Sub
    
        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
            Select Case m.Msg
                Case WM_NCCALCSIZE : Me.WmNcCalcSize(m) : Exit Select
                Case WM_NCPAINT : Me.WmNcPaint(m) : Exit Select
                Case Else : MyBase.WndProc(m) : Exit Select
            End Select
        End Sub
    
        Public Const WM_NCCALCSIZE As Integer = 131
        Public Const WM_NCPAINT As Integer = 133
    
         _
        Private Structure RECT
            Public left As Integer
            Public top As Integer
            Public right As Integer
            Public bottom As Integer
        End Structure
    
         _
        Private Structure NCCALCSIZE_PARAMS
            Public rectProposed As RECT
            Public rectBeforeMove As RECT
            Public rectClientBeforeMove As RECT
            Public lppos As WINDOWPOS
        End Structure
    
         _
        Private Structure WINDOWPOS
            Public hwnd As IntPtr
            Public hWndInsertAfter As IntPtr
            Public x As Integer
            Public y As Integer
            Public cx As Integer
            Public cy As Integer
            Public flags As UInteger
        End Structure
    
        Private Enum DCX As Integer
            CACHE = &H2
            CLIPCHILDREN = &H8
            CLIPSIBLINGS = &H10
            EXCLUDERGN = &H40
            EXCLUDEUPDATE = &H100
            INTERSECTRGN = &H80
            INTERSECTUPDATE = &H200
            LOCKWINDOWUPDATE = &H400
            NORECOMPUTE = &H100000
            NORESETATTRS = &H4
            PARENTCLIP = &H20
            VALIDATE = &H200000
            WINDOW = &H1
        End Enum
    
    End Class
    

    0 讨论(0)
提交回复
热议问题