【问题标题】:How can I insert the EventsTab in the PropertyGrid?如何在 PropertyGrid 中插入 EventsTab?
【发布时间】:2015-02-26 20:56:34
【问题描述】:

这是交易,我有一些要插入验证类的集合,我正在尝试使其能够插入到 Visual Studio 的编辑器 IDE 中并解释所有上下文(如果还不够,请询问我)我想要到 PropertyGrid 以在 Visual Studio 的 IDE

中像这样显示它的 EventsTab

但问题是我已经检查了winforms sourcecode,据我所知,我发现为了插入EventsTab 的按钮,我们必须调用ShowEventsButton(true) PropertyGrid 的私有方法,但这不起作用(用反射调用它)

所以我到目前为止所尝试的......

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

编辑

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

编辑 2

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

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

【问题讨论】:

  • 您想在 IDE 中显示什么 - 来自集合项或验证类的事件?为了让某些东西以这种方式在 IDE 中显示,它必须是控件或组件。那么,Validator 是某种形式的控制吗?
  • 您的编辑让事情变得更加混乱。 CollectionEditor 将编辑 Validator 作用的Items。 PropGrid 可以作用于验证器类或集合项。那么这些事件位于验证器或集合项中的什么位置?在运行时 PropGrid 控件中关于事件有什么需要编辑的?
  • 您显示的属性网格是标准集合编辑器的propertyBrowser 控件。它比你想象的更远:CollectionEditor.CollectionForm.overArchingTableLayoutPanel.propertyBrowser。但是它对事件的影响非常很少,这就是它不显示的原因。我很确定它将无法将事件添加到您的表单中以获取临时集合项。
  • @Plutonix 它没有多大意义,因为当我显示它的类型全名时,它返回System.Windows.Forms.Design.VsPropertyGrid,其中它似乎只是来自 PropertyGrid 的默认继承,如here
  • 是的,它是一个 PropertyGrid。 see this 但是什么您希望 CollectionEditor 处理该事件?如果这是您所追求的,我认为它不能将事件处理程序添加到您的表单“像 VS”中。考虑列表框。您不会从项目中获取事件 - 您将永远添加/删除处理程序。取而代之的是,您会从控件中获取发生更改的摘要事件。

标签: c# .net winforms visual-studio collections


【解决方案1】:

如果我理解正确,您希望为自定义类的事件提供一种在 VS IDE 属性编辑器中显示的方式。

这可以相当简单地完成,只需对您的类进行一些更改。首先,您需要了解 VS 实际上会编译您的表单以供 IDE 设计器使用。具体来说,InitializeComponent 中的所有设计器代码都需要编译才能创建/绘制表单。

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

我已经用其他类在运行时充当普通类但增加了通过 from 设计器在 IDE 中设置属性等的能力(例如,具有ExtenderProvider 能力的类) .对您的班级的更改从以下内容开始:

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()
    {
    }
}

编译和验证器将在工具箱中可用。将一个拖到窗体/组件托盘。选择它,打开属性编辑器 et voila IDE 中显示的属性和事件:

验证器组件属性 (click for larger image)。事件视图:

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

组件的保养和喂养

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

简单的向量

作为一个组件,你的 Validator 类必须有一个简单的(无参数的)ctor。 VS 不知道如何使用上面的(string foo, int bar) 版本来实例化它。

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

ISupportInitialize

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

// 
// 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

如您所见,设计器代码所做的最后一件事是,设置完所有属性后,在您的类/组件上调用 EndInit。任何使用foobar 的初始化ctor 代码都可以简单地移到那里。

属性

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

[Browsable(false)]
public string Foo { get; set; }

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

[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int Bar  { get; set; }

对于您不希望 VS 序列化的任何属性,请使用 DesignerSerializationVisibility.Hidden

最后,OP 提到了 Validator 处理的“项目集合”。如果 Validator 上有一个集合类属性(例如Items),则会显示该属性的默认集合编辑器。这可能是可取的,也可能不是可取的,具体取决于项目是什么。您可以在此[Browsable(false)] 隐藏它。

如果您确实希望通过 IDE 添加/编辑项目,还有更多工作要做,但那是另一回事。


附录

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

Form.Validator.Items<ValidationItems>

首先,CollectionEditor 中使用的属性网格是一个内部网格。在EditorForm 上不难找到,但仅仅启用事件视图并不会神奇地赋予它在单击事件时知道该做什么的能力。由于它与集合一起工作,它对拥有集合的 Type 知之甚少,对承载该 Type 的 Form 知之甚少。

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

要为需要重新配置的项目启用表单事件。作为一个项目类,它们“属于”其他东西——验证器类/组件。如果 Items 也被重做为 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;
    }
}   

现在,Items 将作为表单组件存在并存储在 Validator 的 Items 集合中 - 类似于 DataGridView 的列。要编辑/添加事件,您仍然不能从 CollectionEditor 执行此操作,原因与之前相同,但它们可从 IDE 属性窗口中使用。

选择项目组件并像往常一样使用属性窗口将事件代码添加到设计器和表单(非常类似于原始中的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

形式:

private void validationItem1_Validating(object sender, EventArgs e)
{

}

作为一个组件,之前关于它们的所有要点现在也适用于项目。

缺点

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

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)

这种方法对我来说似乎“嘈杂”。 CollectionClass 完全能够连接到 Items 的事件,然后以单个 Validator 事件的形式冒泡到表单中。为什么要维护 15 甚至 5 个事件,而一个事件可以工作?不应该将所有这些整合到Validator 类的工作中吗?例如:

private void validator1_ValidationComplete(object sender, 
                     ValidationCompleteEventArgs e) 
{
}

ValidationCompleteEventArgs 可以报告哪些项目已验证或未验证、何时验证、为什么验证、提供CancelRemaining 功能或表单需要知道的任何内容。这与 ListBoxDataGridView 没有什么不同,它们代表它包含的内容报告事件。

【讨论】:

  • 不太像我不希望它显示在VisualStudio的属性窗口中,但在PropertyGrid控件中,visualstudio的PropertyWindow的图像仅供参考事件按钮
  • 这不是你在上面对我的问题的现已删除的回复中所说的。
  • 很抱歉我写了这么多东西,之后我意识到我放错地方了,但是我现在的互联网连接不好,所以我延迟了一些时间来删除@Plutonix 的评论
  • 您先生,是真正的 MVP,Validator(ControlValidor) 不是处理验证的人,因为在某些控件中,我希望对用户进行多重验证,顺便向用户反馈我写了我的验证类它自己处理给用户一个反馈,所以 ControlValidor 就像一个验证集合,应该有像 isEveryValidationValidated 这样的方法,所以我可以在保存某些东西或其他东西之前检查
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多