Goal: issue an event when items in a combobox drop down list is selected.
Problem: Using \"SelectionChanged\", however, if the user
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;
}
}
Use SelectionChangeCommitted(object sender, EventArgs e)
event
here
This is a DependencyObject for attaching to a ComboBox.
It records the currently selected item when the dropdown is opened, and then fires SelectionChanged event if the same index is still selected when the dropdown is closed. It may need to be modified for it to work with Keyboard selection.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Web.UI.WebControls;
namespace MyNamespace
{
public class ComboAlwaysFireSelection : DependencyObject
{
public static readonly DependencyProperty ActiveProperty = DependencyProperty.RegisterAttached(
"Active",
typeof(bool),
typeof(ComboAlwaysFireSelection),
new PropertyMetadata(false, ActivePropertyChanged));
private static void ActivePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var element = d as ComboBox;
if (element == null)
return;
if ((e.NewValue as bool?).GetValueOrDefault(false))
{
element.DropDownClosed += ElementOnDropDownClosed;
element.DropDownOpened += ElementOnDropDownOpened;
}
else
{
element.DropDownClosed -= ElementOnDropDownClosed;
element.DropDownOpened -= ElementOnDropDownOpened;
}
}
private static void ElementOnDropDownOpened(object sender, EventArgs eventArgs)
{
_selectedIndex = ((ComboBox) sender).SelectedIndex;
}
private static int _selectedIndex;
private static void ElementOnDropDownClosed(object sender, EventArgs eventArgs)
{
var comboBox = ((ComboBox) sender);
if (comboBox.SelectedIndex == _selectedIndex)
{
comboBox.RaiseEvent(new SelectionChangedEventArgs(Selector.SelectionChangedEvent, new ListItemCollection(), new ListItemCollection()));
}
}
[AttachedPropertyBrowsableForChildrenAttribute(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(ComboBox))]
public static bool GetActive(DependencyObject @object)
{
return (bool)@object.GetValue(ActiveProperty);
}
public static void SetActive(DependencyObject @object, bool value)
{
@object.SetValue(ActiveProperty, value);
}
}
}
and add your namespace prefix to make it accessible.
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ut="clr-namespace:MyNamespace" ></UserControl>
and then you need to attach it like so
<ComboBox ut:ComboAlwaysFireSelection.Active="True" />
For me ComboBox.DropDownClosed
Event did it.
private void cbValueType_DropDownClosed(object sender, EventArgs e)
{
if (cbValueType.SelectedIndex == someIntValue) //sel ind already updated
{
// change sel Index of other Combo for example
cbDataType.SelectedIndex = someotherIntValue;
}
}
For UWP (Windows Store) apps none of the above will work (PointerPressed doesn't fire; no Preview, DropDownClosed or SelectedIndexChanged events exist)
I had to resort to a transparent button overlaying the ComboBox (but not its drop down arrow). When you press on the arrow, the list drops down as usual and the Combo Box's SelectionChanged event fires. When you click anywhere else on the Combo Box the transparent button's click event fires allowing you to re-select the Combo Box's current value.
Some working XAML code:
<Grid x:Name="ComboOverlay" Margin="0,0,5,0"> <!--See comments in code behind at ClickedComboButValueHasntChanged event handler-->
<ComboBox x:Name="NewFunctionSelect" Width="97" ItemsSource="{x:Bind Functions}"
SelectedItem="{x:Bind ChosenFunction}" SelectionChanged="Function_SelectionChanged"/>
<Button x:Name="OldFunctionClick" Height="30" Width="73" Background="Transparent" Click="ClickedComboButValueHasntChanged"/>
</Grid>
Some working C# code:
/// <summary>
/// It is impossible to simply click a ComboBox to select the shown value again. It always drops down the list of options but
/// doesn't raise SelectionChanged event if the value selected from the list is the same as before
///
/// To handle this, a transparent button is overlaid over the ComboBox (but not its dropdown arrow) to allow reselecting the old value
/// Thus clicking over the dropdown arrow allows the user to select a new option from the list, but
/// clicking anywhere else in the Combo re-selects the previous value
/// </summary>
private void ClickedComboButValueHasntChanged(object sender, RoutedEventArgs e)
{
//You could also dummy up a SelectionChangedEvent event and raise it to invoke Function_SelectionChanged handler, below
FunctionEntered(NewFunctionSelect.SelectedValue as string);
}
private void Function_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
FunctionEntered(e.AddedItems[0] as string);
}
You can use "ComboBoxItem.PreviewMouseDown" event. So each time when mouse is down on some item this event will be fired.
To add this event in XAML use "ComboBox.ItemContainerStyle" like in next example:
<ComboBox x:Name="MyBox"
ItemsSource="{Binding MyList}"
SelectedValue="{Binding MyItem, Mode=OneWayToSource}" >
<ComboBox.ItemContainerStyle>
<Style>
<EventSetter Event="ComboBoxItem.PreviewMouseDown"
Handler="cmbItem_PreviewMouseDown"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
and handle it as usual
void cmbItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
//...do your item selection code here...
}
Thanks to MSDN