1

This question evolves kind of the same issue like this question, but it concerns a different problem that I face because I use bindings.

I have added a button to delete the currently selected item from a ListBox (and one for a DataGrid where the same problem arises). The code to do that is bound to the button via an ICommand-object and the Button.Command property:

<Button Command="{Binding DeleteRowCommand}"
        CommandParameter="{Binding ElementName=MyListBox, Path=SelectedItem}" />

However this means that the click action is directly funneled into the ViewModel, which of course does not know the view's ListBox, so it cannot notify the view or update any selection.

What is the proper way to trigger code-behind both in the viewmodel and the view?

Maybe I could use the command-property and a Handles statement, but I'm not sure if that's viable.

Community
  • 1
  • 1
LWChris
  • 3,320
  • 1
  • 22
  • 39

2 Answers2

1

Here's what I would do.

Create a property in your ViewModel which will hold the SelectedItem.

private YourTypeHere _SelectedThing;

public YourTypeHere SelectedThing 
{
   get { return _SelectedThing; }
   set 
   { 
      _SelectedThing = value;

      //Call INotifyPropertyChanged stuff
    }
}

Now, bind your SelectedItem for your List to this property:

<ListBox SelectedItem="{Binding SelectedThing}" ... />

Performing these actions means that your SelectedThing is now the responsibility of the ViewModel, and when you call the Delete command, you can simply update the SelectedThing property to the last item in the list and your ListBox will be automatically updated.

Mike Eason
  • 9,525
  • 2
  • 38
  • 63
  • That is actually a pretty decent way to handle it. I will try to implement my view/viewmodel with that approach and tell you if I face any difficulties. If not, I will also mark this as accepted answer. – LWChris May 19 '15 at 12:05
  • I had a little struggle, but the approach was the way to go. I will post the full solution later. – LWChris May 20 '15 at 14:21
0

XAML:

<ListBox DataContext="{Binding Path=Category, Mode=OneTime}"
         ItemsSource="{Binding Path=Fields}"
         SelectedItem="{Binding Path=SelectedItem, Mode=OneWay}"
         SelectedIndex="{Binding Path=SelectedIndex}" />

Code behind in CategoryViewModel, the class of the Category object from th data context:

Public ReadOnly Property Fields As ObservableCollection(Of FieldViewModel)
  Get
    Return m_Fields
  End Get
End Property
Private ReadOnly m_Fields As New ObservableCollection(Of FieldViewModel)

Public Property SelectedIndex As Integer
  Get
    Return m_SelectedIndex
  End Get
  Set(value As Integer)
    m_SelectedIndex = value
    ValidateSelectedIndex()
    RaisePropertyChanged("SelectedIndex")
    RaisePropertyChanged("SelectedItem")
  End Set
End Property
Private m_SelectedIndex As Integer = -1

Public ReadOnly Property SelectedItem As FieldViewModel
  Get
    Return If(m_SelectedIndex = -1, Nothing, m_Fields.Item(m_SelectedIndex))
  End Get
End Property

Private Sub ValidateSelectedIndex()
  Dim count = m_Fields.Count
  Dim newIndex As Integer = m_SelectedIndex

  If count = 0 Then
    ' No Items => no selections
    newIndex = -1
  ElseIf count <= m_SelectedIndex Then
    ' Index > max index => correction
    newIndex = count - 1
  ElseIf m_SelectedIndex < 0 Then
    ' Index < min index => correction
    newIndex = 0
  End If

  m_SelectedIndex = newIndex
  RaisePropertyChanged("SelectedIndex")
  RaisePropertyChanged("SelectedItem")
End Sub

Public Sub New(model As Category)
  ' [...] Initialising of the view model,
  ' especially the m_Fields collection

  ' Auto update of SelectedIndex after modification
  AddHandler m_Fields.CollectionChanged, Sub() ValidateSelectedIndex()
  ' Set the SelectedIndex to 0 if there are items
  ' or -1 if there are none
  ValidateSelectedIndex()
End Sub

Now, whenever you delete an item from the m_Fields collection, the SelectedItem will be changed to the next item, or the previous item if the last item was removed, or Nothing if the last remaining item was removed.

LWChris
  • 3,320
  • 1
  • 22
  • 39