MVVM Listbox Обновление содержимого Сохранение выбранного элемента Silverlight - PullRequest
6 голосов
/ 18 ноября 2010

Я много читал о MVVM (в частности, используя библиотеку Лорана Буньона), и я постоянно пытаюсь определить, как сделать вещи в 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 - это ObservableCollection объектов Fruit:

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 к кнопке на странице презентации, которая выполняет метод, который увеличивает количество выбранного элемента.Обратите внимание, что я пока не использую этот параметр, но «Боб» является местозаполнителем для некоторых изменений на будущее.

<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 Drag and Drop в MVVM.

Во-вторых, похоже, что при воссоздании списка такой подход выглядит довольно плохо.

Наконец, кажется, что в коде было бы легче (хотя я не уверен на 100%, что мне все равно не придется перестраивать этот список).

Есть ли у кого-нибудь мысли?на мой подход или, возможно, даже ... предложения, чтобы сделать вещи проще?Я просто упускаю что-то очевидное здесь?

Спасибо

-Дриодилат:]

1 Ответ

2 голосов
/ 18 ноября 2010

maulkye,

Что-то идет не так, если вам нужно обновить ObservableCollection.Обычно вам это не нужно, потому что ObservableCollection будет уведомлять об изменениях предметов.

Никогда не делайте этого:

FruitBasket = new ObservableCollection<Fruit>(FruitBasket);

У вашего public ObservableCollection<Fruit> FruitBasket не должно быть без публичного сеттера , это должно быть только для чтения.Просто Add или Remove Элементы в / из списка.

Если вы хотите обрабатывать несколько вариантов выбора, вам, вероятно, понадобится расширенный CollectionView, который может обработать это, получите больше подсказок здесь.

Надеюсь, это немного поможет, даже если я, вероятно, не ответил на все вопросы:)

РЕДАКТИРОВАТЬ: Хорошо, я думаю, я получилчто-то не так.Теперь, я думаю, я полностью понимаю, чего вы пытаетесь достичь.Вы не получаете уведомление об изменении вашей собственности, верно?По этой причине мы адаптировали « BindableLinq » в одном из наших проектов, который вы можете без проблем скомпилировать в Silverlight.(Существуют аналогичные решения, называемые Continuous Linq или Obtics , сделайте свой выбор).

Используя BindableLinq , вы можете преобразовать свой *От 1038 * до BindableCollection с использованием одного метода расширения.BindableCollection будет отражать все изменения должным образом.Попробуйте.

EDIT2: Для реализации правильного ViewModel, пожалуйста, рассмотрите следующие изменения.

1) Fruit это ваш Модель .Поскольку он не реализует INotifyPropertyChanged, он не распространяет никаких изменений.Создайте FruitViewModel, встраивая свою Fruit модель и вызывайте RaisePropertyChanged для каждого установщика свойств.

2) Измените FruitBasket на ObservableCollection из FruitViewModel.Постепенно это начинает иметь смысл:)

3) SelectedFruit также должно быть FruitViewModel.Теперь это имеет еще больший смысл.

4) Теперь оно у меня уже работает, даже без BindableLinq.Был ли у вас успех?

HTH

С наилучшими пожеланиями,
Томас

...