I am using SelectionChanged in ComboBox item, but when I select the same item again the SelectionChanged function does not fire and I need it to do so. How can I tell it to
Behavior which uses DropDownOpen and DropDwonClose
public class InvokeIfSameElementSelectedBehavior : Behavior<ComboBox>
{
#region public ICommand Command
private static readonly PropertyMetadata CommandMetaData = new PropertyMetadata(default(ICommand));
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command",
typeof(ICommand), typeof(InvokeIfSameElementSelectedBehavior), CommandMetaData);
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
#endregion //public ICommand Command
private bool _skipSelectionChanged;
private bool _popupMouseClicked;
private Popup _popup;
private object _previousValue;
protected override void OnAttached()
{
base.OnAttached();
if(AssociatedObject.IsLoaded)
AttachAllEvents();
else
AssociatedObject.Loaded += AssociatedObjectOnLoaded;
}
private void AssociatedObjectOnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
AssociatedObject.Loaded -= AssociatedObjectOnLoaded;
AttachAllEvents();
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.SelectionChanged -= AssociatedObjectOnSelectionChanged;
AssociatedObject.DropDownOpened -= AssociatedObjectOnDropDownOpened;
AssociatedObject.DropDownClosed -= AssociatedObjectOnDropDownClosed;
if(_popup != null)
_popup.PreviewMouseLeftButtonDown -= PopupOnPreviewMouseLeftButtonDown;
}
private void AttachAllEvents()
{
AssociatedObject.SelectionChanged += AssociatedObjectOnSelectionChanged;
AssociatedObject.DropDownOpened += AssociatedObjectOnDropDownOpened;
AssociatedObject.DropDownClosed += AssociatedObjectOnDropDownClosed;
AssociatedObject.ApplyTemplate();
_popup = (Popup)AssociatedObject.Template.FindName("PART_Popup", AssociatedObject);
if(_popup != null)
_popup.PreviewMouseLeftButtonDown += PopupOnPreviewMouseLeftButtonDown;
}
private void AssociatedObjectOnDropDownOpened(object sender, EventArgs e)
{
_popupMouseClicked = false;
_previousValue = AssociatedObject.SelectedItem;
}
private void AssociatedObjectOnDropDownClosed(object sender, EventArgs e)
{
try
{
if (_popupMouseClicked && Equals(AssociatedObject.SelectedItem, _previousValue)) //SelectionChanged handles it if value are not the same
InvokeChangeCommand(AssociatedObject.SelectedItem);
}
finally
{
_popupMouseClicked = false;
}
}
private void PopupOnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//ignore clicks on the scrollbars
if(e.Source is ScrollViewer)
return;
_popupMouseClicked = true;
}
private void AssociatedObjectOnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_skipSelectionChanged)
return;
try
{
_skipSelectionChanged = true;
if (e.AddedItems.Count != 1)
return;
InvokeChangeCommand(e.AddedItems[0]);
}
finally
{
_skipSelectionChanged = false;
}
}
private void InvokeChangeCommand(object item)
{
if (Command == null)
return;
if (!Command.CanExecute(item))
return;
Command.Execute(item);
}
}
Sample:
<ComboBox>
<i:Interaction.Behaviors>
<behaviors:InvokeIfSameElementSelectedBehavior Command="{Binding SelectionChangedCommand}"/>
</i:Interaction.Behaviors>
</ComboBox>
I used DropDownClosed, thank to - Clemens
You could use the dropdown opened even to set the selection to -1. Then in the event handler you need to ignore that change. On the dropdown closed event you can restore the original value if the control is closed.(Also ignore this change)
TO do it you will have to add an event for mouse up for every item you added in combo box.
I had the same question and I finally found the answer:
You need to handle BOTH the SelectionChanged event and the DropDownClosed like this:
In XAML:
<ComboBox Name="cmbSelect" SelectionChanged="ComboBox_SelectionChanged" DropDownClosed="ComboBox_DropDownClosed">
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem>2</ComboBoxItem>
<ComboBoxItem>3</ComboBoxItem>
</ComboBox>
In C#:
private bool handle = true;
private void ComboBox_DropDownClosed(object sender, EventArgs e) {
if(handle)Handle();
handle = true;
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
ComboBox cmb = sender as ComboBox;
handle = !cmb.IsDropDownOpen;
Handle();
}
private void Handle() {
switch (cmbSelect.SelectedItem.ToString().Split(new string[] { ": " }, StringSplitOptions.None).Last())
{
case "1":
//Handle for the first combobox
break;
case "2":
//Handle for the second combobox
break;
case "3":
//Handle for the third combobox
break;
}
}
You can bind the event handler to the onclickevent of the combobox then check if the selected item is null