我在 this C# article 之后了解如何创建ActionList和Action Items,但本文仅关注DesignerActionPropertyItem
类型的操作项。
我想创建一个DesignerActionMethodItem
类型的项来调用一个方法,该方法必须打开MultilineStringEditor
来编辑控件的文本行,就像我们在一个操作中看到的一样。默认 RichTextBox 控件:
有人可以解释一下如何在C#或VB.NET中执行此操作吗?
我坚持要传递给UITypeEditor.EditValue()
方法的值,我认为这是调用/显示编辑器的方法,但我不确定我必须传递给哪个值第一个参数(它接受IServiceProvider
或ITypeDescriptorContext
)。我看到 this related answer ,但我认为应该存在比创建实现IServiceProvider
和ITypeDescriptorContext
的类更直接/更简单的方法...因为我会运行特定的UITypeEditor
(MultilineStringEditor
)。
这是我到目前为止所得到的;当我点击"编辑文字行..."行动项没有任何反应,任何例外,什么都不是;我不确定这是好信号还是坏信号,因为如果我尝试将其他类型的值传递给UITypeEditor.EditValue()
方法的第一个参数,那么当我点击我的时候,我得到了无效类型转换的例外情况自定义操作项。
C#代码版本:
public class MyControlActionList : DesignerActionList {
private DesignerActionUIService designerActionUISvc;
public new MyControl Component {
get { return (MyControl)base.Component; }
}
public MyControlActionList(MyControl component) : base(component) {
// Cache a reference to DesignerActionUIService, so the DesigneractionList can be refreshed.
this.designerActionUISvc = (DesignerActionUIService)GetService(typeof(DesignerActionUIService));
}
public override DesignerActionItemCollection GetSortedActionItems() {
DesignerActionItemCollection items = new DesignerActionItemCollection();
items.Add(new DesignerActionMethodItem(this, "EditTextLines", "Edit Text Lines...", "Behavior", "Opens the Lines collection editor", false));
return items;
}
public void EditTextLines(){
PropertyDescriptor pd = TypeDescriptor.GetProperties(this.Component)("Text");
MultilineStringEditor editor = (MultilineStringEditor)pd.GetEditor(typeof(UITypeEditor));
editor.EditValue((IServiceProvider)this.GetService(typeof(MultilineStringEditor)), this.Component.Text);
}
}
VB.NET代码版本:
Public Class MyControlActionList : Inherits DesignerActionList
Private designerActionUISvc As DesignerActionUIService
Public Shadows ReadOnly Property Component As MyControl
Get
Return DirectCast(MyBase.Component, MyControl)
End Get
End Property
Public Sub New(ByVal component As MyControl)
MyBase.New(component)
' Cache a reference to DesignerActionUIService, so the DesigneractionList can be refreshed.
Me.designerActionUISvc = DirectCast(GetService(GetType(DesignerActionUIService)), DesignerActionUIService)
End Sub
Public Overrides Function GetSortedActionItems() As DesignerActionItemCollection
Dim items As New DesignerActionItemCollection()
items.Add(New DesignerActionMethodItem(Me, "EditTextLines", "Edit Text Lines...", "Behavior", "Opens the Lines collection editor", False))
Return items
End Function
Public Sub EditTextLines()
Dim pd As PropertyDescriptor = TypeDescriptor.GetProperties(Me.Component)("Text")
Dim editor As MultilineStringEditor = DirectCast(pd.GetEditor(GetType(UITypeEditor)), MultilineStringEditor)
editor.EditValue(CType(Me.GetService(GetType(MultilineStringEditor)), IServiceProvider), Me.Component.Text)
End Sub
End Class
答案 0 :(得分:1)
您要查找的编辑器是StringArrayEditor
,用于编辑string[]
属性。它也是System.Design
的内部。
要使用设计师动词在设计时显示StringArrayEditor
,您需要:
string[] Lines
属性,用于获取或设置Text
属性中不同的文本行。实际上,我们将编辑此属性,导致Text
属性被编辑。Lines
属性的默认编辑器,请创建一个实现ITypeDescriptorContext
,IServiceProvider
和IWindowsFormsEditorService
接口的类。这样,在获得Lines
属性的编辑器后,您可以调用其显示所需编辑器的EditValue
方法。ActionList
。在此方法中,您应该使用在上一步中创建的类来显示属性的编辑器,并在编辑属性后,设置已编辑的属性值。ActionLists
以返回自定义操作列表。 Designer
属性装饰控件,为控件注册自定义设计器。示例强>
要使示例正常工作,只需将以下代码复制并粘贴到Windows窗体应用程序中的文件即可。别忘了添加对System.Design
汇编的引用。构建项目后,您可以在表单上删除MyControl
的实例并使用智能标记窗口,您可以单击Edit Text Lines...
链接以显示StringArrayEditor
对话框以编辑{{ 1}}(以及Line
)属性。这是代码:
Text
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.Design;
[Designer(typeof(MyControlDesigner))]
public class MyControl : Control
{
public string[] Lines
{
get
{
return this.Text.Split(new string[] { Environment.NewLine },
StringSplitOptions.None);
}
set
{
if (value != null)
this.Text = string.Join(Environment.NewLine, value);
}
}
}
public class MyControlDesigner : ControlDesigner
{
public override DesignerActionListCollection ActionLists
{
get
{
var list = new DesignerActionListCollection();
list.Add(new MyControlActionList(this));
return list;
}
}
}
public class MyControlActionList : DesignerActionList
{
MyControlDesigner designer;
MyControl Control { get { return (MyControl)designer.Control; } }
public MyControlActionList(MyControlDesigner designer) : base(designer.Component)
{
this.designer = designer;
}
public override DesignerActionItemCollection GetSortedActionItems()
{
DesignerActionItemCollection items = new DesignerActionItemCollection();
items.Add(new DesignerActionMethodItem(this, "EditTextLines",
"Edit Text Lines...", "Behavior", "Opens the Lines collection editor", false));
return items;
}
public void EditTextLines()
{
var linesPropertyDescriptor = TypeDescriptor.GetProperties(this.Control)["Lines"];
var context = new TypeDescriptionContext(this.Control, linesPropertyDescriptor);
var editor =(UITypeEditor)linesPropertyDescriptor.GetEditor(typeof(UITypeEditor));
var lines = (this.Control).Lines;
var result = (string[])editor.EditValue(context, context, lines);
if (!result.SequenceEqual(lines))
linesPropertyDescriptor.SetValue(this.Control, result);
}
}
注意强>
您可以找到针对此问题我提出的public class TypeDescriptionContext : ITypeDescriptorContext, IServiceProvider,
IWindowsFormsEditorService
{
private Control component;
private PropertyDescriptor editingProperty;
public TypeDescriptionContext(Control component, PropertyDescriptor property)
{
this.component = component;
editingProperty = property;
}
public IContainer Container { get { return component.Container; } }
public object Instance { get { return component; } }
public void OnComponentChanged()
{
var svc = (IComponentChangeService)this.GetService(
typeof(IComponentChangeService));
svc.OnComponentChanged(component, editingProperty, null, null);
}
public bool OnComponentChanging() { return true; }
public PropertyDescriptor PropertyDescriptor { get { return editingProperty; } }
public object GetService(Type serviceType)
{
if ((serviceType == typeof(ITypeDescriptorContext)) ||
(serviceType == typeof(IWindowsFormsEditorService)))
return this;
return component.Site.GetService(serviceType);
}
public void CloseDropDown() { }
public void DropDownControl(Control control) { }
DialogResult IWindowsFormsEditorService.ShowDialog(Form dialog)
{
IUIService service = (IUIService)(this.GetService(typeof(IUIService)));
return service.ShowDialog(dialog);
}
}
,ITypeDescriptorContext
和IServiceProvider
接口的更强大的实现:
然后在您的自定义IWindowsFormsEditorService
课程中,您可以通过以下方式显示ActionList
属性编辑器:
Lines
这与EditorServiceContext.EditValue(this.designer, base.Component, "Lines");
中使用的方式完全相同。