代码之家  ›  专栏  ›  技术社区  ›  Mike

自定义WinForms控件中的基线管理线

  •  32
  • Mike  · 技术社区  · 17 年前

    我有一个自定义用户控件,上面有一个文本框,我想在自定义控件外公开基线(文本框中的文本)对齐线。我知道您创建了一个设计器(继承自ControlDesigner)并重写Snaplines以访问Snaplines,但我想知道如何获取自定义用户控件公开的控件的文本基线。

    5 回复  |  直到 17 年前
        1
  •  25
  •   Miral    16 年前

    我有一个类似的需求,我像这样解决了它:

     public override IList SnapLines
    {
        get
        {
            IList snapLines = base.SnapLines;
    
            MyControl control = Control as MyControl;
            if (control == null) { return snapLines; }
    
            IDesigner designer = TypeDescriptor.CreateDesigner(
                control.textBoxValue, typeof(IDesigner));
            if (designer == null) { return snapLines; }
            designer.Initialize(control.textBoxValue);
    
            using (designer)
            {
                ControlDesigner boxDesigner = designer as ControlDesigner;
                if (boxDesigner == null) { return snapLines; }
    
                foreach (SnapLine line in boxDesigner.SnapLines)
                {
                    if (line.SnapLineType == SnapLineType.Baseline)
                    {
                        snapLines.Add(new SnapLine(SnapLineType.Baseline,
                            line.Offset + control.textBoxValue.Top,
                            line.Filter, line.Priority));
                        break;
                    }
                }
            }
    
            return snapLines;
        }
    }
    

    这样,它实际上为子控件创建了一个临时的子设计器,以便找出“真正的”基线对齐线在哪里。

    这在测试中似乎是合理的,但是如果性能成为一个问题(并且如果内部文本框不移动),那么大部分代码可以提取到初始化方法中。

    这还假定文本框是UserControl的直接子级。如果有其他布局影响控件的方式,那么偏移量计算将变得更加复杂。

        2
  •  42
  •   Matthew M.    12 年前

    作为对米拉尔答案的更新……以下是一些“缺失的步骤”,对于正在寻找如何做到这一点的新员工来说。:)上面的C代码几乎可以“插入”了,除了更改一些值以引用将要修改的用户控件之外。

    可能需要的参考:
    系统设计(@robyaw)

    需要使用:

    using System.Windows.Forms.Design;
    using System.Windows.Forms.Design.Behavior;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Collections;
    

    在用户控件上,需要以下属性:

    [Designer(typeof(MyCustomDesigner))]
    

    然后您需要一个“designer”类,该类将覆盖Snaplines:

    private class MyCustomerDesigner : ControlDesigner {
      public override IList SnapLines {
        get {
         /* Code from above */
        IList snapLines = base.SnapLines;
    
        // *** This will need to be modified to match your user control
        MyControl control = Control as MyControl;
        if (control == null) { return snapLines; }
    
        // *** This will need to be modified to match the item in your user control
        // This is the control in your UC that you want SnapLines for the entire UC
        IDesigner designer = TypeDescriptor.CreateDesigner(
            control.textBoxValue, typeof(IDesigner));
        if (designer == null) { return snapLines; }
    
        // *** This will need to be modified to match the item in your user control
        designer.Initialize(control.textBoxValue);
    
        using (designer)
        {
            ControlDesigner boxDesigner = designer as ControlDesigner;
            if (boxDesigner == null) { return snapLines; }
    
            foreach (SnapLine line in boxDesigner.SnapLines)
            {
                if (line.SnapLineType == SnapLineType.Baseline)
                {
                    // *** This will need to be modified to match the item in your user control
                    snapLines.Add(new SnapLine(SnapLineType.Baseline,
                        line.Offset + control.textBoxValue.Top,
                        line.Filter, line.Priority));
                    break;
                }
            }
        }
    
        return snapLines;
    }
    
        }
      }
    }
    
        3
  •  7
  •   Robert H.    15 年前

    感谢所有的帮助。这是一个很难接受的问题。在每个用户控件中都有一个私有子类的想法不是很好理解。

    我想出了这个基础班来帮忙。

    [Designer(typeof(UserControlSnapLineDesigner))]
    public class UserControlBase : UserControl
    {
        protected virtual Control SnapLineControl { get { return null; } }
    
        private class UserControlSnapLineDesigner : ControlDesigner
        {
            public override IList SnapLines
            {
                get
                {
                    IList snapLines = base.SnapLines;
    
                    Control targetControl = (this.Control as UserControlBase).SnapLineControl;
    
                    if (targetControl == null)
                        return snapLines;
    
                    using (ControlDesigner controlDesigner = TypeDescriptor.CreateDesigner(targetControl,
                        typeof(IDesigner)) as ControlDesigner)
                    {
                        if (controlDesigner == null)
                            return snapLines;
    
                        controlDesigner.Initialize(targetControl);
    
                        foreach (SnapLine line in controlDesigner.SnapLines)
                        {
                            if (line.SnapLineType == SnapLineType.Baseline)
                            {
                                snapLines.Add(new SnapLine(SnapLineType.Baseline, line.Offset + targetControl.Top,
                                    line.Filter, line.Priority));
                                break;
                            }
                        }
                    }
                    return snapLines;
                }
            }
        }
    }
    

    接下来,从此基础派生用户控件:

    public partial class MyControl : UserControlBase
    {
        protected override Control SnapLineControl
        {
            get
            {
                return txtTextBox;
            }
        }
    
        ...
    
    }
    

    再次感谢您发布此消息。

        4
  •  6
  •   gunr2171    11 年前

    VB.NET版本:
    注意:您必须更改 txtDescription 到文本框或您使用的其他内部控件名称。和 ctlUserControl 对你 usercontrol 名称

    <Designer(GetType(ctlUserControl.MyCustomDesigner))> _
    Partial Public Class ctlUserControl
       '... 
       'Your Usercontrol class specific code
       '... 
        Class MyCustomDesigner
            Inherits ControlDesigner
            Public Overloads Overrides ReadOnly Property SnapLines() As IList
                Get
                    ' Code from above 
    
                    Dim lines As IList = MyBase.SnapLines
    
                    ' *** This will need to be modified to match your user control
                    Dim control__1 As ctlUserControl = TryCast(Me.Control, ctlUserControl)
                    If control__1 Is Nothing Then Return lines
    
                    ' *** This will need to be modified to match the item in your user control
                    ' This is the control in your UC that you want SnapLines for the entire UC
                    Dim designer As IDesigner = TypeDescriptor.CreateDesigner(control__1.txtDescription, GetType(IDesigner))
                    If designer Is Nothing Then
                        Return lines
                    End If
    
                    ' *** This will need to be modified to match the item in your user control
                    designer.Initialize(control__1.txtDescription)
    
                    Using designer
                        Dim boxDesigner As ControlDesigner = TryCast(designer, ControlDesigner)
                        If boxDesigner Is Nothing Then
                            Return lines
                        End If
    
                        For Each line As SnapLine In boxDesigner.SnapLines
                            If line.SnapLineType = SnapLineType.Baseline Then
                                ' *** This will need to be modified to match the item in your user control
                                lines.Add(New SnapLine(SnapLineType.Baseline, line.Offset + control__1.txtDescription.Top, line.Filter, line.Priority))
                                Exit For
                            End If
                        Next
                    End Using
    
                    Return lines
                End Get
            End Property
        End Class
    
    End Class
    
        5
  •  2
  •   BenR    17 年前

    你走对了。您需要重写设计程序中的snaplines属性,并执行如下操作:

    Public Overrides ReadOnly Property SnapLines() As System.Collections.IList
        Get
            Dim snapLinesList As ArrayList = TryCast(MyBase.SnapLines, ArrayList)
    
            Dim offset As Integer
            Dim ctrl As MyControl = TryCast(Me.Control, MyControl)
            If ctrl IsNot Nothing AndAlso ctrl.TextBox1 IsNot Nothing Then
                offset = ctrl.TextBox1.Bottom - 5
            End If
    
            snapLinesList.Add(New SnapLine(SnapLineType.Baseline, offset, SnapLinePriority.Medium))
    
            Return snapLinesList
    
        End Get
    End Property
    

    在本例中,用户控件包含一个文本框。代码添加了一个新的Snapline,它表示文本框的基线。重要的是要正确计算偏移量。