MVVM列表框更新内容维护所选项目Silverlight
我已经读了很多关于MVVM的书(具体使用了Laurent Bugnon的库),我一直在努力确定如何在MVVM中做一些代码隐藏很容易的事情 这里只有一个例子,我怀疑我做的事情很艰难。如果有人有时间阅读所有这些,也许他们可以评论我的方法是否明智 我有一个绑定到ViewModel的列表框,如下所示:MVVM列表框更新内容维护所选项目Silverlight,silverlight,mvvm,binding,listbox,command,Silverlight,Mvvm,Binding,Listbox,Command,我已经读了很多关于MVVM的书(具体使用了Laurent Bugnon的库),我一直在努力确定如何在MVVM中做一些代码隐藏很容易的事情 这里只有一个例子,我怀疑我做的事情很艰难。如果有人有时间阅读所有这些,也许他们可以评论我的方法是否明智 我有一个绑定到ViewModel的列表框,如下所示: <ListBox x:Name="lstFruitBasketLeft" ItemsSource="{Binding FruitBasket}" SelectedItem="{Bindi
<ListBox x:Name="lstFruitBasketLeft" ItemsSource="{Binding FruitBasket}"
SelectedItem="{Binding SelectedFruit, Mode=TwoWay}" Width="150">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"
HorizontalAlignment="Left" Margin="2">
<TextBlock Text="{Binding Name}" />
<TextBlock Text=":" />
<TextBlock Text="{Binding Quantity}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
它在ViewModel中定义为:
// Property FruitBasket
public const string FruitBasketPropertyName = "FruitBasket";
private ObservableCollection<Fruit> _fruitBasket = null;
public ObservableCollection<Fruit> FruitBasket
{
get { return _fruitBasket; }
set
{
if (_fruitBasket == value)
return;
_fruitBasket = value;
// Update bindings, no broadcast
RaisePropertyChanged(FruitBasketPropertyName);
}
}
然后,在构建ViewModel时填充该列表
现在,我向演示页面上的一个按钮添加了一个RelayCommand,该按钮执行一个增加所选项目数量的方法。请注意,我还没有使用参数,但是“Bob”是一个占位符,用于以后的一些更改
<Button x:Name="butMore" Content="More!" HorizontalAlignment="Right" Height="25" Width="75" Margin="4">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand
Command="{Binding addMoreCommand}"
CommandParameter="Bob" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
public void AddFruit()
{
//生果
选择水果。数量++;
//保存上一个选定项目
水果oldSelectedItem=选择的水果;
//我们必须有一个新的列表才能刷新列表框
果篮=新观察到的集合(果篮);
//重选
SelectedFruit=oldSelectedItem;
}
公共图书馆
{
返回true;//暂时返回
}
现在这确实有效,但我有一些问题:
首先,我觉得有很多条件必须结合在一起才能让它工作,我想知道如果我尝试将一些Telerik拖放代码移动到MVVM中,是否会如此幸运
其次,像这样重新创建列表似乎是一种性能非常差的方法
最后,在代码隐藏中这似乎更容易(尽管我不能100%确定我仍然不必重新构建该列表)
有没有人对我的方法有任何想法,或者甚至。。。让事情变得更简单的建议?我是不是错过了一些明显的东西
谢谢
-Driodilate:maulkye
如果您必须刷新您的可观察集合
,则会出现问题。通常,您不应该需要它,因为ObservableCollection
将通知项目更改
永远不要这样做:
FruitBasket = new ObservableCollection<Fruit>(FruitBasket);
foultbasket=新的可见采集(foultbasket);
您的公共可观察收集子篮
应该有无公共设置器,它应该是只读的。只需在列表中添加或删除项即可
如果您想处理多个选择,您可能需要一个扩展的CollectionView
,它可以处理这个问题,并获得更多提示
我希望这有点帮助,即使我可能没有回答所有的问题:)
编辑:
好吧,我想我有些地方搞错了。现在我想我完全理解你想要实现的目标。当您的财产发生变化时,您不会得到通知,对吗?出于这个原因,我们在一个项目中修改了“”,您可以在Silverlight中毫无问题地编译它。(有类似的解决方案,称为或,由您选择)
使用BindableLinq,您可以使用一种扩展方法将observedcollection
转换为BindableCollection
。BindableCollection
将正确反映所有更改。试试看
EDIT2:
要实现<强>正确的<强> VIEW模型,请考虑以下更改:
1) 水果
是您的型号。由于它没有实现INotifyPropertyChanged,因此不会传播任何更改。创建一个水果视图模型
,嵌入您的水果
模型,并为每个属性设置器调用RaisePropertyChanged
2) 将您的水果篮
更改为水果视图模型
的可观察集合
。慢慢地,它开始有意义了:)
3) SelectedFruit
也必须是FruitViewModel
。现在它更有意义了
4) 现在它已经对我起作用了,即使没有BindableLinq
。你成功了吗
嗯
致以最诚挚的问候,thomas好吧,这确实有帮助,但这让我不知道如何正确更新绑定控件。请记住,我不是在添加或删除项目(如果没有额外的代码,这将非常有效)。我的问题发生在我更新ObservaleCollection.Hmmmm中某个对象的属性时,尽管你让我思考了一下。我可以删除所选项目,对其进行更新,然后将其添加回以使自动更新生效。虽然我不确定这将如何影响排序。请检查我的编辑,还有一个轨道,你可以遵循:)我将不得不花更多的时间看看这些。我的第一个使用Bindable Linq的测试已经编译并运行,但没有传播我的更改(我确实将源代码编译到了我的项目中,因为它是针对它的项目中的WPF的)。此外,如果我真的让它工作了,我还不确定如何将它推到我的ViewModel中。等我有更多的时间再做评论。谢谢好吧,好吧,你说的是ViewModels,对吧,请先检查我的EDIT2并忘记
BindableLinq
。也许我们稍后会再讨论它,但您需要首先实现一个适当的ViewModel
<Button x:Name="butMore" Content="More!" HorizontalAlignment="Right" Height="25" Width="75" Margin="4">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand
Command="{Binding addMoreCommand}"
CommandParameter="Bob" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
// Property addMoreCommand
public RelayCommand addMoreCommand
{
get;
private set;
}
//Init relays (this is in the constructor)
addMoreCommand = new RelayCommand(AddFruit, CanExecute);
public void AddFruit()
{
//Increment the fruit
SelectedFruit.Quantity++;
//Save the previous selected item
Fruit oldSelectedItem = SelectedFruit;
//We have to have a new list in order to get the list box to refresh
FruitBasket = new ObservableCollection<Fruit>(FruitBasket);
//Reselect
SelectedFruit = oldSelectedItem;
}
public bool CanExecute()
{
return true; //for now
}
FruitBasket = new ObservableCollection<Fruit>(FruitBasket);