Baseline Ausrichtungslinien in benutzerdefinierten WinForms-Steuerelemente
-
01-07-2019 - |
Frage
Ich habe eine benutzerdefinierte Steuerung mit einem Textfeld auf es und ich mag die Basislinie belichten (des Textes in der Textbox) Ausrichtungslinie außerhalb der benutzerdefinierten Kontrolle. Ich weiß, dass Sie einen Designer (geerbt von Controldesigner) erstellen und Ausrichtungslinien außer Kraft setzen Zugriff auf die Ausrichtungslinien zu bekommen, aber ich frage mich, wie die Textgrundlinie einer Kontrolle zu bekommen, die ich durch meine benutzerdefinierte Kontrolle ausgesetzt.
Lösung
Ich hatte gerade ein ähnliches Bedürfnis, und ich löste es wie folgt aus:
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;
}
}
Auf diese Weise ist es tatsächlich einen temporären Unter Designern für das Substeuerelement, um die „echte“ Baseline-Ausrichtungslinie ist, um herauszufinden, wo die Schaffung.
Dies schien in der Prüfung einigermaßen performant, aber wenn perf wird ein Anliegen (und wenn das interne Textfeld bewegt sich nicht), dann können die meisten dieser Code an die Initialize-Methode extrahiert werden.
Dies setzt auch voraus, dass die Textbox ein direkter Nachkomme des Usercontrol ist. Wenn es andere Layout beeinträchtig Kontrollen in der Art und Weise sind dann die Offset-Berechnung wird ein wenig komplizierter.
Andere Tipps
Als ein Update auf die Antwort der Miral .. hier sind ein paar der „fehlenden Schritte“, für jemanden Neues, das schaut, wie dies zu tun. :) Der C # -Code oben ist fast ‚Drop-in‘ bereit, mit Ausnahme von ein paar der Werte Ändern des Usercontrol zu verweisen, die geändert werden sollen.
Mögliche Referenzen benötigt:
System.Design (@robyaw)
Usings benötigt:
using System.Windows.Forms.Design;
using System.Windows.Forms.Design.Behavior;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
Auf Ihrem Usercontrol benötigen Sie folgendes Attribut:
[Designer(typeof(MyCustomDesigner))]
Dann brauchen Sie eine „Designer“ Klasse, die die Ausrichtungslinien außer Kraft setzen müssen:
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;
}
}
}
}
Danke an alle, die für die Hilfe. Dies war eine schwierige Frage zu schlucken. Der Gedanke, eine private Unterklasse in jedem Usercontrol mit war nicht sehr schmackhaft.
Ich kam mit dieser Basisklasse bis .. zu helfen
[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;
}
}
}
}
Als nächstes leiten Sie Ihr Benutzersteuerelement von dieser Basis:
public partial class MyControl : UserControlBase
{
protected override Control SnapLineControl
{
get
{
return txtTextBox;
}
}
...
}
Nochmals vielen Dank für dieses Posting.
VB.Net Version:
Hinweis: Sie können die txtDescription
auf die Textbox oder einem anderen internen Kontroll Namen ändern, die Sie verwenden. und ctlUserControl
zu Ihrem usercontrol
Namen
<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
Sie sind auf dem richtigen Weg. Sie müssen die Ausrichtungslinien Eigenschaft in Ihrem DesignR außer Kraft zu setzen und so etwas tun:
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
In diesem Beispiel wird die Usercontrol ein Textfeld enthält. Der Code fügt eine neue Ausrichtungslinie, die die Grundlage für die Textbox darstellt. Das Wichtigste ist, die richtig Offset zu berechnen.