VB.NET自定义类型字典转对象:解决设计器类型转换错误
问题解决与对象转换器实现
一、先解决类型不匹配错误
你遇到的这个错误,本质是CLR将看似相同的类型判定为不同类型——通常是因为设计器加载时,Dictionary(Of Integer, RegistryDataItem)或RegistryDataItem被不同的程序集加载上下文加载(比如设计器引用了程序集副本,和运行时的程序集实例不统一)。解决这个问题最可靠的方式是替换默认Dictionary为自定义强类型集合,而非直接使用泛型字典作为设计属性类型:
1. 自定义强类型字典集合
创建一个继承自KeyedCollection(Of Integer, RegistryDataItem)的类,既保留字典的键值对特性,又能被设计器更好地识别:
<Serializable> Public Class RegistryDataDictionary Inherits KeyedCollection(Of Integer, RegistryDataItem) ' 重写GetKeyForItem,指定RegistryDataItem的某个属性作为键(替换为你实际的键属性,比如item.Id) Protected Overrides Function GetKeyForItem(item As RegistryDataItem) As Integer Return item.Id End Function ' 可选:添加便捷的键值对添加方法 Public Sub Add(id As Integer, item As RegistryDataItem) MyBase.Add(item) End Sub End Class
2. 修改原属性定义
把原来的Dictionary类型替换成这个自定义集合:
Protected RegistryDatasValue As New RegistryDataDictionary() <ProviderType(ProvideTypes.RegistryData)> <Browsable(True), RefreshProperties(RefreshProperties.All)> <Editor(GetType(StringTableCollectionEditor), GetType(Drawing.Design.UITypeEditor))> <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> Public Property RegistryDatas() As RegistryDataDictionary Get Return RegistryDatasValue End Get Set(ByVal value As RegistryDataDictionary) RegistryDatasValue = value End Set End Property
二、为自定义字典实现对象转换器(TypeConverter)
如果需要为自定义集合添加设计器转换支持(序列化、反序列化、类型转换),可以实现TypeConverter类:
1. 创建自定义TypeConverter类
Imports System.ComponentModel Imports System.Globalization Public Class RegistryDataDictionaryConverter Inherits TypeConverter ' 允许从字符串转换为目标类型 Public Overrides Function CanConvertFrom(context As ITypeDescriptorContext, sourceType As Type) As Boolean If sourceType = GetType(String) Then Return True End If Return MyBase.CanConvertFrom(context, sourceType) End Function ' 实现从字符串到字典的转换(根据实际序列化格式调整解析逻辑) Public Overrides Function ConvertFrom(context As ITypeDescriptorContext, culture As CultureInfo, value As Object) As Object If TypeOf value Is String Then Dim dict As New RegistryDataDictionary() ' 假设序列化格式为"键1:项内容1;键2:项内容2",可根据实际需求修改 Dim parts As String() = DirectCast(value, String).Split(";"c) For Each part In parts If Not String.IsNullOrEmpty(part) Then Dim keyValue As String() = part.Split(":"c) If keyValue.Length = 2 Then Dim id As Integer = Integer.Parse(keyValue(0)) ' 这里假设RegistryDataItem有FromString方法,或自行实例化对象 Dim item As RegistryDataItem = RegistryDataItem.FromString(keyValue(1)) dict.Add(id, item) End If End If Next Return dict End If Return MyBase.ConvertFrom(context, culture, value) End Function ' 允许转换为字符串(用于设计器属性栏显示) Public Overrides Function CanConvertTo(context As ITypeDescriptorContext, destinationType As Type) As Boolean If destinationType = GetType(String) Then Return True End If Return MyBase.CanConvertTo(context, destinationType) End Function ' 实现从字典到字符串的转换 Public Overrides Function ConvertTo(context As ITypeDescriptorContext, culture As CultureInfo, value As Object, destinationType As Type) As Object If destinationType = GetType(String) AndAlso TypeOf value Is RegistryDataDictionary Then Dim dict As RegistryDataDictionary = DirectCast(value, RegistryDataDictionary) Dim parts As New List(Of String)() For Each item In dict parts.Add($"{item.Id}:{item.ToString()}") ' 用Item的ToString或自定义属性生成显示字符串 Next Return String.Join(";", parts) End If Return MyBase.ConvertTo(context, culture, value, destinationType) End Function End Class
2. 为自定义字典绑定转换器
在RegistryDataDictionary类上添加特性,关联刚才的转换器:
<Serializable> <TypeConverter(GetType(RegistryDataDictionaryConverter))> Public Class RegistryDataDictionary Inherits KeyedCollection(Of Integer, RegistryDataItem) ' ... 原有代码 ... End Class
额外注意事项
- 确保
RegistryDataItem类的<Serializable>特性正确,若有自定义序列化逻辑,可实现ISerializable接口。 - 若使用自定义的
StringTableCollectionEditor,需确保它支持新的RegistryDataDictionary类型,必要时调整编辑器代码。 - 强命名你的程序集,避免设计器加载时出现程序集版本冲突。
内容的提问来源于stack exchange,提问作者vblover
相关产品推荐
相关产品推荐

