set Listbox.SelectedItem from code

Nov 27, 2013 at 5:21 AM
My apologies for this noob question.

View.xaml
  <ListBox ItemsSource="{Binding Path=VirtualStationCollection,Mode=TwoWay}" 
                     SelectedItem="{Binding VirtualStation, Mode=TwoWay}"/>  
ViewModel.cs
public IMachine VirtualStation
        {
            get { return GetValue<IMachine>(VirtualStationProperty); }
            set { SetValue(VirtualStationProperty, value); }
        }   
        public static readonly PropertyData VirtualStationProperty = RegisterProperty("VirtualStation", typeof(IMachine), null, (sender, e) => ((VirtualViewModel)sender).OnVirtualStationChanged(sender,e));

        private void OnVirtualStationChanged(object sender, AdvancedPropertyChangedEventArgs e)
    {
    if (VirtualStation != null)
            {
          VirtualStation = VirtualStationCollection[0];  //Doesn't work.
            }
    }
but if I set via EventToCommand instead:
 <i:Interaction.Triggers>
                  <i:EventTrigger EventName="SelectionChanged">
                    <catel:EventToCommand Command="{Binding OnSelectVirtualStation}" 
                                          PassEventArgsToCommand="True"
                                          DisableAssociatedObjectOnCannotExecute="false"/>
                  </i:EventTrigger>
 </i:Interaction.Triggers>
public Command<object> OnSelectVirtualStation { get; private set; }
private void OnOnSelectVirtualStationExecute(object parameter)
{
if (VirtualStation != null)
  {
    VirtualStation = VirtualStationCollection[0];  //this actually works! Sets the ListBox.SelectedItem to VirtualStation value;
   }
}
My objective is to get oldvalue and newvalue of a property, and if certain conditions are not met, then set the propertyvalue to oldvalue. The AdvancedPropertyChangedEventArgs would be suitable enough, but I can't seem to figure out.

What am I missing?
Many Thanks.
Coordinator
Nov 27, 2013 at 6:27 PM
Edited Nov 27, 2013 at 6:27 PM
First of all, we recommend that you rename the command to SelectVirtualStation.

Second, it depends on which version of the .NET framework you are using. There is an issue with older versions (I think it was fixed in 4.5) where setting the value inside the call that handles the binding update, the source would not update in the view again.

To solve this quick 'n' dirty, do this:
private void OnVirtualStationChanged(object sender, AdvancedPropertyChangedEventArgs e)
{
    if (VirtualStation != null)
    {
        DispatcherHelper.CurrentDispatcher.BeginInvoke(() => VirtualStation = VirtualStationCollection[0]);
     }
}
Note that it is a bit ugly, but it will help you out for now.

You can also use the IDispatcherService for this (which at least is a better abstraction).
Nov 29, 2013 at 8:08 AM
Many thanks Geert!


What I'm trying to implement is to somehow handle(and cancel) the selectionchanged event of the listbox.
I did some reading and unfortunately, this is a case of buggy selector base class.

"The problem is in a base class called Selector, which ListView, Listbox, TabControl,
TreeNodes, combo box items and whole other bunch of selectables come from."
http://social.msdn.microsoft.com/Forums/vstudio/en-US/8eeed347-ede5-4a24-88f1-953acd16e774/preventing-listbox-selection-change?forum=wpf

I thought it's a good idea to somehow catch it during PreviewMouseLeftButtonDown.
<ListBox Margin="5,10" Name="VMListBox" MinWidth="150" 
              ItemsSource="{Binding Path=VirtualStationCollection}" 
                     SelectedItem="{Binding VirtualStation}">
<i:Interaction.Triggers>
                  <i:EventTrigger EventName="Loaded">
                    <catel:EventToCommand Command="{Binding LoadVirtualStations}"/>
                  </i:EventTrigger>
                  <i:EventTrigger EventName="PreviewMouseLeftButtonDown">
                    <catel:EventToCommand Command="{Binding SelectVirtualStationChanged}" 
                                          PassEventArgsToCommand="True" DisableAssociatedObjectOnCannotExecute="false"/>
                  </i:EventTrigger>
                </i:Interaction.Triggers>       
</ListBox>       
public Command<object> SelectVirtualStationChanged { get; private set; }
private void OnSelectVirtualStationChangedExecute(object parameter)
        {
            System.Windows.Input.MouseButtonEventArgs e = parameter as System.Windows.Input.MouseButtonEventArgs;
            if (VirtualStation != null)
            {           
                if(System.Windows.MessageBox.Show("Switch VirtualStation?","Confirm",System.Windows.MessageBoxButton.OKCancel)==System.Windows.MessageBoxResult.Cancel)
                {
                    e.Handled = true;                   
                }           
            }
        }
Now my problem is, after handling the PreviewMouseLeftButtonDown, the event does not reach my PropertyChanged
private void OnVirtualStationChanged(object sender, AdvancedPropertyChangedEventArgs e)
{
  Debug.WriteLine("VirtualStationChanged!");
}
It seems to get lost here, since without this, it reaches my propertychanged event.
if(System.Windows.MessageBox.Show("Switch VirtualStation?","Confirm",
System.Windows.MessageBoxButton.OKCancel)==System.Windows.MessageBoxResult.Cancel)
                {
                    e.Handled = true;                   
                }   
This could probably be WPF specific, but I'm hoping somebody else is familiar with this issue.
Thanks!