MVVM content list content content supports selected Silverlight item

I read a lot about MVVM (using the Laurent Bugnion library in particular), and I am constantly trying to determine how to do something in MVVM that were otherwise easy with the code.

Here is just one example where I suspect that I am doing something difficult. If anyone has the time to read all this, maybe they can comment on the common sense of my approach. :)

I have a list box related to ViewModel as follows:

<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 is an ObservableCollection of Fruit object:

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

It is defined in the ViewModel as:

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

The bound SelectedItem property as such:

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

Then the list is entered into the ViewModel construct.

Now I am adding RelayCommand to a button on the presentation page that executes a method that increases the number of the selected item. Note that I am not using the option yet, but "Bob" is a replacement for some changes later.

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

Here is the code for the command:

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

Now it works, but I have some problems with it:

Firstly, I feel that there are many conditions that need to come together for this to work, and I wonder if I can get so lucky that it moves some kind of Telerik drag and drop code to MVVM.

Secondly, it seems like a pretty poor performance approach to recreate a list.

Finally, it seems like it would be easier in code (although I'm not 100% sure that I still won’t have to rebuild this list).

Does anyone have any thoughts on my approach or maybe even ... suggestions to ease the situation? Did I just miss something obvious here?

thanks

-Driodilate:]

+6
command silverlight mvvm binding listbox
source share
1 answer

maulkye,

Something is wrong if you need to update ObservableCollection . Usually you do not need it, because ObservableCollection will notify you about changes to elements.

Never do this:

 FruitBasket = new ObservableCollection<Fruit>(FruitBasket); 

Your public ObservableCollection<Fruit> FruitBasket should not have a public setter , it should be read-only. Just Add or Remove Items to / from the list.

If you want to handle multiple options, you probably need an advanced CollectionView that can handle this, get more tips here .

Hope this helps a little, even if I probably didn't answer all the questions :)

EDIT: Well, I think something is wrong with me. Now I think I fully understand what you are trying to achieve. You don’t get notified when your property is changed, right? For this reason, we adapted " BindableLinq in one of our projects, which you can easily compile into Silverlight. (There are similar solutions called Continuous Linq or Obtics , make your choice).

Using BindableLinq , you can convert an ObservableCollection to a BindableCollection with a single extension method. BindableCollection will then reflect all changes properly. Give it a try.

EDIT2: To implement ViewModel correctly , consider the following changes.

1) Fruit is your Model . Since it does not implement INotifyPropertyChanged , it will not propagate any changes. Create a FruitViewModel your Fruit model and call RaisePropertyChanged for each property setting tool.

2) Change FruitBasket to ObservableCollection FruitViewModel . Slowly it starts to make sense :)

3) SelectedFruit must also be a FruitViewModel . Now that makes even more sense.

4) Now it already works for me, even without BindableLinq . Have you had success?

NTN

best regards,
Thomas

+2
source share

All Articles