简体   繁体   English

如何在自定义 UserControl(.Net 4、Winforms)上使用项目集合编辑器?

[英]How to use an Items Collection Editor on a custom UserControl (.Net 4, Winforms)?

I created a UserControl that contains a custom ToolStrip Control .我创建了一个包含自定义ToolStrip ControlUserControl While using the UserControl throughout an application, the ToolStrip control cannot be accessed directly, as it is logically embedded in the UserControl .在整个应用程序中使用UserControl ,不能直接访问ToolStrip控件,因为它在逻辑上嵌入在UserControl

So, to access the items of the ToolStrip I defined a readonly property in the UserControl class that returns the items of the ToolStrip.因此,为了访问ToolStrip的项目,我在UserControl类中定义了一个readonly属性,该属性返回 ToolStrip 的项目。

Now, programmatically the items of the ToolStrip can be edited, by using the UserControl.Items property, but I cannot do the same in the design mode.现在,可以使用UserControl.Items属性以编程方式编辑ToolStrip的项目,但我无法在设计模式下执行相同操作。

Like someone drags the UserControl from the ToolBox to the form, goes to the propertyGrid , chooses the Item's property and manipulates the items of the ingrained ToolStrip accordingly;就像有人将UserControlToolBox拖到窗体上,转到propertyGrid ,选择 Item 的属性并相应地操作根深蒂固的ToolStrip的项目; just as we do with any standard ToolStrip control's items collection with the help of Items Collection Editor .就像我们在项目Collection Editor的帮助下处理任何标准ToolStrip控件的项目集合一样。

Herein, though the Items property of the UserControl shows in the propertyGrid , it is not usable and everytime I click, it shows an error message这里,虽然UserControlItems属性显示在propertyGrid ,但它不可用,每次单击时都会显示错误消息

Value cannot be null.值不能为空。 Parameter name: value参数名称:值

I'm sure this is because the property is declared just as readonly and I need to hike more so that, when it is clicked in the propertyGrid, the Items Collection Editor pops-up with the items of the ToolStrip and can be handled consequently.我确定这是因为该属性被声明为只读,我需要更多地加息,以便在 propertyGrid 中单击它时,Items Collection Editor弹出ToolStrip的项目,因此可以进行处理。

So how should I be doing this?那么我该怎么做呢?

You can do that by exposing the ToolStrip itself, but it is not a good idea.您可以通过公开ToolStrip本身来做到这一点,但这不是一个好主意。 A UserControl shouldn't expose its internal controls. UserControl不应公开其内部控件。

If your user control has just a ToolStrip you should consider using a CustomControl which is a class that inherits ToolStrip and you get all its functionality including design capabilities for free.如果您的用户控件只有一个ToolStrip您应该考虑使用CustomControl ,它是一个继承ToolStrip的类,您可以免费获得其所有功能,包括设计功能。

I have been working on the issue for a while, and the two most widely held ideas I got are: 1) Exposing the ToolStrip as a property.我一直在研究这个问题一段时间,我得到的两个最广泛的想法是:1) 将 ToolStrip 作为属性公开。 2) Use a ControlDesigner for the UserControl and set EnableDesignMode for the ToolStrip. 2) 为 UserControl 使用 ControlDesigner 并为 ToolStrip 设置 EnableDesignMode。

But somehow none of them actually served my purpose, as exposing the ToolStrip would let the user have full control on it, which was not my objective.但不知何故,它们都没有真正达到我的目的,因为公开 ToolStrip 会让用户完全控制它,这不是我的目标。 The second option would even put the user up with deleting the ToolStrip.第二个选项甚至会让用户删除 ToolStrip。 Hence I had to figure out a different approach.因此,我不得不想出一种不同的方法。 That's when I tripped upon the CollectionBase class.那是我在 CollectionBase 类上绊倒的时候。

As it says, the CollectionBase class is the abstract base class for a strongly typed collection.正如它所说, CollectionBase 类是强类型集合的抽象基类。 So how about maintaining the ToolStrip item collection through it?那么如何通过它维护 ToolStrip 项目集合呢? I created an instance of the CollectionBase class and regulated the addition, modification, fetching and deletion of the ToolStrip items through it.我创建了一个 CollectionBase 类的实例,并通过它来规范 ToolStrip 项目的添加、修改、获取和删除。 Each item in the collection hails from a class that is inherited from the ToolStripButton class.集合中的每一项都来自一个继承自 ToolStripButton 类的类。 In that way, individual item can be handled as any standard ToolStripButton and you can hide or show the properties to the user accordingly.这样,单个项目可以作为任何标准 ToolStripButton 处理,您可以相应地向用户隐藏或显示属性。 Lastly, the ToolStrip in question is set as the parent of the CollectionBase which eventually becomes the parent of each ToolStripItem too.最后,有问题的 ToolStrip 被设置为 CollectionBase 的父级,它最终也成为每个 ToolStripItem 的父级。 Here's the concept:这是概念:

Imports System.ComponentModel
Imports System.Windows.Forms
Imports Office2003
Imports System.Drawing
Imports System.Windows.Forms.Design

Public Class MyUserControl
    Private _Buttons As MyUserControlButtons
    Public Event MyUserControlButtonClicked(ByVal Sender As MyUserControlButton)

    Public Sub New()
        MyBase.New()

        'This call is required by the Component Designer.
        InitializeComponent()

        _Buttons = New MyUserControlButtons(MyToolStrip)
    End Sub

    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    Public ReadOnly Property Buttons As MyUserControlButtons
        Get
            Return _Buttons
        End Get
    End Property

    Private Sub MyToolStrip_ItemClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles MyToolStrip.ItemClicked
     'Check if the ToolStrip item clicked is a ToolStripButton...
        If TypeOf e.ClickedItem Is ToolStripButton Then
            'Insert your code here...

         'Raise the custom event.
            RaiseEvent MyUserControlButtonClicked(Item)
        End If
    End Sub
End Class

#Region "Manager classes for MyUserControl buttons."

Public Class MyUserControlButtons
    Inherits CollectionBase
    Private _Parent As ToolStrip

    ''' <summary>
    ''' Initializes a new instance of the MyUserControlButtons class.
    ''' </summary>
    ''' <param name="Holder">The ToolStrip that contains the items of the MyUserControlButtons class.</param>
    Public Sub New(ByVal Holder As ToolStrip)
        MyBase.New()
        _Parent = Holder
    End Sub

    ''' <summary>
    ''' The ToolStrip that contains this item.
    ''' </summary>
    Public ReadOnly Property Parent() As ToolStrip
        Get
            Return _Parent
        End Get
    End Property

    ''' <summary>
    ''' Gets the element at the specified index.
    ''' </summary>
    ''' <param name="Index">The zero-based index of the element to get.</param>
    Default Public ReadOnly Property Item(ByVal Index As Integer) As MyUserControlButton
        Get
            Return CType(List(Index), MyUserControlButton)
        End Get
    End Property

    ''' <summary>
    ''' Adds an item to the collection.
    ''' </summary>
    Public Function Add() As MyUserControlButton
        Return Me.Add
    End Function

    ''' <summary>
    ''' Adds an item to the collection.
    ''' </summary>
    ''' <param name="Value">The object to add to the collection.</param>
    Public Sub Add(ByVal Value As MyUserControlButton)
        List.Add(Value)
        Value.Parent = Me.Parent
    End Sub

    ''' <summary>
    ''' Adds an item to the collection.
    ''' </summary>
    ''' <param name="Name">The name of the object to add to the collection.</param>
    ''' <param name="Image">The image of the object to add to the collection.</param>
    Public Function Add(ByVal Name As String, ByVal Image As Image) As MyUserControlButton
        Dim b As MyUserControlButton = New MyUserControlButton(Me.Parent)
        b.Name = Name
        b.Text = Name
        b.Image = Image
        Me.Add(b)
        Return b
    End Function

    ''' <summary>
    ''' Adds an item to the collection.
    ''' </summary>
    ''' <param name="Name">The name of the object to add to the collection.</param>
    ''' <param name="Text">The text of the object to add to the collection.</param>
    ''' <param name="Image">The image of the object to add to the collection.</param>
    Public Function Add(ByVal Name As String, ByVal Text As String, ByVal Image As Image) As MyUserControlButton
        Dim b As MyUserControlButton = New MyUserControlButton(Me.Parent)
        b.Name = Name
        b.Text = Text
        b.Image = Image
        Me.Add(b)
        Return b
    End Function

    ''' <summary>
    ''' Removes the first occurence of a specific object from the collection.
    ''' </summary>
    ''' <param name="Value">The object to be removed.</param>
    Public Sub Remove(ByVal Value As MyUserControlButton)
        List.Remove(Value)
    End Sub

    ''' <summary>
    ''' Determines the index of a specific item in the collection.
    ''' </summary>
    ''' <param name="Value">The object to locate in the collection.</param>
    Public Function IndexOf(ByVal Value As Object) As Integer
        Return List.IndexOf(Value)
    End Function

    ''' <summary>
    ''' Determines whether the collection contains a specific value.
    ''' </summary>
    ''' <param name="Value">The object to locate in the collection.</param>
    Public Function Contains(ByVal Value As MyUserControlButton) As Boolean
        Return List.Contains(Value)
    End Function

    Protected Overrides Sub OnInsertComplete(ByVal index As Integer, ByVal value As Object)
        Dim b As MyUserControlButton = CType(value, MyUserControlButton)
        b.Parent = Me.Parent
        Me.Parent.Items.Insert(index, CType(value, ToolStripButton))
        MyBase.OnInsertComplete(index, value)
    End Sub

    Protected Overrides Sub OnSetComplete(ByVal index As Integer, ByVal oldValue As Object, ByVal newValue As Object)
        Dim b As MyUserControlButton = CType(newValue, MyUserControlButton)
        b.Parent = Me.Parent
        MyBase.OnSetComplete(index, oldValue, newValue)
    End Sub

    Protected Overrides Sub OnClearComplete()
        MyBase.OnClearComplete()
    End Sub
End Class

Public Class MyUserControlButton
    Inherits ToolStripButton

    ''' <summary>
    ''' Initializes a new instance of the MyUserControlButton class.
    ''' </summary>
    Sub New()
        MyBase.New()
        Init()
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the MyUserControlButton class.
    ''' </summary>
    ''' <param name="Holder">The ToolStrip that contains the StackView button.</param>
    Sub New(ByVal Holder As ToolStrip)
        MyBase.New()
        Init()
        Me.Parent = Holder
    End Sub

    Private Sub Init()
        Me.AutoToolTip = False
        Me.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText
        Me.ImageAlign = ContentAlignment.MiddleLeft
        Me.ImageIndex = -1
        Me.ImageKey = ""
        Me.ImageTransparentColor = Color.Magenta
        Me.TextAlign = ContentAlignment.MiddleLeft
        Me.TextDirection = ToolStripTextDirection.Horizontal
    End Sub

    ''' <remarks>
    ''' Hide this property from the user in both design and code editor.
    ''' </remarks>
    <Browsable(False),
    EditorBrowsable(False)> _
    Public Shadows Property AccessibleDefaultActionDescription As String
        Get
            Return MyBase.AccessibleDefaultActionDescription
        End Get
        Set(ByVal value As String)
            MyBase.AccessibleDefaultActionDescription = value
        End Set
    End Property

    ''' <remarks>
    ''' Hide this property from the user in both design and code editor.
    ''' </remarks>
    <Browsable(False),
    EditorBrowsable(False)> _
    Public Shadows Property AccessibleDescription As String
        Get
            Return MyBase.AccessibleDescription
        End Get
        Set(ByVal value As String)
            MyBase.AccessibleDescription = value
        End Set
    End Property

    ''' <remarks>
    ''' Hide this property from the user in both design and code editor.
    ''' </remarks>
    <Browsable(False),
    EditorBrowsable(False)> _
    Public Shadows Property AccessibleName As String
        Get
            Return MyBase.AccessibleName
        End Get
        Set(ByVal value As String)
            MyBase.AccessibleName = value
        End Set
    End Property


    ' Keep on hiding the irrelevant properties...


    ''' <summary>
    ''' Gets or sets a value indicating whether default or custom ToolTip text is displayed on the ToolStripButton.
    ''' </summary>
    <DefaultValue(False)> _
    Public Shadows Property AutoToolTip As Boolean
        Get
            Return MyBase.AutoToolTip
        End Get
        Set(ByVal value As Boolean)
            MyBase.AutoToolTip = value
        End Set
    End Property

    ''' <summary>
    ''' Specifies whether the image and text are rendered.
    ''' </summary>
    <DefaultValue(GetType(ToolStripItemDisplayStyle), "ImageAndText")> _
    Public Overrides Property DisplayStyle As System.Windows.Forms.ToolStripItemDisplayStyle
        Get
            Return MyBase.DisplayStyle
        End Get
        Set(ByVal value As System.Windows.Forms.ToolStripItemDisplayStyle)
            MyBase.DisplayStyle = value
        End Set
    End Property

    ''' <summary>
    ''' The image that will be displayed on the control.
    ''' </summary>
    Public Overrides Property Image() As Image
        Get
            Return MyBase.Image
        End Get
        Set(ByVal value As Image)
            MyBase.Image = value
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the alignment of the image on a ToolStripItem.
    ''' </summary>
    <DefaultValue(GetType(ContentAlignment), "MiddleLeft")> _
    Public Shadows Property ImageAlign As ContentAlignment
        Get
            Return MyBase.ImageAlign
        End Get
        Set(ByVal value As ContentAlignment)
            MyBase.ImageAlign = value
        End Set
    End Property

    <EditorBrowsable(False),
    DefaultValue(-1)> _
    Public Shadows Property ImageIndex As Integer
        Get
            Return MyBase.ImageIndex
        End Get
        Set(ByVal value As Integer)
            MyBase.ImageIndex = value
        End Set
    End Property

    <EditorBrowsable(False),
    DefaultValue("")> _
    Public Shadows Property ImageKey As String
        Get
            Return MyBase.ImageKey
        End Get
        Set(ByVal value As String)
            MyBase.ImageKey = value
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the color to treat as transparent in a ToolStripItem image.
    ''' </summary>
    Public Shadows Property ImageTransparentColor As Color
        Get
            Return MyBase.ImageTransparentColor
        End Get
        Set(ByVal value As Color)
            MyBase.ImageTransparentColor = value
        End Set
    End Property

    ''' <summary>
    ''' Specifies the name used to identify the object.
    ''' </summary>
    Public Shadows Property Name() As String
        Get
            Return MyBase.Name
        End Get
        Set(ByVal value As String)
            MyBase.Name = value
        End Set
    End Property

    ''' <summary>
    ''' The ToolStrip that contains this item.
    ''' </summary>
    <Browsable(False)> _
    Public Shadows Property Parent As ToolStrip
        Get
            Return MyBase.Parent
        End Get
        Set(ByVal value As ToolStrip)
            MyBase.Parent = value
        End Set
    End Property

    ''' <summary>
    ''' The text that will be displayed on the control.
    ''' </summary>
    Public Overrides Property Text() As String
        Get
            Return MyBase.Text
        End Get
        Set(ByVal value As String)
            MyBase.Text = value
        End Set
    End Property

    ''' <summary>
    ''' Gets or sets the alignment of the text on a ToolStripLabel.
    ''' </summary>
    <DefaultValue(GetType(ContentAlignment), "MiddleLeft")> _
    Public Overrides Property TextAlign As ContentAlignment
        Get
            Return MyBase.TextAlign
        End Get
        Set(ByVal value As ContentAlignment)
            MyBase.TextAlign = value
        End Set
    End Property

    <Browsable(False),
    EditorBrowsable(False),
    DefaultValue(GetType(ToolStripTextDirection), "Horizontal")> _
    Public Overrides Property TextDirection As ToolStripTextDirection
        Get
            Return MyBase.TextDirection
        End Get
        Set(ByVal value As ToolStripTextDirection)
            MyBase.TextDirection = value
        End Set
    End Property


    ' Define other properties accordingly...
End Class

#End Region

MyUserControl is the custom user control containing the ToolStrip named MyToolStrip. MyUserControl 是包含名为 MyToolStrip 的 ToolStrip 的自定义用户控件。 MyUserControlButtons is the class that inherits from CollectionBase and each item of MyUserControlButtons is an object of MyUserControlButton class that inherits from ToolStripButton. MyUserControlButtons 是继承自 CollectionBase 的类,MyUserControlButtons 的每一项都是继承自 ToolStripButton 的 MyUserControlButton 类的对象。

In the constructor of MyUserControl, MyUserControlButtons is instantiated with MyToolStrip as its parent.在 MyUserControl 的构造函数中,MyUserControlButtons 以 MyToolStrip 作为其父项进行实例化。 Items are added to MyUserControlButtons by creating new objects from MyUserControlButton.通过从 MyUserControlButton 创建新对象,将项目添加到 MyUserControlButtons。 Properties of the items to be hidden or shown are managed in MyUserControlButton.要隐藏或显示的项目的属性在 MyUserControlButton 中管理。 MyUserControl returns the list of the buttons through the read only property 'Buttons'. MyUserControl 通过只读属性“Buttons”返回按钮列表。 Note the DesignerSerializationVisibility attribute of the 'Buttons' property.请注意“Buttons”属性的 DesignerSerializationVisibility 属性。 It specifies the type of persistence to use when serializing a property on a component at design time.它指定在设计时序列化组件上的属性时要使用的持久性类型。 The 'Content' enumeration member tells the code generator to produce code for the contents of the object, rather than for the object itself. “Content”枚举成员告诉代码生成器为对象的内容生成代码,而不是为对象本身生成代码。

The drawback in this approach is that you cannot retain the items of the ToolStrip while performing copy-paste on the UserControl.这种方法的缺点是您不能在对 UserControl 执行复制粘贴时保留 ToolStrip 的项目。 It serializes the contents only when items are handled explicitly by the user but not during copy-paste.它仅在用户明确处理项目时而不是在复制粘贴期间序列化内容。 Any idea of how to deal with it is highly appreciated.任何关于如何处理它的想法都受到高度赞赏。

Thanks to all posters.感谢所有海报。 Though I applied my own concept, your ideas paved my way.虽然我应用了我自己的概念,但你的想法为我铺平了道路。

I have a solution but for c#我有一个解决方案,但对于 c#

        [Editor("System.ComponentModel.Design.CollectionEditor, System.Design", typeof(UITypeEditor))]
    [MergableProperty(false)]
    [Category("Data")]
    [DescriptionAttribute("ToolStripItems")]
    public virtual ToolStripItemCollection ToolstripItems
    {
        get => toolStrip.Items;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何打印Winforms用户控件 - How to print a winforms usercontrol 如何在XAML中为WPF中托管的Winforms UserControl解析自定义属性名称? - How To Resolve Custom Property Name In XAML For a Winforms UserControl Hosted In WPF? WinForms-UserControl-列表 <bool> 集合 <bool> 作为UserControl的可浏览属性 - WinForms - UserControl - List<bool> an Collection<bool> as Browseable Property of UserControl Winforms usercontrol现象:突然所有物品都消失了! - Winforms usercontrol phenomenon : suddenly all items are away! 在属性网格,.net,winforms中编辑自定义只读集合时出现问题 - Problem editing custom readonly collection in property grid, .net, winforms 如何在 Winforms 窗体和由 Winforms 窗体中的 elementhost 托管的 WPF 用户控件之间使用委托? - How to use a delegate between a Winforms Form and a WPF Usercontrol hosted by an elementhost in the Winforms form? 在Winforms自定义UserControl上启用设计图面 - Enabling design surface on Winforms custom UserControl WinForms 中自定义的 UserControl 属性绑定 - custom-made UserControl property binding in WinForms 如何在自定义WPF用户控件中正确使用CoerceValueCallback - how to propertly use CoerceValueCallback in a custom WPF usercontrol WinForms:UserControl DesignTime:使用哪种方法? - WinForms: UserControl DesignTime: which method to use?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM