VB .Net - ShouldSerialize 函数

VB .Net - ShouldSerialize function

我对 ShouldSerialize 函数有疑问。
我定义了一个带有标签(名为 Label1)的用户控件。
现在我将下面的代码放在用户控件中 class :

Imports System.ComponentModel

Public Class UserControl1

Dim _Range As UShort = 100

Private Sub UserControl1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Label1.Text = _Range
End Sub

Public Function ShouldSerializeTBValueRange() As Boolean
    Return _Range <> 200
End Function

Public Sub ResetTBValueRange()
    _Range = 200
    Label1.Text = _Range
End Sub

Public Property TBValueRange As UShort
    Get
        Return _Range
    End Get
    Set(ByVal Steps As UShort)
        _Range = Steps
        Label1.Text = _Range
    End Set
End Property

End Class

现在在新表单中包含用户控件。
在用户控件的属性网格中,您可以找到 属性 TBValueRange。
如果您右键单击 属性 名称,您可以重新初始化 属性.
重新初始化后,您可以在 属性.
中看到值 200 现在,重新生成项目会将 属性 重置为初始值 (id 100)。
为什么值 200 没有保留?
如果我将函数 ShouldSerializeTBValueRange() 中的行 Return _Range <> 200 替换为

Return Not _Range.Equals(200)

它会起作用的。 我不明白。

谁能解释一下?

这些方法按编码工作。 似乎 无法按预期工作的是 Not _Range.Equals(200) 部分。

  • 你将_Range初始化为100:Dim _Range As UShort = 100

  • 然后,你的ShouldSerializeTBValueRange方法告诉VS 不是[=89=时保存范围值] 200: Return _Range <> 200

  • 所以,当你在IDE中重置为200时,它不会保存200的值,而初始值[=24] =] 显示。

代码使用一个值作为默认值,100 但对 ShouldSerialize 测试使用不同的值。您应该将其更改为使用默认值 200:

Dim _Range As UShort = 200

ShouldSerialize 测试更改为使用 100:

Public Function ShouldSerializeTBValueRange() As Boolean
    Return _Range <> 100
End Function

将默认值视为默认值,并且仅使用 一个 值作为默认值一切正常,仅使用 ShouldSerializexxxResetxxx 没有需要其他任何东西。

' THIS is the default value -
'     ie the value that need not be saved because the
'     control automatically starts with that value
Dim _Range As UShort = 200US

' Controls:
'   - displays the prop value in Bold in the property window 
'           when the value is NOT the default
'   - saves the value when it is NOT the default
'   - enables/disables the RESET function
Public Function ShouldSerializeTBValueRange() As Boolean
    Return (_Range <> 200US)
End Function

使用一个值作为实际默认值 (100),然后根据 不同的 值 (200) 返回 T/F 结果

  • 100 在不需要时被保存
  • 200 没有 应该被保存
  • Reset 菜单项和 粗体值 处于错误状态

奇怪的是 Not _Range.Equals(200) 似乎失败了。它 returns False 在重置(到 200)后导致值在实际上不应该被保存时被保存。为此有 2 个重载:

 UInt16.Equals(obj As Object) As Boolean
 UInt16.Equals(v As UShort) As Boolean

如果您传递的不是实际的 UInt16/UShort,该值将被装箱为 Object。所以,Not _Range.Equals(200) 使用第一个,因为 200Int32。该版本的 ILCode 是:

public override bool Equals(object obj)
{
    return obj is ushort && this == (ushort)obj;
}

测试将无法通过第一个测试,因为 obj 包含一个 Int32。如果你传递一个 UShort,它将起作用:

UShort.Equals(_Range, 200US)
'or:
_Range.Equals(200US)

了解不同数据类型的所有充分理由,避免装箱 (As Object) 并永远设置 Option Strict On

感谢大家花时间回答我的问题。
我找到了答案:当 ShouldSerialize 函数 return 为 false 时,属性 值未保存在文件 Form1.designer.vb 中,因此它获得原始值。
对于我需要的 ShouldSerialize 函数应该总是 return true.

Public Function ShouldSerializeTBValueRange() As Boolean
    Return true
End Function

因此 属性 值将始终保存。
现在,我正在寻找的是如何控制 属性 网格的上下文菜单。
我希望选项 "Reinit" 在值好的时候变灰。

终于,我找到了一些东西,使用 PropertyDescriptor。 有兴趣的可以把属性保存在designer.vb文件里,测试一下要重置的值。
这是我的程序,基于 MSDN - Microsft:

的文章
Imports System.ComponentModel
Imports System.Windows.Forms.Design

<Designer(GetType(DemoControlDesigner))>
Public Class UserControl1

Dim _MyProperty1 As String = "Test1"
Dim _MyProperty2 As Integer = 100
Dim _MyProperty3 As UShort = 200

Public Sub New()
    InitializeComponent()
End Sub

Public Function CanResetMyProperty1() As Boolean
    Return _MyProperty1 <> "Test"
End Function

Public Sub ResetMyProperty1()
    _MyProperty1 = "Test"
End Sub

Public Property MyProperty1 As String
    Get
        Return _MyProperty1
    End Get
    Set(ByVal Value As String)
        _MyProperty1 = Value
    End Set
End Property

Public Function CanResetMyProperty2() As Boolean
    Return _MyProperty2 <> 150
End Function

Public Sub ResetMyProperty2()
    _MyProperty2 = 150
End Sub

Public Property MyProperty2 As Integer
    Get
        Return _MyProperty2
    End Get
    Set(ByVal Value As Integer)
        _MyProperty2 = Value
    End Set
End Property

Public Function CanResetMyProperty3() As Boolean
    Return _MyProperty3 <> _MyProperty2
End Function

Public Sub ResetMyProperty3()
    _MyProperty3 = _MyProperty2
End Sub

Public Property MyProperty3 As UShort
    Get
        Return _MyProperty3
    End Get
    Set(ByVal Value As UShort)
        _MyProperty3 = Value
    End Set
End Property

End Class


Friend NotInheritable Class SerializePropertyDescriptor
Inherits PropertyDescriptor
Private _pd As PropertyDescriptor = Nothing

Public Sub New(ByVal pd As PropertyDescriptor)
    MyBase.New(pd)
    _pd = pd
End Sub

Public Overrides ReadOnly Property Attributes() As AttributeCollection
    Get
        Return Me._pd.Attributes
    End Get
End Property

Protected Overrides Sub FillAttributes(ByVal attributeList As IList)
    MyBase.FillAttributes(attributeList)
End Sub

Public Overrides ReadOnly Property ComponentType() As Type
    Get
        Return Me._pd.ComponentType
    End Get
End Property

Public Overrides ReadOnly Property Converter() As TypeConverter
    Get
        Return Me._pd.Converter
    End Get
End Property

Public Overrides Function GetEditor(ByVal editorBaseType As Type) As Object
    Return Me._pd.GetEditor(editorBaseType)
End Function

Public Overrides ReadOnly Property IsReadOnly() As Boolean
    Get
        Return Me._pd.IsReadOnly
    End Get
End Property

Public Overrides ReadOnly Property PropertyType() As Type
    Get
        Return Me._pd.PropertyType
    End Get
End Property

Public Overrides Function CanResetValue(ByVal component As Object) As Boolean
    Try
        Return CallByName(component, "CanReset" & _pd.Name, CallType.Get, Nothing)
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
    Return False
End Function

Public Overrides Function GetValue(ByVal component As Object) As Object
    Return Me._pd.GetValue(component)
End Function

Public Overrides Sub ResetValue(ByVal component As Object)
    Me._pd.ResetValue(component)
End Sub

Public Overrides Sub SetValue(ByVal component As Object, ByVal val As Object)
    Me._pd.SetValue(component, val)
End Sub

Public Overrides Function ShouldSerializeValue(ByVal component As Object) As Boolean
    Return True
End Function

End Class

Class DemoControlDesigner
Inherits ControlDesigner
Dim PropertiesToSerialize As String() = {"MyProperty1", "MyProperty2", "MyProperty3"}

Protected Overrides Sub PostFilterProperties(ByVal properties As IDictionary)
    Dim original As PropertyDescriptor
    For Each PropName As String In PropertiesToSerialize
        If properties.Contains(PropName) Then
            original = properties(PropName)
            properties(PropName) = New SerializePropertyDescriptor(original)
        End If
    Next
    MyBase.PostFilterProperties(properties)
End Sub
End Class

对于每个应该序列化并测试重置的 属性,我们应该编写一个子 "CanResetPropertyName" 来测试要重置的值(参见示例)。
即使我们重新生成项目,这些值现在仍然存在。
它对我来说很好用,也许可以改进。

此致。