当前位置:  开发笔记 > 编程语言 > 正文

自定义Winforms控件中的基线捕捉线

如何解决《自定义Winforms控件中的基线捕捉线》经验,为你挑选了4个好方法。

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



1> Matthew M...:

作为Miral答案的更新......这里有一些"缺失的步骤",对于那些正在寻找如何做到这一点的新人.:)上面的C#代码几乎可以"插入",除了更改一些值以引用将被修改的UserControl.

需要的可能参考:
System.Design(@robyaw)

所需的用途:

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

在UserControl上,您需要以下属性:

[Designer(typeof(MyCustomDesigner))]

那么你需要一个"设计器"类,它将使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;
}

    }
  }
}


一个很大的投票(希望我能提供更多),因为你不屑一提,你需要将ControlDesigner类INSIDE你的UserControl并使用Designer属性装饰你的UserControl类,该属性指示ControlDesigner类.一旦你看到它,一切都有意义,但不是之前.干杯.

2> Miral..:

我只是有类似的需求,我这样解决了:

 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;
    }
}

这样它实际上为子控件创建了一个临时子设计器,以便找出"真正的"基线对齐线的位置.

这似乎在测试中具有相当的性能,但如果perf成为一个问题(如果内部文本框不移动),则可以将大部分代码提取到Initialize方法.

这也假定文本框是UserControl的直接子项.如果在其他方式中存在其他影响布局的控件,则偏移计算会变得有点复杂.


我们有几个控件需要它才能工作,所以我们最终把它分解为一个通用的控件设计器,我们实现了一个"ISnapable"接口,我们明确地实现并暴露了控件.这样,逻辑仍然封装在设计器中,但是通用化.

3> Robert H...:

感谢所有人的帮助.这是一个艰难的吞下去.在每个UserControl中都有一个私有子类的想法并不是很可口.

我想出了这个基类来帮助...

[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;
            }
        }
    }
}

接下来,从此基础派生您的UserControl:

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

    ...

}

再次感谢发布此内容.



4> 小智..:

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

 _
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

推荐阅读
罗文彬2502852027
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有