2010-04-19 30 views
4

我有一个Silverlight控件,它具有我的根ViewModel对象,因为它是数据源。 ViewModel公开了一张卡片列表以及一个SelectedCard属性,该属性绑定到视图顶部的下拉列表中。然后,我在底部显示SelectedCard的属性。我的XAML显示为(减少为简单起见):Silverlight 3数据绑定子属性不更新

<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> 

我希望将TextBlock和列表框更新,每当我选择在ComboBox一个新的项目,但事实并非如此。我相信这与TextBlock和ListBox实际绑定到SelectedCard的属性有关,因此它正在侦听该对象属性的属性更改通知。但是,我会认为数据绑定足够聪明,可以识别绑定表达式中的父对象已经更改并更新整个绑定。

它注意到PendingTransactions属性(绑定到ListBox)是延迟加载的。因此,我第一次在ComboBox中选择一个项目时,我会进行异步调用并加载列表和UI更新以显示与所选项目相对应的信息。但是,当我重新选择一个项目时,UI不会改变!

例如,如果我的原始列表包含三张卡片,则默认选择第一张卡片。数据绑定确实尝试访问该Card对象上的PendingTransactions属性并正确更新ListBox。如果我选择列表中的第二张卡片,则会发生同样的情况,并显示该卡片的PendingTransactions列表。但是,如果我再次选择第一张卡片,则在我的用户界面中没有任何变化!设置断点,我能够确认正在更新SelectedCard属性。

我该如何做这项工作?

回答

0

原来,问题不在UI中。 PendingTransactions类使用异步WCF调用向服务器延迟加载其值。异步模式使用事件来通知调用者操作已完成,因此可以将数据解析到类中。因为每张卡片都有自己的PendingTransactions类的实例,并且我们使用ServiceFactory来管理我们的WCF代理,所以每个实例都将它们的事件处理程序连接到相同的事件(为了性能原因,我们正在使用单例方法 - 暂时) 。因此,每当任何实例触发异步操作时,每个实例都会收到该事件。

这意味着数据绑定工作正常。 PendingTransactions系列每次查看新卡片时都会覆盖自己。所以,看起来选择一张以前的卡片实际上并没有做任何事情,事实上,它选择了正确的对象进行绑定,数据被搞砸了,看起来没有任何变化。

感谢您的建议和指导!

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,一切都应该是快乐的。

+0

这就是我唯一的例外,即Cards属性是ReadOnlyCollection,因为它不会改变。 – SonOfPirate 2010-04-19 16:07:56

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> 
+0

这根本不起作用!我没有任何约束力。至少在它第一次绑定之前,我使用元素引用选择了一个项目,根本没有任何事情发生。 – SonOfPirate 2010-04-19 16:35:46