65.9K
CodeProject 正在变化。 阅读更多。
Home

在设计时访问窗体上的控件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (6投票s)

2012年7月30日

CPOL

3分钟阅读

viewsIcon

35377

downloadIcon

482

如何在设计时为属性编辑器发现窗体上的所有控件

引言

这个技巧的重点在于,如何在 Visual Studio 中使用 Visual Basic 从属性编辑器(UITypeEditor)访问设计时窗体。

关于下载的说明

  1. 不要尝试运行该应用程序,它什么也不做
  2. 重点是,在 IDE 中,当窗体设计器打开(Simple Demo -> ExampleForm)时,您可以选择名为 ExampleComponent1 的组件,然后在属性编辑器中,TargetControls 属性是一个集合,单击省略号会显示 UITypeEditor
  3. 您可以注意到,选中的(或未选中的)控件会在 IDE 会话之间持久保存,这意味着当您构建应用程序时,该集合将在运行时可见

我正在为 .NET component 创建一个 Visual Studio 属性编辑器(UITypeEditor),该编辑器保存设计时附加到的 formcontrols 的一个子集。最初,我很难弄清楚如何做到这一点,但像往常一样,一旦你发现了答案,它就变得非常容易。

下图显示了一个使用自定义 UITypeEditor 的演示应用程序。有一个自定义组件,具有一个名为 TargetControls 的属性,该属性使用该自定义 UITypeEditor。实际的属性编辑器本身是左下方的窗体(红色边框),正如您所看到的,它包含顶部显示的窗体上的 控件 列表。该图像来自 Visual Studio 内部,不在调试模式下,所以您在顶部看到的是窗体设计器。

The Control Collection Property Editor showing a CheckedListBox with all the Controls on a Form in the Design window

背景

在运行时创建一个 Collection(Of Control) 很容易,其中 Collection 中的 ControlsForm 上的 Controls。在设计时执行此操作要困难得多 - 这就是我需要做的,所以我创建了一个 UITypeEditor,它可以使用设计时窗体上的一个或多个 Controls 来填充 ComponentControl 属性。我使用了 Creating Property Editors in DesignTime for VS.Net Easily (UITypeEditor Helper) 这篇文章,作者是 S.Serpooshan,以提供基类。

在这里,我将仅重现用于检索窗体上控件列表的代码部分,因为完整的类(希望如此)将是文章而不是技巧的主题。

Using the Code

UITypeEditor 中,有一个名为 EditValue 的方法,其工作是显示自定义控件(下拉列表或模态窗体)并根据用户与控件的交互方式更新属性。我已经删除了所有加载和显示自定义控件的周围代码以及管理更新属性的代码,以便将重点放在技巧的有趣部分。所有其他内容都可以从 S. Serpooshan 的文章中获取。

myControl 是对自定义属性编辑器控件的引用,在这种情况下,该控件是一个包含 CheckedListBox 的窗体(其名称为 AvailableControls)。

第一个 For Each 循环将项目添加到该 CheckedListBox 中,通过 EditValue 函数的 context 参数访问对设计时窗体的引用。弄清楚这个参数为您提供了一种引用设计时窗体的方法是关键,从那里开始非常容易。

第二个 For Each 循环只是确定在显示它之前,在 CheckedListBox 中要选中哪些项目,即,在用户有机会编辑它之前,保存在属性的当前值中的项目。

Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, _
ByVal provider As IServiceProvider, ByVal value As Object) As Object
    ...
    ...
    'Load the AvailableControls checked list with all form controls visible through the Designer
    For Each c As Component In context.Container.Components
        'Cycle through the components owned by the form in the designer
        If TypeOf c Is Control Then
            'if the component is a control then add it to the CheckedListBox
            myControl.AvailableControls.Items.Add(c)
        End If
    Next
    If value IsNot Nothing Then
        'If the property currently has anything in its collection 
        'then check those items in the checked list box
        'create a temporary Collection that holds the current controls held by the property
        Dim tCollection As Collection(Of Control) = CType(value, Collection(Of Control))
        Dim found As Integer
        For Each c As Control In tCollection
            'cycle through the current controls held by the property
            found = myControl.AvailableControls.Items.IndexOf(c)
            If Not found = -1 Then
                'if the control has been found in the CheckedListBox 
                'then set its checked state to true
                myControl.AvailableControls.SetItemChecked(found, True)
            End If
        Next
    End If
    ...
    ...
End Function

要使用此代码,您需要创建一个自定义组件,该组件具有类型为 Collection(Of Control)public 属性。然后,您需要将其 EditorAttribute 设置为 UITypeEditor 的类名。

Public Class ControlCollectionUITypeEditor
    Inherits UITypeEditor
    ...
    ...
End Class

Public Class ExampleComponent
    Inherits Component
    Private _TargetControls As New Collection(Of Control)
    'EditorAttribute tells the Property Grid to use this editor to change the property
    'DesignerSerializationVisibility stops the compiler trying to 
    'serialize a Collection object (since it can't be serialized)
    <EditorAttribute(GetType(ControlCollectionUITypeEditor), _
    GetType(System.Drawing.Design.UITypeEditor))>
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
    Public Property TargetControls As Collection(Of Control)
        Get
            Return _TargetControls
        End Get
        Set(ByVal value As Collection(Of Control))
            'Validity checking, event raising etc. deliberately left out for simplicity
            _TargetControls = value
        End Set
    End Property
End Class

关注点

我曾经在 MSDN Visual Basic General 论坛上与几个人讨论过这个问题,其主要内容是“你做不到”。

只要你足够努力,你就可以!

历史

  • 版本 1:原始技巧
  • 版本 2:根据 2013 年 10 月 29 日的第 29 个问题的答案添加了下载
© . All rights reserved.