设计时编辑器支持控件集合

发布于 2024-08-04 13:08:51 字数 601 浏览 7 评论 0原文

我想向组件添加一个表示控件集合的属性,并有一个集合编辑器,通过它我可以轻松选择属于该集合的控件。 VS 使用以下代码自动执行我想要的操作:

    Private _controls As New List(Of Control)
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property SelectedControls() As List(Of Control)
        Get
            Return _controls
        End Get
    End Property

我获得默认的 CollectionEditor,可以添加和删除控件,并且集合被序列化。

问题是我不想添加控件,我想从表单上的其他可用控件中选择多个控件。有没有任何简单/标准的方法可以做到这一点,或者我必须编写自己的集合编辑器并运行控件集合?

尽管有大量关于集合编辑器(UITypeEditors)和其他设计时主题的材料,但我无法找到任何演示这种确切行为的链接,因此感谢任何帮助。

I'd like to add a property which represents a collection of controls to a component and have a collection editor with which I can easily select the controls that belong to the collection. VS does almost what I want automatically with the following code:

    Private _controls As New List(Of Control)
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property SelectedControls() As List(Of Control)
        Get
            Return _controls
        End Get
    End Property

I get the default CollectionEditor, can add and remove controls, and the collection is serialized.

The problem is that I don't want to add new controls, I want to select multiple controls from the other available controls on the form. Is there any easy/standard way to do this, or will I have to write my own collection editor and run through the controls collection?

Although there's plenty of material on collection editors (UITypeEditors) and other design-time topics, I haven't been able to find any links demonstrating this exact behaviour, so any help is appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

依 靠 2024-08-11 13:08:51

好吧,与此同时我已经吃过午饭并自己编写了编辑器。并没有付出多大的努力。如果有帮助的话,我很乐意分享。

编辑:解决方案摘要

我编写了一个编辑器(参见屏幕截图),它递归地列出了树视图中表单上找到的所有控件。如果控件设置了文本或图像属性,则显示文本/图像。用户可以使用复选框选择多个控件,甚至可以过滤列表以仅显示某些类型的控件。

(不过,我必须承认,由于这个编辑器仅供内部使用,所以我没有费心去检查图像属性,我只是处理几个众所周知的控件类型。)

alt text

编辑器表单中的代码实际上仅用于 UI,负责填充树、设置对预选控件列表的检查,并在用户单击“确定”关闭表单时返回所选控件的列表。

接下来,我们有一个实现 UITypeEditor 的类,我将其称为 FormControlSelectionEditor。这个类被分配给我们想要使用编辑器使用[Editor]属性的属性。它只不过是在需要时创建表单的新实例并将其显示为模式对话框。

然后是属性本身,其类型为 System.Collections.ObjectModel.ObservableCollection(Of Control)。我选择 ObservableCollection 是因为我也需要在运行时对列表的更改做出反应,但其他列表只需稍作调整即可完成。

我发现的一件事是我必须编写我的属性和编辑器,以便它们使用控件列表的副本。换句话说,UITypeEditor 代码复制存储在属性中的列表,并将其传递到编辑器表单(用于在打开表单时设置检查),当表单关闭时,我清除属性的支持列表并复制从编辑器返回的列表中的每个控件。我发现否则我在 .designer 文件中序列化时会遇到问题。我不认为事情必须是这样;我认为这更有可能是我的错误。

典型属性的代码:

    Private WithEvents _insertButtons As New System.Collections.ObjectModel.ObservableCollection(Of Control)
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    <Editor(GetType(Design.FormControlSelectionEditor), GetType(UITypeEditor))> _
    Public Property InsertButtons() As System.Collections.ObjectModel.ObservableCollection(Of Control)
        Get
            Return _insertButtons
        End Get
        Set(ByVal value As System.Collections.ObjectModel.ObservableCollection(Of Control))
            If value Is Nothing Then
                RemoveInsertButtonEventHandlers(_insertButtons)
                _insertButtons.Clear()
            Else
                ' Copy the list items passed in into the internal list
                For i As Integer = _insertButtons.Count - 1 To 0 Step -1
                    If Not value.Contains(_insertButtons.Item(i)) Then _insertButtons.RemoveAt(i)
                Next
                For Each ctl As Control In value
                    If Not _insertButtons.Contains(ctl) Then _insertButtons.Add(ctl)
                Next
            End If
        End Set
    End Property
    Private Function ShouldSerializeInsertButtons() As Boolean
        Return _insertButtons.Count > 0
    End Function
    Private Sub ResetInsertButtons()
        InsertButtons = Nothing
    End Sub

我已将编辑器放入 zip 文件中; 在此处下载

正如我之前提到的,这只是一个快速的过程。脏溶液仅供内部使用。尽管如此,我还是很感激任何改进建议。

OK, so in the mean time I've had lunch and written the editor myself. Wasn't such a great effort. I'd be glad to share, if it helps.

Edit: Solution Summary

I wrote an editor (see screenshot) which recursively lists all the controls found on the form in a treeview. If the controls have their Text or Image properties set the text/image is displayed. The user can select multiple controls with checkboxes and even filter the list to only display controls of certain types.

(I must admit, though, that since this editor was only intended for internal use, I didn't bother to check for the image property generically, I just handle a couple of well-known control types.)

alt text

The code in the editor form is really just for the UI, responsible for filling the tree, setting the checks on the list of pre-selected controls and returning the list of selected controls when the user closes the form with OK.

Next, we have a class that implements UITypeEditor, which I called FormControlSelectionEditor. This class is assigned to the properties which we want to use the editor for using the [Editor] attribute. It doesn't do much more than create a new instance of the form when required and display it as a modal dialog.

Then there are the properties themselves, which are of type System.Collections.ObjectModel.ObservableCollection(Of Control). I chose ObservableCollection because I need to react to changes to the lists at run-time as well, but other lists would do just as well with minor adaptation.

One thing I discovered is that I had to write my properties and editor such that they use copies of the lists of controls. In other words, the UITypeEditor code makes a copy of the list stored in the property and passes it to the editor form (for setting the checks when the form is opened), and when the form is closed, I clear the property's backing list and copy over each control in the list returned from the editor. I found that otherwise I had problems with serialization in the .designer file. I don't believe it has to be this way; I think it's more likely an error on my part.

Code for a typical property:

    Private WithEvents _insertButtons As New System.Collections.ObjectModel.ObservableCollection(Of Control)
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    <Editor(GetType(Design.FormControlSelectionEditor), GetType(UITypeEditor))> _
    Public Property InsertButtons() As System.Collections.ObjectModel.ObservableCollection(Of Control)
        Get
            Return _insertButtons
        End Get
        Set(ByVal value As System.Collections.ObjectModel.ObservableCollection(Of Control))
            If value Is Nothing Then
                RemoveInsertButtonEventHandlers(_insertButtons)
                _insertButtons.Clear()
            Else
                ' Copy the list items passed in into the internal list
                For i As Integer = _insertButtons.Count - 1 To 0 Step -1
                    If Not value.Contains(_insertButtons.Item(i)) Then _insertButtons.RemoveAt(i)
                Next
                For Each ctl As Control In value
                    If Not _insertButtons.Contains(ctl) Then _insertButtons.Add(ctl)
                Next
            End If
        End Set
    End Property
    Private Function ShouldSerializeInsertButtons() As Boolean
        Return _insertButtons.Count > 0
    End Function
    Private Sub ResetInsertButtons()
        InsertButtons = Nothing
    End Sub

I've put the editor into a zip file; download it here.

As I mentioned before, this was just a quick & dirty solution intended for internal use only. All the same, I'd appreciate any suggestions for improvement.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文