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

时间:2010-11-18 19:39:33

标签: silverlight mvvm binding listbox command

我一直在阅读很多关于MVVM的信息(特别是使用Laurent Bugnion的库),我一直在努力确定如何在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>

ItemSource是Fruit对象的ObservableCollection:

public class Fruit
{
    public string Name { get; set; }
    public int Quantity { get; set; }

    public Fruit() { }
    public Fruit(string name, int quantity) 
    {
      this.Name = name;
      this.Quantity = quantity;
    }
  }

它在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);
  }
}

绑定的SelectedItem属性如下:

//Property SelectedFruit
public const string SelectedFruitPropertyName = "SelectedFruit";

private Fruit _selectedFruit = null;

public Fruit SelectedFruit
{
  get { return _selectedFruit; }
  set
  {
    if (_selectedFruit == value)
      return;

    var oldValue = _selectedFruit;
    _selectedFruit = value;

    // Update bindings, no broadcast
    RaisePropertyChanged(SelectedFruitPropertyName);
  }
}

然后,列表将填充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>

以下是该命令的代码:

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

现在这确实有效,但我遇到了一些问题:

首先,我觉得有很多条件必须聚集起来才能实现这一点,我想知道我是否会如此幸运地试图将一些Telerik拖放代码移动到MVVM中。

其次,重新创建列表似乎是一种非常差的性能方法。

最后,在代码背后似乎会更容易(虽然我不是100%肯定我仍然不需要重建该列表)。

有没有人对我的方法有任何想法,甚至可能......提出更容易的建议?我只是遗漏了一些明显的东西吗?

由于

-Dalodilate:]

1 个答案:

答案 0 :(得分:2)

maulkye,

如果您需要刷新ObservableCollection,则会出现问题。通常,您不应该需要它,因为ObservableCollection将通知项目更改。

永远不要这样做:

FruitBasket = new ObservableCollection<Fruit>(FruitBasket);

您的public ObservableCollection<Fruit> FruitBasket应该没有公开制定者,它应该是只读的。只需AddRemove列表中的项目。

如果您想要处理多项选择,您可能需要一个可以处理此问题的扩展CollectionView,获得更多提示here

我希望这有点帮助,即使我可能没有回答所有问题:)

修改 好吧,我想我有些不对劲。现在我想我完全理解你想要完成的事情。当您的房产发生变更时, 会收到通知,对吗?好吧,出于这个原因,我们在我们的一个项目中调整了“BindableLinq”,你可以在Silverlight中编译而没有问题。 (有类似的解决方案,名为Continuous LinqObtics,可供选择)。

使用 BindableLinq ,您可以使用一种扩展方法将ObservableCollection转换为BindableCollection。然后,BindableCollection会正确反映所有更改。试一试。

<强> EDIT2: 要实施正确的 ViewModel,请考虑以下更改。

1)Fruit是您的模型。由于它没有实现INotifyPropertyChanged,因此不会传播任何更改。创建FruitViewModel,嵌入Fruit模型并为每个属性设置器调用RaisePropertyChanged

2)将您的FruitBasket更改为ObservableCollection FruitViewModel。慢慢地开始有意义:))

3)SelectedFruit也必须是FruitViewModel。现在它更有意义。

4)现在它已经适合我,即使没有BindableLinq。你有成功吗?

HTH

最好的问候,
托马斯