.net、winforms 中类级别的 RefreshProperties 属性 +错误地刷新属性网格
我在编辑属性网格中的类时遇到了一个奇怪的问题,属性网格将错误地刷新。
我设法将问题简化为只有两个属性的类。我在最后添加了代码以方便解释。
它基本上可以归结为具有两个属性的类。第一个是可扩展的(字体)。 该类本身是可扩展的,并且还实现了类型转换器中的CreateInstance方法。
要查看问题,请展开字体,进行编辑,说“粗体”,然后按 Tab 键离开。出现两个问题:
(1) 第二个属性向上跳转并最终出现在扩展的字体属性中。
(2) 扩展字体的“-”号变为“+”。
通过将 ResfreshProperties(RefreshProperties.All) 附加到该类,问题就消失了。
太好了,但我想了解它是如何解决问题的。我查看了反射器,但找不到任何在类级别附加的 RefreshProperties 示例。
/// 简单类
<TypeConverter(GetType(Class1Converter)), _
RefreshProperties(RefreshProperties.All)> _
Public Class Class1
Public Sub New(ByVal font As Font, ByVal image As Image)
Me.New()
Me.Image = image
Me.Font = font
End Sub
Public Sub New()
End Sub
Private _Font As Font = New Font("Arial", 10)
Public Property Font() As Font
Get
Return _Font
End Get
Set(ByVal value As Font)
_Font = value
End Set
End Property
Private _Image As Image
Public Property Image() As Image
Get
Return _Image
End Get
Set(ByVal value As Image)
_Image = value
End Set
End Property
End Class
/// 类的转换器
Public Class Class1Converter
Inherits ExpandableObjectConverter
Public Overrides Function GetCreateInstanceSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
Return True
End Function
Public Overrides Function CreateInstance(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal propertyValues As System.Collections.IDictionary) As Object
Dim font As Font = TryCast(propertyValues("Font"), Font)
Dim image As Image = CType(propertyValues("Image"), Image)
Return New Class1(font, image)
End Function
End Class
/// 托管类的按钮
Public Class MyButton
Inherits Button
Private _C As Class1 = New Class1
Public Property C() As Class1
Get
Return _C
End Get
Set(ByVal value As Class1)
_C = value
End Set
End Property
End Class
I had a strange problem editing a class in the property grid whereby the property grid would refresh incorrectly.
I managed to reduce the problem down to a class with just two properties. I've included the code at the end to ease explanation.
It basically boils down to a class with two properties. The first of which is expandable (a font).
The class itself is expandable and also implements the CreateInstance method in the type converter.
To see the problem, expand the font, edit, say 'Bold', and tab away. Two problems happen:
(1) The second property jumps up and ends up in the expanded font property.
(2) The '-' sign of the expanded font changes to a '+'.
The problem goes away by attaching ResfreshProperties(RefreshProperties.All) to the class.
That's great, but I'd like to understand how it fixed the problem. I've had a look in reflector and can't find any examples of RefreshProperties being attached at the class level.
/// Simple Class
<TypeConverter(GetType(Class1Converter)), _
RefreshProperties(RefreshProperties.All)> _
Public Class Class1
Public Sub New(ByVal font As Font, ByVal image As Image)
Me.New()
Me.Image = image
Me.Font = font
End Sub
Public Sub New()
End Sub
Private _Font As Font = New Font("Arial", 10)
Public Property Font() As Font
Get
Return _Font
End Get
Set(ByVal value As Font)
_Font = value
End Set
End Property
Private _Image As Image
Public Property Image() As Image
Get
Return _Image
End Get
Set(ByVal value As Image)
_Image = value
End Set
End Property
End Class
/// Converter for the class
Public Class Class1Converter
Inherits ExpandableObjectConverter
Public Overrides Function GetCreateInstanceSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
Return True
End Function
Public Overrides Function CreateInstance(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal propertyValues As System.Collections.IDictionary) As Object
Dim font As Font = TryCast(propertyValues("Font"), Font)
Dim image As Image = CType(propertyValues("Image"), Image)
Return New Class1(font, image)
End Function
End Class
/// A button to host the class
Public Class MyButton
Inherits Button
Private _C As Class1 = New Class1
Public Property C() As Class1
Get
Return _C
End Get
Set(ByVal value As Class1)
_C = value
End Set
End Property
End Class
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
听起来好像发生的是属性网格控件中的绘画错误。发生错误时是否在属性级别应用了 RefreshPropertiesAttribute?该组件是否实现了 INotifyPropertyChanged?
该问题可能消失的原因之一是在类级别应用 RefreshPropertiesAttribute 并不是该属性应该使用的方式。我猜想通过在班级级别应用它,您可以有效地删除它。看起来他们将其设置为 AttributeTargets.All 但显然这不是设计使然。
RefreshProperties 是一种逃避属性。它告诉设计者,当该属性的值发生更改(通过属性网格)时,请重新查询该类上的所有其他属性。显然,这是一种浪费,特别是如果更改的属性不会对任何其他属性产生任何影响。
如果您的属性确实会导致其他属性发生更改,则可以使用 PropNameChanged 事件模式。在这种情况下,当这些属性更改时,您将在类上引发 FontChanged 或 ImageChanged 事件。 Windows 窗体设计器查找具有该命名约定的事件,并使用它们使属性网格失效。
但在您给出的示例中,这两个属性不会彼此无效,因此您不需要使其中一个属性无效来响应另一个属性。
It sounds like what's happening is a painting bug in the property grid control. Was the RefreshPropertiesAttribute applied at the property level when the bug occurred? Does the component implement INotifyPropertyChanged?
One reason the problem likely goes away is that applying RefreshPropertiesAttribute at the class level is not the way the attribute is supposed to be used. I'm guessing that by applying it at the class level you're effectively removing it. It looks like they left it set as AttributeTargets.All but clearly that's not by design.
RefreshProperties is kind of a cop-out attribute. It tells the designer that when the value of this property changes (via the property grid), go re-query every other property on this class. Obviously that's kind of wasteful, particularly if the property that changed doesn't have any impact on any other properties.
If you do have properties that cause changes in other properties, you can use the PropNameChanged event pattern. In this case, you would raise a FontChanged or ImageChanged event on the class when those properties change. The Windows Forms designer looks for events with that naming convention and uses them to invalidate the property grid.
But in the example you gave, those two properties would not invalidate each other and therefore you wouldn't need to invalidate either one in response to the other.