Sending data from view to viewmodel with command binding

2.5k Views Asked by At

Question: How do send data to a view model when using command binding? So that, for example, when i click a button, it sends the "currently selected index" of a list so that it can perform an operation on that item of the list


Further Information: I'm working on a program where i have a list of shipments, and each shipment has a list of pallets. I want to make a button that will allow me to add a new pallet to the currently selected shipment. >Edit> And to through another wrench into the works, each pallet has a list of products. so not only do i need to know what shipment i'm on, but i also need to know what pallet of what shipment I'm on.

When I do a command binding, I have no idea how to send the data to the ViewModel. I would like to keep this pure MVVM so i don't want to have the ViewModel checking the view for anything.

~N


Edits: 11/04/09 - I removed the section of the question about the instantiation of the ViewModel. I'll ask that again in a different question as this one is well on track for solving the other question. And I made a few other edits to the question to clearify in the direction i want. as well as changed some grammatical bits so that it wasn't talking about two questions when there is only one.

2

There are 2 best solutions below

9
On BEST ANSWER

I usually expose a CollectionView from the view model and set the IsSynchronizedWithCurrentItem property on the ItemsControl displaying the list in the view. Then when the command is executed, I can inspect the CollectionView.CurrrentItem propety to see what is currently selected.

EDIT: This answer addresses the first question in your, um, question. Rather than your view sending the currently selected item to the ViewModel, the ViewModel keeps track of the currently selected item. So using this technique you don't need to work out how to send that information.

Something like this in your view model:

class ApplicationViewModel
{
    // Exposes a list of ShipmentViewModels.
    public CollectionView Shipments { get; private set; }

    // A DelegateCommand or similar, that when executed calls AddPallet().
    public ICommand AddPalletCommand { get; private set; }

    void AddPallet()
    {
        ShipmentViewModel shipment = (ShipmentViewModel)Shipments.CurrentItem;
        shipment.Pallets.Add(new PalletViewModel(...));
    }
}

And then this in your xaml:

<ListBox ItemsSource="{Binding Shipments}" IsSynchronizedWithCurrentItem="True"/>
<Button Command="{Binding AddPalletCommand}>Add Pallet</Button>

This way you can also track the selection of the Shipments collection from your ViewModel and update the command's CanExecute state.

Does that help any?

5
On

For keeping track of the currently selected item I do something similar to Groky, maybe this example make a little more sense.

In your ViewModel that contains the collection that your list is bound to (I'm using a ListBox in this example) expose a property that relates to the selected item.

// Assuming your using the MVVM template from Microsoft
public class PalletListViewModel : ViewModelBase
{
   // The collection our list is bound to
   private ObservableCollection<Pallet> _palletList;
   // The current selected item
   private Pallet _selectedPallet;
   // Our command bound to the button
   private DelegateCommand _processCommand;

   public ObservableCollection<Pallet> PalletList
   {
      get { return _palletList; }
   }

   public Pallet SelectedPallet
   {
      get { return _selectedPallet; }
      set
      {
         if(value == _selectedPallet)
            return;

         _selectedPallet = value;

         // INotifyPropertyChanged Method for updating the binding
         OnPropertyChanged("SelectedPallet");
      }
   }

   public ICommand ProcessCommand
   {
      get
      {
         if(_processCommand == null)
            _processCommand = new DelegateCommand(Process);
         return _processCommand;
      }
   }

   private void Process()
   {
      // Process the SelectedPallet
   }
}

<Window ...>
   <Grid x:Name="LayoutRoot">
      <Button Content="Process Pallet" Command="{Binding ProcessCommand}" />
      <ListBox ItemsSource="{Binding PalletList}" SelectedItem="{Binding SelectedPallet}">
         ...
      </ListBox>
   </Grid>
</Window>

Hopefully this is what your looking for.