Silverlight 3数据绑定的子属性不更新

4

我有一个Silverlight控件,它的数据源是我的根ViewModel对象。ViewModel公开了一组卡片以及一个SelectedCard属性,该属性绑定到视图顶部的下拉列表中。然后,在底部有一种表单显示所选卡的属性。我的XAML代码如下(为简化起见):

<StackPanel Orientation="Vertical">
  <ComboBox DisplayMemberPath="Name"
            ItemsSource="{Binding Path=Cards}"
            SelectedItem="{Binding Path=SelectedCard, Mode=TwoWay}"
            />
  <TextBlock Text="{Binding Path=SelectedCard.Name}"
             />
  <ListBox DisplayMemberPath="Name"
           ItemsSource="{Binding Path=SelectedCard.PendingTransactions}"
           />
</StackPanel>

我希望当我在 ComboBox 中选择一个新项目时,TextBlock 和 ListBox 能够更新,但事实并非如此。我确信这与 TextBlock 和 ListBox 实际上绑定到 SelectedCard 的属性有关,因此它正在监听该对象上的属性更改通知。但是,我认为数据绑定应该足够聪明,能够识别绑定表达式中的父对象已更改并更新整个绑定。
值得注意的是,PendingTransactions 属性(绑定到 ListBox)是惰性加载的。因此,当我第一次在 ComboBox 中选择项目时,我会进行异步调用并加载列表,UI 更新以显示与所选项目对应的信息。然而,当我重新选择项目时,UI 不会更改!
例如,如果我的原始列表包含三张卡片,则默认选择第一张卡片。数据绑定确实尝试访问该 Card 对象上的 PendingTransactions 属性,并正确更新了 ListBox。如果我选择列表中的第二张卡片,同样的情况发生了,我会得到该卡片的 PendingTransactions 列表。但是,如果我再次选择第一张卡片,我的 UI 没有任何变化!通过设置断点,我可以确认 SelectedCard 属性正在被正确更新。
我该怎么做才能让它工作???
3个回答

0

如果你正在使用Silverlight 3,你需要使用INotifyPropertyChanged。

示例:

public class CardViewModel : INotifyPropertyChanged
{
 public event PropertyChangedEventHandler PropertyChanged;
 public ObservableCollection<Card> Cards { get; set; }
 private Card _selectedCard;
 public SelectedCard
 {
  get
  {
   return _selectedCard;
  }
  set
  {
   if (value != _selectedCard)
   {
    _selectedCard = value;
    NotifyPropertyChanged("SelectedCard");
   }
  }
 }
 public CardViewModel()
 {
  Cards = new ObservableCollection<Card>();
  //Populate Cards collection with objects
 }
 public void NotifyPropertyChanged(string item)
 {
  if (PropertyChanged!=null)
  {
   PropertyChanged(this, new PropertyChangedEventArgs(item));
  }
 }
}

只要将这个类设置为您的视图的DataContext,一切都会很顺利。

这就是我拥有的,唯一的例外是Cards属性是一个ReadOnlyCollection,因为它不会改变。 - SonOfPirate

0
我最近使用的一种模式是将详细信息容器的数据上下文绑定到列表框中选择的项目。在您的情况下,XAML 如下所示:
<StackPanel Orientation="Vertical">
    <ComboBox x:Name="_lbxCards"       <-- new
              DisplayMemberPath="Name"
              ItemsSource="{Binding Path=Cards}"
              SelectedItem="{Binding Path=SelectedCard, Mode=TwoWay}"
              />
    <StackPanel DataContext={Binding ElementName=_lbxCards,Path=SelectedItem}> <-- new
        <TextBlock Text="{Binding Path=Name}"                                  <-- updated
                   />
        <ListBox DisplayMemberPath="Name"
                 ItemsSource="{Binding Path=PendingTransactions}"              <-- updated
                 />
    </StackPanel>                                                              <-- new
</StackPanel>

完全没用!我根本没有任何绑定。至少以前第一次选择项目时会使用元素引用进行绑定,现在什么都没发生。 - SonOfPirate

0
原来问题根本不在UI上。PendingTransactions类使用异步WCF调用服务器来延迟加载其值。异步模式使用事件通知调用者操作完成,因此数据可以解析到类中。由于每个卡都有自己的PendingTransactions类实例,并且我们使用ServiceFactory来管理WCF代理,因此每个实例都将其事件处理程序连接到相同的事件(出于性能原因,我们目前正在使用单例方法)。因此,每个实例每次触发异步操作时都会收到事件。
这意味着数据绑定是正确的。每次查看新卡片时,PendingTransactions集合都会被覆盖。因此,选择以前的卡片似乎没有任何作用,实际上它选择了正确的绑定对象,只是数据出了问题,使其看起来像什么也没有改变。
尽管如此,感谢您的建议和指导!

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