![](/img/trans.png)
[英]Refresh property grid, at Design-time, when a readonly collection changes in .Net, Winforms
[英]Difficulty with persisting a collection that references an internal property at design time in Winforms and .net
解释此问题的最简单方法是向您显示一些代码:
Public Interface IAmAnnoyed
End Interface
Public Class IAmAnnoyedCollection
Inherits ObjectModel.Collection(Of IAmAnnoyed)
End Class
Public Class Anger
Implements IAmAnnoyed
End Class
Public Class MyButton
Inherits Button
Private _Annoyance As IAmAnnoyedCollection
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public ReadOnly Property Annoyance() As IAmAnnoyedCollection
Get
Return _Annoyance
End Get
End Property
Private _InternalAnger As Anger
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public ReadOnly Property InternalAnger() As Anger
Get
Return Me._InternalAnger
End Get
End Property
Public Sub New()
Me._Annoyance = New IAmAnnoyedCollection
Me._InternalAnger = New Anger
Me._Annoyance.Add(Me._InternalAnger)
End Sub
End Class
这是设计者生成的代码:
Private Sub InitializeComponent()
Dim Anger1 As Anger = New Anger
Me.MyButton1 = New MyButton
'
'MyButton1
'
Me.MyButton1.Annoyance.Add(Anger1)
// Should be: Me.MyButton1.Annoyance.Add(Me.MyButton1.InternalAnger)
'
'Form1
'
Me.Controls.Add(Me.MyButton1)
End Sub
我在上面添加了一条注释,以显示代码应该如何生成。 现在,如果我省略了界面并且只有一个Anger的集合,那么它会持续正确。
有任何想法吗?
我厌倦了这一点。 这个问题特别是关于持久化接口集合,但现在进一步测试它不适用于普通集合。 这里有一些更简单的代码:
Public Class Anger
End Class
Public Class MyButton
Inherits Button
Private _Annoyance As List(Of Anger)
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public ReadOnly Property Annoyance() As List(Of Anger)
Get
Return _Annoyance
End Get
End Property
Private _InternalAnger As Anger
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public ReadOnly Property InternalAnger() As Anger
Get
Return Me._InternalAnger
End Get
End Property
Public Sub New()
Me._Annoyance = New List(Of Anger)
Me._InternalAnger = New Anger
Me._Annoyance.Add(Me._InternalAnger)
End Sub
End Class
设计人员以与原始问题相同的方式搞砸了持久性代码。
我弄清楚了发生了什么。 我想知道为什么有时会起作用而不是其他人。 它归结为我给内部属性和集合的名称。
如果我将属性'Annoyance'重命名为'WTF',它将正确序列化,因为'WTF'按字母顺序排在集合名称之后 - 'InternalAnger'。
看起来序列化器按字母顺序创建对象实例,并且需要在创建集合时创建内部属性。
我可以通过重命名解决这个问题,但这是一个黑客攻击,我担心编写自定义序列化程序是一项很重要的工作 - 我以前从未做过。
有任何想法吗?
我用黑客回答了这个问题。 除非MS改变了编码器序列化设计器代码的方式,否则我对此非常有信心。
我在这里有点偏离我的元素,但是你不应该在这个只读属性上有一个私有的setter吗? 我的意思是,它无法序列化它无法设置的内容,对吗?
这里的问题可能是你在控件的构造函数中将一个项添加到集合中,然后设计器会单独序列化吗?
我认为您评论的“应该已生成”代码也是不正确的。 由于控件的构造函数将InternalAnger添加到集合中,为什么还要在InitializeComponent中看到它?
从InternalAnger
属性中取出DesignerSerializationVisibility.Content
,它应该按预期工作。
例如(C#,但想法是一样的)
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
this.InternalAnger = new Anger();
this.InternalAnger.SomeValue = 2;
this.Angers.Add(this.InternalAnger);
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<Anger> Angers
{
get { return this.list; }
}
public Anger InternalAnger { get; set; }
private List<Anger> list = new List<Anger>();
private Anger _InternalAnger;
}
public class Anger
{
public Anger() { }
public int SomeValue { get; set; }
}
产生:
WindowsFormsApplication1.Anger anger1 = new WindowsFormsApplication1.Anger();
anger1.SomeValue = 2;
this.userControl11.Angers.Add(anger1);
this.userControl11.InternalAnger = anger1;
我认为,这就是你想要的。
正如我在OP中所说,问题归结为我给内部属性和集合的名称。
在不深入研究自定义编码序列化器的情况下,简单的解决方案是确保内部属性的名称在引用它之前的任何其他属性之前按字母顺序排列。
我这样做是通过保留原始属性名称'InternalProperty',但我禁用序列化并将其引用到一个代理属性,这是一个狡猾的命名,并被序列化。
Private _InternalProperty
Public ReadOnly Property InternalProperty
Get
Return Me._ProxyInternalProperty
End Get
End Property
<Browsable(False), EditorBrowsable(Never), DesignerSerializationVisibility(Content)> _
Public ReadOnly Property _ProxyInternalProperty
Get
Return Me._InternalProperty
End Get
End Property
这是一个黑客,但它比重命名我的属性AInternalProperty更好。 此外,用户永远不会看到_ProxyInternalProperty,因为它是隐藏的,即使他们确实发现了它,也没有引用它的危险。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.