如何在自定义用户控件中暴露DataGridView的设计时属性(含列编辑箭头)?
解决DataGridView用户控件设计时列编辑功能的编译错误
问题描述
我有一个名为DGVManager的用户控件,内部包含名为DGV的DataGridView及其他控件。想要暴露该DataGridView的设计时属性,尤其是添加/编辑列的小箭头功能。参考相关方案转成VB.NET代码后,出现编译错误:"InitializeComponent"和"Return DGV"提示"引用非共享成员需要对象引用"。
原代码如下:
Public Class MyDataGridView Inherits DataGridView <Editor(GetType(ExtendedDataGridViewColumnCollectionEditor), GetType(UITypeEditor))> Public Overloads ReadOnly Property Columns As DataGridViewColumnCollection Get Return MyBase.Columns End Get End Property Private Class ExtendedDataGridViewColumnCollectionEditor Inherits UITypeEditor Private dataGridViewColumnCollectionDialog As Form Private Sub New() End Sub Private Shared Function CreateColumnCollectionDialog(ByVal provider As IServiceProvider) As Form Dim myassembly = Assembly.Load(GetType(ControlDesigner).Assembly.ToString()) Dim type = myassembly.[GetType]("System.Windows.Forms.Design.DataGridViewColumnCollectionDialog") Dim ctor = type.GetConstructors(BindingFlags.NonPublic Or BindingFlags.Instance)(0) Return CType(ctor.Invoke(New Object() {provider}), Form) End Function Public Shared Sub SetLiveDataGridView(ByVal form As Form, ByVal dgv As DataGridView) Dim method = form.[GetType]().GetMethod("SetLiveDataGridView", BindingFlags.NonPublic Or BindingFlags.Instance) method.Invoke(form, New Object() {dgv}) End Sub Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, ByVal provider As IServiceProvider, ByVal value As Object) As Object If provider IsNot Nothing AndAlso context IsNot Nothing Then Dim service = CType(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService) If service Is Nothing OrElse context.Instance Is Nothing Then Return value Dim host = CType(provider.GetService(GetType(IDesignerHost)), IDesignerHost) If host Is Nothing Then Return value If dataGridViewColumnCollectionDialog Is Nothing Then dataGridViewColumnCollectionDialog = CreateColumnCollectionDialog(provider) Dim dgv = (CType(context.Instance, MyDataGridView)) Dim oldSite = dgv.Site dgv.Site = (CType(context.Instance, MyDataGridView)).Parent?.Site SetLiveDataGridView(dataGridViewColumnCollectionDialog, dgv) Using transaction = host.CreateTransaction("DataGridViewColumnCollectionTransaction") If service.ShowDialog(dataGridViewColumnCollectionDialog) = DialogResult.OK Then transaction.Commit() Else transaction.Cancel() End If End Using dgv.Site = oldSite End If Return value End Function Public Overrides Function GetEditStyle(ByVal context As ITypeDescriptorContext) As UITypeEditorEditStyle Return UITypeEditorEditStyle.Modal End Function End Class End Class Partial Public Class DGVManager Inherits UserControl Public Sub New() InitializeComponent() End Sub <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> Public ReadOnly Property DataGridView As DataGridView Get Return DGV End Get End Property End Class
错误原因
DGVManager是分部类,InitializeComponent方法和DGV成员由VS自动生成在对应的DGVManager.Designer.vb文件中,若当前代码文件未正确关联分部类,编译器无法找到这些非共享成员。- 原代码中
MyDataGridView扩展了列编辑器,但用户控件内部的DGV仍是原生DataGridView,未关联扩展功能;同时暴露的DataGridView属性未正确配置设计器元数据,无法触发列编辑对话框。
修正后的代码
1. 扩展DataGridView类(保持原逻辑,确保命名空间一致)
Imports System.ComponentModel Imports System.ComponentModel.Design Imports System.Reflection Imports System.Windows.Forms.Design Public Class MyDataGridView Inherits DataGridView <Editor(GetType(ExtendedDataGridViewColumnCollectionEditor), GetType(UITypeEditor))> <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> Public Overloads ReadOnly Property Columns As DataGridViewColumnCollection Get Return MyBase.Columns End Get End Property Private Class ExtendedDataGridViewColumnCollectionEditor Inherits UITypeEditor Private dataGridViewColumnCollectionDialog As Form Private Sub New() End Sub Private Shared Function CreateColumnCollectionDialog(ByVal provider As IServiceProvider) As Form Dim myassembly = Assembly.Load(GetType(ControlDesigner).Assembly.ToString()) Dim type = myassembly.[GetType]("System.Windows.Forms.Design.DataGridViewColumnCollectionDialog") Dim ctor = type.GetConstructors(BindingFlags.NonPublic Or BindingFlags.Instance)(0) Return CType(ctor.Invoke(New Object() {provider}), Form) End Function Public Shared Sub SetLiveDataGridView(ByVal form As Form, ByVal dgv As DataGridView) Dim method = form.[GetType]().GetMethod("SetLiveDataGridView", BindingFlags.NonPublic Or BindingFlags.Instance) method.Invoke(form, New Object() {dgv}) End Sub Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, ByVal provider As IServiceProvider, ByVal value As Object) As Object If provider IsNot Nothing AndAlso context IsNot Nothing Then Dim service = CType(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService) If service Is Nothing OrElse context.Instance Is Nothing Then Return value Dim host = CType(provider.GetService(GetType(IDesignerHost)), IDesignerHost) If host Is Nothing Then Return value If dataGridViewColumnCollectionDialog Is Nothing Then dataGridViewColumnCollectionDialog = CreateColumnCollectionDialog(provider) Dim dgv = CType(context.Instance, MyDataGridView) Dim oldSite = dgv.Site dgv.Site = dgv.Parent?.Site SetLiveDataGridView(dataGridViewColumnCollectionDialog, dgv) Using transaction = host.CreateTransaction("DataGridViewColumnCollectionTransaction") If service.ShowDialog(dataGridViewColumnCollectionDialog) = DialogResult.OK Then transaction.Commit() Else transaction.Cancel() End If End Using dgv.Site = oldSite End If Return value End Function Public Overrides Function GetEditStyle(ByVal context As ITypeDescriptorContext) As UITypeEditorEditStyle Return UITypeEditorEditStyle.Modal End Function End Class End Class
2. 修正用户控件类
确保DGVManager的分部类完整,且内部DGV控件类型改为MyDataGridView:
' DGVManager.vb Partial Public Class DGVManager Inherits UserControl Public Sub New() InitializeComponent() End Sub <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> <Browsable(True)> Public ReadOnly Property DataGridView As MyDataGridView Get Return DGV End Get End Property End Class
同时检查DGVManager.Designer.vb文件,确保DGV的定义为:
Friend WithEvents DGV As MyDataGridView
关键修正点
- 将用户控件内部的
DataGridView替换为扩展后的MyDataGridView,继承列编辑功能。 - 为
DataGridView属性添加<Browsable(True)>,确保设计器中可见;保留<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>,确保列配置能被序列化。 - 确保分部类的一致性,
DGVManager的两个分部文件(.vb和.Designer.vb)需在同一命名空间下。
内容的提问来源于stack exchange,提问作者ilens
相关产品推荐
相关产品推荐

