テキスト ボックスを含むカスタム ユーザー コントロールがあり、(テキスト ボックス内のテキストの) ベースライン スナップラインをカスタム コントロールの外に表示したいと考えています。デザイナー (ControlDesigner から継承) を作成し、SnapLines をオーバーライドしてスナップラインにアクセスすることは知っていますが、カスタム ユーザー コントロールによって公開されたコントロールのテキスト ベースラインを取得する方法を知りたいです。
5 に答える
ミラルの回答の更新として..これを行う方法を探している新しい人のために、「欠落している手順」のいくつかを次に示します。:) 上記の 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;
}
}
}
}
同様のニーズがありましたが、次のように解決しました。
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;
}
}
このようにして、「実際の」ベースライン スナップラインがどこにあるかを見つけるために、実際にサブコントロールの一時的なサブデザイナーを作成しています。
これはテストではかなりのパフォーマンスを発揮するように見えましたが、パフォーマンスが問題になる場合 (および内部テキスト ボックスが動かない場合) は、このコードのほとんどを Initialize メソッドに抽出できます。
これは、テキスト ボックスが UserControl の直接の子であることも前提としています。他のレイアウトに影響を与えるコントロールがある場合、オフセットの計算はもう少し複雑になります。
助けてくれたすべての人に感謝します。これは飲み込むのが大変でした。すべての 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;
}
}
...
}
これを投稿してくれてありがとう。
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
あなたは正しい軌道に乗っています。デザイナーで 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
この例では、ユーザー コントロールにテキスト ボックスが含まれています。このコードは、テキスト ボックスのベースラインを表す新しいスナップラインを追加します。重要なことは、オフセットを正しく計算することです。