MVVM列表框更新内容维护所选项目Silverlight

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

我已经读了很多关于MVVM的书(具体使用了Laurent Bugnon的库),我一直在努力确定如何在MVVM中做一些代码隐藏很容易的事情

这里只有一个例子,我怀疑我做的事情很艰难。如果有人有时间阅读所有这些,也许他们可以评论我的方法是否明智

我有一个绑定到ViewModel的列表框,如下所示:

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