我正在关注
有人可以向我解释如何在C#或VB.NET中做到这一点.
我被困在传递给 UITypeEditor.EditValue()方法的值上,我认为这是调用/显示编辑器的方法,但是我不确定我使用哪个值必须传递给第一个参数(它接受 IServiceProvider 或 ITypeDescriptorContext ).我看到了 此相关答案 ,但我认为应该比创建更直接/更简便的方法一个实现 IServiceProvider 和 ITypeDescriptorContext ...的类,因为我将运行特定的 UITypeEditor ( MultilineStringEditor ).
这是我到目前为止所得到的;当我单击编辑文本行..."(Edit Text Lines ...)操作项目时,什么也没有发生,没有任何例外,只有一无所获;我不确定这是好还是坏的信号,因为如果我尝试将其他类型的值传递给 UITypeEditor.EditValue()方法的第一个参数,那么我将得到无效类型强制转换的异常当我点击我的自定义操作项时.
C#代码版本:
公共类MyControlActionList:DesignerActionList {私人DesignerActionUIService designerActionUISvc;公开的新MyControl组件{获取{return(MyControl)base.Component;}}公共MyControlActionList(MyControl组件):基本(组件){//缓存对DesignerActionUIService的引用,以便可以刷新DesigneractionList.this.designerActionUISvc =(DesignerActionUIService)GetService(typeof(DesignerActionUIService));}公共重写DesignerActionItemCollection GetSortedActionItems(){DesignerActionItemCollection项目=新的DesignerActionItemCollection();items.Add(new DesignerActionMethodItem(this,"EditTextLines","Edit Text Lines ...","Behavior",打开线集合编辑器",false));退换货品;}公共无效EditTextLines(){PropertyDescriptor pd = TypeDescriptor.GetProperties(this.Component)("Text");MultilineStringEditor编辑器=(MultilineStringEditor)pd.GetEditor(typeof(UITypeEditor));editor.EditValue((IServiceProvider)this.GetService(typeof(MultilineStringEditor)),this.Component.Text);}}VB.NET代码版本:
公共类MyControlActionList:继承DesignerActionList私人designerActionUISvc作为DesignerActionUIServicePublic Shadows ReadOnly属性组件作为MyControl得到返回DirectCast(MyBase.Component,MyControl)结束获取最终财产Public Sub New(ByVal组件为MyControl)MyBase.New(组件)'缓存对DesignerActionUIService的引用,以便可以刷新DesigneractionList.Me.designerActionUISvc = DirectCast(GetService(GetType(DesignerActionUIService)),DesignerActionUIService)结束子公共重写函数GetSortedActionItems()作为DesignerActionItemCollection昏暗的项目作为新的DesignerActionItemCollection()items.Add(New DesignerActionMethodItem(Me,"EditTextLines","Edit Text Lines ...","Behavior",打开行集合编辑器",False))退换货品结束功能公共子EditTextLines()昏暗的pd作为PropertyDescriptor = TypeDescriptor.GetProperties(Me.Component)("Text")昏暗的编辑器为MultilineStringEditor = DirectCast(pd.GetEditor(GetType(UITypeEditor)),MultilineStringEditor)editor.EditValue(CType(Me.GetService(GetType(MultilineStringEditor)),IServiceProvider),Me.Component.Text)结束子末级 解决方案您要查找的编辑器是 StringArrayEditor ,用于编辑 string [] 属性.它也是 System.Design 的内部.
要在设计时使用设计器动词显示 StringArrayEditor ,您需要:
示例
要使该示例正常工作,将以下代码复制并粘贴到Windows Forms应用程序中的文件中就足够了.不要忘记添加对 System.Design 程序集的引用.生成项目后,可以将 MyControl 的实例拖放到窗体上,并使用智能标记窗口,可以单击 Edit Text Lines ... 链接以显示 StringArrayEditor 对话框,以编辑 Line (以及因此的 Text )属性.这是代码:
使用系统;使用System.ComponentModel;使用System.ComponentModel.Design;使用System.Drawing.Design;使用System.Linq;使用System.Windows.Forms;使用System.Windows.Forms.Design;[Designer(typeof(MyControlDesigner))]公共类MyControl:控件{公共字符串[]行{得到{返回this.Text.Split(new string [] {Environment.NewLine},StringSplitOptions.None);}放{如果(值!=空)this.Text = string.Join(Environment.NewLine,value);}}} 公共类MyControlDesigner:ControlDesigner{公共重写DesignerActionListCollection ActionLists{得到{var list = new DesignerActionListCollection();list.Add(new MyControlActionList(this));返回清单;}}} 公共类MyControlActionList:DesignerActionList{MyControlDesigner设计器;MyControl控件{get {return(MyControl)designer.Control;}}公共MyControlActionList(MyControlDesigner设计器):基础(designer.Component){this.designer =设计师;}公共重写DesignerActionItemCollection GetSortedActionItems(){DesignerActionItemCollection项目=新的DesignerActionItemCollection();items.Add(new DesignerActionMethodItem(this,"EditTextLines",编辑文本行...",行为",打开行集合编辑器",false));退换货品;}公共无效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);如果(!result.SequenceEqual(lines))linesPropertyDescriptor.SetValue(this.Control,result);}} 公共类TypeDescriptionContext:ITypeDescriptorContext,IServiceProvider,IWindowsFormsEditorService{私有控制组件;私有PropertyDescriptor EditingProperty;公共TypeDescriptionContext(控件组件,PropertyDescriptor属性){thisponent =组件;editingProperty =属性;}公共IContainer容器{获取{返回component.Container;}}公共对象实例{get {返回组件;}}公共无效OnComponentChanged(){var svc =(IComponentChangeService)this.GetService(typeof(IComponentChangeService));svc.OnComponentChanged(component,editingProperty,null,null);}公共布尔OnComponentChanging(){返回true;}public PropertyDescriptor PropertyDescriptor {get {return editProperty;}}公共对象GetService(Type serviceType){如果((serviceType == typeof(ITypeDescriptorContext))||(serviceType == typeof(IWindowsFormsEditorService))返回这个;返回component.Site.GetService(serviceType);}公共无效CloseDropDown(){}公共无效DropDownControl(控制控件){}DialogResult IWindowsFormsEditorService.ShowDialog(窗体对话框){IUIService服务=(IUIService)(this.GetService(typeof(IUIService)));返回service.ShowDialog(dialog);}}注意
您可以找到针对以下问题而提出的 ITypeDescriptorContext , IServiceProvider 和 IWindowsFormsEditorService 接口的更强大的实现:
- 如何在继承的ControlDesigner类中获取ITypeDescriptorContext和IServiceProvider
然后在您的自定义 ActionList 类中,您可以通过以下方式显示 Lines 属性编辑器:
EditorServiceContext.EditValue(this.designer,base.Component,"Lines");与 RichTextBoxDesigner 中使用的方法完全相同.
I'm following this C# article to learn how to create an ActionList and Action Items, however the article is only focused to action items of type DesignerActionPropertyItem...
I would like to create an item of type DesignerActionMethodItem to call a method that must open a MultilineStringEditor to edit the text lines of the control, just the same action item that we can see in a default RichTextBox control:
Someone could explain me how to do this in C# or VB.NET?.
I'm stuck on the values to pass to the UITypeEditor.EditValue() method, I think that is the method that invokes/displays the editor, but I'm not sure which value I must pass to the first parameter (it accepts an IServiceProvider or ITypeDescriptorContext). I seen this related answer but I think there should exist a more direct/easier way than creating a class that implements IServiceProvider and ITypeDescriptorContext... since I will to run a specific UITypeEditor (MultilineStringEditor).
This is what I got so far; when I click on the "Edit Text Lines..." action item nothing happens, any exception, just nothing of nothing; I'm not sure whether that is a good or bad signal, because if I try to pass other kind of values to the first parameter of UITypeEditor.EditValue() method then I got exceptions of invalid type casting when I click on my custom action item.
C# code version:
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 code version:
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解决方案
The editor which you are looking for is StringArrayEditor which is used to edit string[] properties. It also is internal to System.Design.
To show StringArrayEditor at design-time using a designer verb you need to:
Example
To make the example working, it's enough to copy and paste following code to a file in your Windows Forms application. Don't forget to add reference to System.Design assembly. After you build the project, you can drop an instance of MyControl on a form and using the smart tag window, you can click on Edit Text Lines... link to show StringArrayEditor dialog to edit the Line (and consequently Text) property. Here is the code:
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) { thisponent = 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); } }
Note
You can find a more robust implementation of ITypeDescriptorContext, IServiceProvider and IWindowsFormsEditorService interfaces which I posed in response to this question:
- How to obtain ITypeDescriptorContext and IServiceProvider in inherited ControlDesigner class
Then in your custom ActionList class, you can show Lines property editor this way:
EditorServiceContext.EditValue(this.designer, base.Component, "Lines");That's exactly the same way which is used in RichTextBoxDesigner.
更多推荐
在设计时显示MultilineStringEditor以编辑编辑控件的行?
发布评论