我有一个ObservableCollection的地址,我绑定到ListBox。然后在ItemTemplate中,我使用{Binding。}绑定到当前地址记录。这导致我的地址使用他们设置的ToString方法显示格式化地址。一切都很好,除非我更新单个地址记录的属性,UI中的列表不会更新。添加/删除列表会更新UI(使用ObservableCollection行为)。如果我直接绑定到UI确实更新的地址上的属性(使用Address对象的INotifyPropertyChanged行为)。
我的问题是,有没有办法通知UI整个对象的更改,以便我仍然可以使用这种语法或者我需要在我调用的地址类型上放置一个DisplayText属性ToString方法并绑定到那个?仅供参考,这是一个MVVM架构,所以我不能直接在ListBox上调用Refresh。
感谢您的任何帮助/想法。
<ListBox x:Name="AddressList" ItemsSource="{Binding Addresses}" Background="Transparent" BorderBrush="Transparent"
Width="200" HorizontalAlignment="Left">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding .}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
答案 0 :(得分:3)
当你绑定到Address对象本身时,对象本身 - 即它的身份 - 不会改变,即使它的属性也是如此。因此,在这种情况下,WPF不知道刷新绑定。
所以是的,您需要绑定到通知属性(或属性)而不是整个对象。正如您所说,一种方法是创建一个DisplayText属性,并在影响显示文本的某些内容发生更改时为该属性引发PropertyChanged事件。另一种方法是在水平定向的StackPanel中使用多个TextBlock,每个TextBlock都绑定到一个特定的属性,例如
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding HouseNumber}" />
<TextBlock Text=", " />
<TextBlock Text="{Binding Street}" />
<TextBlock Text=", " />
<TextBlock Text="{Binding City}" />
</StackPanel>
第二种方法的优点在于它为用户提供了灵活性,可以更改地址的显示方式,例如多行,格式化等;缺点是如果你有条件逻辑,它会变得复杂,例如可选的单号或第二地址行。
答案 1 :(得分:2)
我试图重现问题并成功。
我激活了step-into-.NET调试选项,并看到如果绑定中的路径为空,WPF不会监听INotifyPropertyChanged。
要使更改反映在列表框中的作用是替换ObservableCollection中的整个对象。这会触发INotifyCollectionChanged和Replace操作。
但在您的情况下,这可能是不可接受的。而且可以看作更像是黑客攻击而非固体解决方案。
我认真考虑使用DataTemplate for Address。在那里你应该绑定到你需要的确切属性(这将创建INotifyPropertyChanged的监听器)。它比ToString()更灵活,您可能会遇到需要ToString()为非UI内容做某事的情况,这会产生冲突。老实说,ToString并不是真的用于UI的东西。