如何在PropertyGrid中插入EventsTab?

Pat*_*ick 2 .net c# collections visual-studio winforms

这是交易,我有一些集合要插入到验证类中,我试图让它能够插入到Visual Studio的编辑器IDE中并解释所有上下文(如果还不够,请问我)我想要PropertyGrid以显示EventsTab这样在Visual Studio的IDEPropertyGrid VS Editor中的EventsTab

但问题是我已经检查了winforms源代码并且我能理解我已经发现为了插入Button for EventsTab我们必须调用ShowEventsButton(true)PropertyGrid的私有方法但是不能工作(用反射调用它)

那么到目前为止我尝试了什么......

  • Caliing AddRefTab使用参数传递EventsTab(私有方法)
  • 使用true参数调用SetupToolbar(私有方法)
  • 调用RefreshTabs
  • 将所有TooltipItens设置为Visible
  • 调用ShowEventsButton(true)

编辑

我在这个方案中有两个类,其中一个是Validation类,它继承自IValidation接口,它有我想在propertyGrid中显示的事件,另一个类是一个ControlValidator,它派生自一个组件并且有一个列表验证

编辑2

更具体地说,我想要完成的是在这个CollectionEditor中使用CollectionEditor(用于编辑DataGridView的列的相同窗口)我想让它在PropertyGrid中显示EventsTab(实际上我想要制作它)它与VisualStudio IDE的PropertyTab完全相同,但我不在那部分但是,所以我想要显示的事件和属性是ControlValidator(组件)的List/Collection

让我试着说清楚一点 类图 正如您所看到的,Control Validator有一个IValidation接口的集合,它是组件所以它应该并且正在这样工作 ControlValidator应该正常工作 你可以看到它没有在IDE中显示事件选项卡,因为它没有任何事件,但如果你双击controlValidator的Validations属性,它会打开CollectionEditor,其中有一个PropertyGrid CollectionEditor 作为一个PropertyGrid,我试图让它显示eventsTab(我无法以我在其中列出的任何方式显示它)

Ňɏs*_*arp 5

如果我理解正确,您希望为VS IDE属性编辑器中的Custom类提供事件.

只需对您的班级进行一些更改,就可以相当简单地完成此操作.首先,您需要了解VS实际上编译您的表单以便在IDE设计器中使用.具体来说,InitializeComponent需要编译所有设计器代码才能创建/绘制表单.

这意味着为了让您的类事件(和道具)在IDE中显示,您的类需要是Component(或Control),因此它可以像IDE属性编辑器一样进行编译.它不能是您在运行时实例化的类,因为不会检查表单编辑器的代码.

我已经多次使用这些类,这些类在运行时可以作为普通类,但是通过from设计器(ExtenderProvider例如,具有异能的类)可以在IDE中设置属性等.你班级的变化从这样的事情开始:

class Validator:Component, ISupportInitialize
{
    // fake props
    public string Foo { get; set; }
    public int Bar  { get; set; }

    public event ValidatingEventHandler Validating;
    public delegate void ValidatingEventHandler(object sender, EventArgs e);

    public event ValidatedEventHandler Validated;
    public delegate void ValidatedEventHandler(object sender, EventArgs e);

    public Validator(string foo, int bar) 
    { 
    }
    public Validator()
    {
    }

    // ISupportInitialize methods
    public void BeginInit()
    { 
    }
    public void EndInit()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

Compile和Validator将在工具箱中提供.将一个拖到窗体/组件托盘中.选择它,打开属性编辑器等瞧属性和事件显示在IDE中:

在此输入图像描述

验证器组件属性(单击查看大图).活动视图:

在此输入图像描述

双击所需的事件,VS将添加骨架事件处理程序供您编辑.

组件的保养和喂养

只需让您的类继承自Component就能完成大部分工作.有一些与组件相关的东西是必需的或可能出现的.其中大多数是简单的问题和修复.

简单的Ctor

作为Component,您的Validator类必须具有简单(无参数)的ctor.VS不知道如何使用(string foo, int bar)上面的版本来实例化它.

如果您的代码依赖于这些参数来初始化构造函数中的其他内容,则会导致问题.答案是这样的ISupportIntialize.

ISupportInitialize接口

此接口提供对将从设计器代码调用的BeginInit和EndInit方法的支持,因为它现在负责设置Component的属性:

// 
// validator1
// 
this.validator1.Bar = 0;
this.validator1.Foo = null;
this.validator1.Validating += new Validator.ValidatingEventHandler(this.validator1_Validating);
...
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.tableLayoutPanel1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.validator1)).EndInit();
this.ResumeLayout(false);

...
private Validator validator1;          // note: no params
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,在设置了所有属性之后,设计器代码执行的最后一项操作是EndInit在类/组件上调用.使用foobar可以简单地将任何初始化代码移动到那里.

属性

现在,将在IDE中显示属性以及类的事件.如果您希望隐藏其中任何一个(可能只有在有实际项目需要验证时才有意义),您可以使用以下Browsable属性阻止它们显示在属性窗格中:

[Browsable(false)]
public string Foo { get; set; }
Run Code Online (Sandbox Code Playgroud)

为了确保VS 确实将您希望通过IDE管理的那些序列化,请使用以下DesignerSerialization属性:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int Bar  { get; set; }
Run Code Online (Sandbox Code Playgroud)

使用DesignerSerializationVisibility.Hidden你不想VS序列化的任何财产.

最后,OP提到了一个"项目集合",其中的Validator作品.如果Validator上有一个集合类属性(例如Items),则将显示该属性的默认集合编辑器.根据物品的不同,这可能是也可能不是.你可以[Browsable(false)]在这上面隐藏它.

如果您确实希望通过IDE添加/编辑项目,还有更多工作要做,但这是另一个鱼.


附录

这是关于在CollectionEditor中访问Item Events的新兴愿,并且(显然)在点击时为它们创建了代码(创建在哪里,我不确定).这在设计和实践中都存在许多问题.我假设这样的结构:

Form.Validator.Items<ValidationItems>
Run Code Online (Sandbox Code Playgroud)

首先,在CollectionEditor内部使用的属性网格是内部网格.它不难找到EditorForm,但只是启用事件视图不会让它有能力知道当你点击一个事件时该怎么做.由于它正在使用该集合,因此它对拥有该集合的Type知之甚少,而对于托管Type的Form则知之甚少.

事件视图在CollectionEditor中关闭,因为它无法将事件代码添加到表单(Items的曾祖父对象!),因为没有要引用的表单级对象.它不能/不会将事件添加到您的集合类代码中,因为您的代码没有设计器文件.最后,集合属性的主要要求是集合实现IList.如果您的集合属性是普通的List或Collection 变量,没有要修改的代码文件.

要为项目启用表单事件,需要重新配置它.作为Item类,它们'属于'其他东西 - Validator类/组件.如果项目也被重新设计为a Component,则表单级事件变为可能:

[Serializable]
public class ValidationItem: Component
{
    [DefaultValue("")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public string DisplayName { get; set; }

    [DefaultValue(-1)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public int Value { get; set; }

    public event ValidatingEventHandler Validating;
    public delegate void ValidatingEventHandler(object sender, EventArgs e);

    public ValidationItem() 
    {
        Name = "New Item";
        Value = 0;
    }
}   
Run Code Online (Sandbox Code Playgroud)

现在,Items将作为表单组件存在,并存储在Validator的Items集合中 - 类似于DataGridView的列.要编辑/添加事件,出于与以前相同的原因,您仍然无法从CollectionEditor执行此操作,但可以从IDE Properties Window中获取它们.

选择项目组件并正常使用属性窗口将事件代码添加到设计器和表单(非常类似于Validator原始组件):

//  (Designer)
// validationItem1
// 
this.validationItem1.DisplayName = "New Item";
this.validationItem1.Value = 0;
this.validationItem1.Validating += new ValidationItem.ValidatingEventHandler(this.validationItem1_Validating);

...
private ValidationItem validationItem1;     // persistent form var
Run Code Online (Sandbox Code Playgroud)

形式如下:

private void validationItem1_Validating(object sender, EventArgs e)
{

}
Run Code Online (Sandbox Code Playgroud)

作为一个组件,关于它们的所有早期要点现在也适用于这些项目.

缺点

a)如果有很多项目,ValidationItems组件托盘中会有很多项目.我要问自己的第一件事是我是否需要Validator类以及所有这些项目作为单独的表单级别对象.

b)与控件一样,如果删除一个,它将从设计器中删除代码,但不删除表单.更改/更新项目时可能会导致重复的代码(集合内容往往更不稳定):

private void validationItem1_Validating(object sender, EventArgs e)
...
private void validationItem1_Validating_1(object sender, EventArgs e)
...
private void validationItem1_Validating_2(object sender, EventArgs e)
Run Code Online (Sandbox Code Playgroud)

这种方法对我来说似乎"吵".CollectionClass完全能够连接到Items的事件,然后以单个Validator事件的形式冒泡到表单.当一个人可以工作时,为什么还要维持15个甚至5个事件​​?不应该巩固所有属于Validator班级工作的一部分吗?例如:

private void validator1_ValidationComplete(object sender, 
                     ValidationCompleteEventArgs e) 
{
}
Run Code Online (Sandbox Code Playgroud)

ValidationCompleteEventArgs可以报​​告哪个项目确实或未验证,何时,为什么,提供CancelRemaining能力或表格需要知道的任何内容.这与代表其包含的内容的事件ListBoxDataGridView报告事件没有什么不同.