当使用 {Binding .} 或 {Binding} 时,数据绑定未更新

4
我有一个地址的ObservableCollection,我将其绑定到ListBox上。然后,在ItemTemplate中,我使用{Binding .}来绑定到当前地址记录。这会导致我的地址使用它们的ToString方法显示,我已经设置了格式化地址的方法。一切都很好,但是,如果我更新单个地址记录的属性,则UI中的列表不会更新。添加/删除列表将更新UI(使用ObservableCollection行为)。如果我直接绑定到地址的属性,则UI会更新(使用Address对象的INotifyPropertyChanged行为)。
我的问题是,是否有一种方法可以通知UI整个对象已更改,以便仍然可以使用此语法?还是我需要放弃在我的地址类型上放置一个DisplayText属性来调用ToString方法并绑定到它?FYI,这是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>
2个回答

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>

第二种方法的优点是可以在用户界面上灵活地更改地址的显示方式,例如多行、格式等;缺点是如果有条件逻辑,例如可选的门牌号或第二个地址行,则会变得复杂。

这很有道理。虽然我认为我会坚持使用显示文本属性路线,因为我们需要支持美国和外国地址以及第二行,正如你所提到的。要在WPF方面实现这一点,可能需要一个转换器类。对我来说,将其集中在实体类中更有意义。如果必要,调用者可以覆盖所有单独的字段。 - Mark

2

我尝试重现了这个问题,并成功了。

我启用了逐步进入 .NET 调试选项,发现如果绑定中的路径为空,则 WPF 不会监听 INotifyPropertyChanged。

要使更改在列表框中反映出来,可以替换 ObservableCollection 中的整个对象。这将触发 INotifyCollectionChanged,使用 Replace 操作。

但是,在您的情况下,这可能不可接受。而且,这可能被视为一种 hack 而不是一个可靠的解决方案。

我认真考虑了为 Address 设计 DataTemplate。在那里,您应该绑定到您需要的确切属性(这将创建 INotifyPropertyChanged 的监听器)。它比 ToString() 更灵活,您可能会遇到需要为非 UI 事务执行 ToString() 的情况,这将创建冲突。而且,老实说,ToString 并不真正适用于 UI 方面。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接