【问题标题】:Why Does Binding to a Struct Not Work?为什么绑定到结构不起作用?
【发布时间】:2011-12-04 14:51:51
【问题描述】:
我最近遇到了一个问题,我将 ObservableCollection 绑定到 ListView。人是我写的一个结构。只要我在绑定之前设置 People 对象的值,一切似乎都可以正常工作。但是,当我尝试在运行时从 GUI 设置值时,底层对象似乎没有反映更改。
我终于通过简单地将 People 从结构更改为类来克服这个问题。无需进行其他更改。
谁能解释一下这是为什么?
【问题讨论】:
标签:
c#
wpf
class
binding
struct
【解决方案1】:
你的绑定获得了一个结构的副本,因为结构是按值传递给方法的。如果绑定更新了一些东西;内存中某处的副本正在被修改,因此您的原始对象没有更新。
【解决方案2】:
由于结构是按值传递给控件的,因此当您在 UI 中进行更改时,WPF 会将更改写回People 的不同实例。
把它改成一个类就可以了。
除非你完全理解struct 的用途,否则我建议不要使用它。
【解决方案3】:
ListView 是一个 ItemsControl,可以在直接模式下工作,通过在 XAML 中声明多个 ListViewItem 对象来填充它的 Items,或者在 ItemsSource 模式下工作,在 ItemsSource 属性上设置绑定
See this Dr. WPF article for a good explanation.
无论哪种方式,ListView.Items 都是一个 ItemCollection,它是一个 CollectionView,即 Items 不是您提供给 ItemsSource 属性的实际集合,而是您提供的集合的规范化副本,它允许框架例如访问底层IEnumerable by index 即使 IEnumerable 本身不提供索引器。
由于 ListView 使用副本,当它使用 Class 实例的集合时,它可以复制引用,两个引用都指向内存中的同一个对象,因此更改其中一个引用中的值的效果可以通过另一个引用,但是当它使用作为值类型的结构集合时,它必须复制这些值,而不是让两个引用指向同一个对象,然后你就有两个不同的值类型对象。
【解决方案4】:
对于所有对此主题感兴趣的人:
我用 Combobox 和 Objectdataprovider 让它运行起来。
“ItemsSource”是结构,但“SelectedItem”写在其他地方。
这里是:
<!--resources-->
<ObjectDataProvider x:Key="StructValues"
MethodName="GetValues"
ObjectType="{x:Type local:MyStruct}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:MyStruct" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ComboBox Margin="0,5"
VerticalAlignment="Center"
ItemsSource="{Binding Source={StaticResource StructValues}}"/>
这就是结构体的样子:
public struct MyStruct
{
public const string A = "A";
public const string B = "B";
public const string C = "C";
public static IEnumerable GetValues(Type type)
{
List<String> retVals = new List<string>();
FieldInfo[] fi = type.GetFields();
foreach (FieldInfo info in fi)
{
retVals.Add(info.Name);
}
return retVals;
}
}