c# - 如何在 UserControl 中创建部分客户区?

标签 c# vb.net winforms user-controls

在我之前的问题中,我整理了如何创建容器依赖控件。现在,我在该控件中遇到了问题。控件的设计有点困惑。设计看起来像这样。

enter image description here

在此设计中,开发人员无法在页面控件之外添加控件。 PageControl 将自动添加到客户区。我想阻止用户在 PageControl 之外添加控件。我不会再制造困惑了。那么,我的问题是我该怎么做?

enter image description here

类声明可以看我之前的question

如果您对此有任何其他想法,请建议我。

更新:

控件应如下所示。

enter image description here

但是,在分配非客户区之后,放置的控件进入客户区。我想阻止用户在该部分添加控件。 enter image description here

最佳答案

简单的方法

最简单的方法是在父级大小发生变化时重新计算 XWizardPage 的边界。

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

艰难的道路

困难的方法需要本地调用。我无法附加完整的解决方案,因为这非常复杂,但可行。您要查找的术语是 nonclient area .网上有很多教程,你应该搜索一下。

下面的代码只是一个示例,向您展示从哪里开始,不是最终的解决方案。为了使其完美运行,您需要处理 Window redrawMouse events

Public Class XWizardControl
    Inherits DevExpress.XtraEditors.XtraUserControl

    <DllImport("user32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True)> _
    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

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure RECT
        Public left As Integer
        Public top As Integer
        Public right As Integer
        Public bottom As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure NCCALCSIZE_PARAMS
        Public rectProposed As RECT
        Public rectBeforeMove As RECT
        Public rectClientBeforeMove As RECT
        Public lppos As WINDOWPOS
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    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

关于c# - 如何在 UserControl 中创建部分客户区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22267736/

相关文章:

c# - 如何在 C# 中反序列化 JSON 字符串是正确的?

vb.net - 自动旋转画中画框

c# - 尝试在 VB.NET 中使用 C# Web 服务

c# - session 在 Controller 方法中变为空

c# - 信箱不可用。服务器响应是 : No such domain at this location

c# - 从 C# 调用 DLL (VS2008)

javascript - VB.NET - WebBrowser 不显示 html 源代码中由 javascript 创建的 html 元素

c# - WinForms App + MS SQL Server DB 迁移到 Azure 平台

c# - 使用 UI 进行后台工作

c# - 以编程方式格式化 USB 驱动器