我有一个Silverlight控件,它的根ViewModel对象是它的数据源。 ViewModel公开了一个Cards列表以及一个SelectedCard属性,该属性绑定到视图顶部的下拉列表。然后我在底部有一种形式的分类,显示了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属性正在正确更新。
我该如何工作?
答案 0 :(得分: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,一切都应该是满意的。
答案 1 :(得分: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>
答案 2 :(得分:0)
原来根本不在UI中的问题。 PendingTransactions类使用对服务器的异步WCF调用来延迟加载其值。异步模式使用事件通知调用者操作已完成,因此可以将数据解析到类中。因为每个Card都有自己的PendingTransactions类实例,并且我们使用ServiceFactory来管理我们的WCF代理,每个实例都将它们的事件处理程序连接到同一个事件(出于性能原因,我们暂时使用单例方法 - 暂时) 。因此,每次实例都会在每次实例触发异步操作时收到事件。
这意味着数据绑定工作正常。每次查看新卡时,PendingTransactions系列都会覆盖自己。因此,事实上,当选择正确的绑定对象时,选择之前的卡片似乎没有做任何事情,而是数据被搞砸了,看起来没什么变化。
感谢您的建议和指导!