C# 用于 ComboBox Item Selected 的事件处理程序(Selected Item 不一定更改)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16966264/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What event handler to use for ComboBox Item Selected (Selected Item not necessarily changed)
提问by grc
Goal:issue an event when items in a combobox drop down list is selected.
目标:选择组合框下拉列表中的项目时发出事件。
Problem:Using "SelectionChanged", however, if the user choose the same item as the item is currently being selected then the selection is not changed and therefore this event will not be triggered.
问题:然而,使用“SelectionChanged”,如果用户选择与当前正在选择的项目相同的项目,则选择不会改变,因此不会触发此事件。
Question:What other event handler(or other ways) I may use to issue an event regardless of the selected item is changed or not as long as the mouse clicked on that item and that item is being selected.
问题:我可以使用哪些其他事件处理程序(或其他方式)来发出事件,而不管所选项目是否更改,只要鼠标单击该项目并且该项目被选中。
(Clarification: Problem is how to trigger "something" when the same item is being selected again. No duplicates in the drop down list. Scenario: first time select item 1,close drop down. And then again, open drop down box and select item 1 when some function are triggered.)
(澄清:问题是如何在再次选择同一项目时触发“某事”。下拉列表中没有重复。场景:第一次选择项目 1,关闭下拉列表。然后再次打开下拉框并选择触发某些功能时的第 1 项。)
Solution: for now there seems to be no straight-forward solution to do this. But according to each individual project, there can be ways to work around it. (Please update if there are indeed good ways to do this). Thanks.
解决方案:目前似乎没有直接的解决方案来做到这一点。但是根据每个单独的项目,可以有办法解决它。(如果确实有好的方法,请更新)。谢谢。
回答by Vas Vasanth
You can try "SelectedIndexChanged", it will trigger the event even if the same item is selected.
您可以尝试“ SelectedIndexChanged”,即使选择了相同的项目,它也会触发事件。
回答by Vadim Levkovsky
You can use "ComboBoxItem.PreviewMouseDown" event. So each time when mouse is down on some item this event will be fired.
您可以使用“ComboBoxItem.PreviewMouseDown”事件。所以每次当鼠标放在某个项目上时,这个事件都会被触发。
To add this event in XAML use "ComboBox.ItemContainerStyle" like in next example:
要在 XAML 中添加此事件,请使用“ComboBox.ItemContainerStyle”,如下例所示:
<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
感谢MSDN
回答by deltonio2
I had the same question and I finally found the answer:
我有同样的问题,我终于找到了答案:
You need to handle BOTH the SelectionChanged event and the DropDownClosed like this:
您需要像这样处理 SelectionChanged 事件和 DropDownClosed:
In XAML:
在 XAML 中:
<ComboBox Name="cmbSelect" SelectionChanged="ComboBox_SelectionChanged" DropDownClosed="ComboBox_DropDownClosed">
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem>2</ComboBoxItem>
<ComboBoxItem>3</ComboBoxItem>
</ComboBox>
In C#:
在 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;
}
}
回答by nevets
This problem bugs me for a long time since none of the work-around worked for me :(
这个问题困扰了我很长时间,因为没有一种解决方法对我有用:(
But good news is, the following method works fine for my application.
但好消息是,以下方法适用于我的应用程序。
The basic idea is to register a EventManagerin App.xmal.csto sniff PreviewMouseLeftButtonDownEventfor all ComboBoxItem, then trigger the SelectionChangedEventif the selecting item is the same as the selected item, i.e. the selection is performed without changing index.
基本思想是注册一个EventManagerinApp.xmal.cs来嗅探PreviewMouseLeftButtonDownEventfor all ComboBoxItem,SelectionChangedEvent如果选择项与被选择项相同则触发,即在不改变 index 的情况下执行选择。
In App.xmal.cs:
在App.xmal.cs:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// raise selection change event even when there's no change in index
EventManager.RegisterClassHandler(typeof(ComboBoxItem), UIElement.PreviewMouseLeftButtonDownEvent,
new MouseButtonEventHandler(ComboBoxSelfSelection), true);
base.OnStartup(e);
}
private static void ComboBoxSelfSelection(object sender, MouseButtonEventArgs e)
{
var item = sender as ComboBoxItem;
if (item == null) return;
// find the combobox where the item resides
var comboBox = ItemsControl.ItemsControlFromItemContainer(item) as ComboBox;
if (comboBox == null) return;
// fire SelectionChangedEvent if two value are the same
if ((string)comboBox.SelectedValue == (string)item.Content)
{
comboBox.IsDropDownOpen = false;
comboBox.RaiseEvent(new SelectionChangedEventArgs(Selector.SelectionChangedEvent, new ListItem(), new ListItem()));
}
}
}
Then, for all combo boxes, register SelectionChangedEventin a normal way:
然后,对于所有组合框,SelectionChangedEvent以正常方式注册:
<ComboBox ItemsSource="{Binding BindList}"
SelectionChanged="YourSelectionChangedEventHandler"/>
Now, if two indices are different, nothing special but the ordinary event handling process; if two indices are the same, the Mouse Event on the item will first be handled, and thus trigger the SelectionChangedEvent. In this way, both situations will trigger SelectionChangedEvent:)
现在,如果两个索引不同,则没什么特别的,只是普通的事件处理过程;如果两个索引相同,将首先处理项目上的鼠标事件,从而触发SelectionChangedEvent. 这样,两种情况都会触发SelectionChangedEvent:)
回答by jv_
This is a DependencyObject for attaching to a ComboBox.
这是一个用于附加到 ComboBox 的 DependencyObject。
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.
它在下拉列表打开时记录当前选定的项目,如果在下拉列表关闭时仍然选择相同的索引,则触发 SelectionChanged 事件。可能需要对其进行修改才能与键盘选择一起使用。
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" />
回答by Daniel
For me ComboBox.DropDownClosedEvent did it.
对我来说ComboBox.DropDownClosedEvent 做到了。
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;
}
}
回答by Zack
回答by Robert
For UWP (Windows Store) apps none of the above will work (PointerPressed doesn't fire; no Preview, DropDownClosed or SelectedIndexChanged events exist)
对于 UWP(Windows 应用商店)应用,以上都不起作用(PointerPressed 不会触发;不存在 Preview、DropDownClosed 或 SelectedIndexChanged 事件)
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.
我不得不求助于覆盖 ComboBox 的透明按钮(但不是它的下拉箭头)。当您按下箭头时,列表会像往常一样下拉,并且组合框的 SelectionChanged 事件会触发。当您单击组合框上的任何其他位置时,透明按钮的单击事件会触发,允许您重新选择组合框的当前值。
Some working XAML code:
一些有效的 XAML 代码:
<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:
一些有效的 C# 代码:
/// <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);
}
回答by Gianluca Conte
I hope that you will find helpfull the following trick.
我希望你会发现以下技巧很有帮助。
You can bind both the events
您可以绑定两个事件
combobox.SelectionChanged += OnSelectionChanged;
combobox.DropDownOpened += OnDropDownOpened;
And force selected item to null inside the OnDropDownOpened
并强制所选项目在 OnDropDownOpened 内为空
private void OnDropDownOpened(object sender, EventArgs e)
{
combobox.SelectedItem = null;
}
And do what you need with the item inside the OnSelectionChanged. The OnSelectionChanged will be raised every time you will open the combobox, but you can check if SelectedItem is null inside the method and skip the command
并使用 OnSelectionChanged 中的项目执行您需要的操作。每次打开组合框时都会引发 OnSelectionChanged ,但您可以检查方法内的 SelectedItem 是否为空并跳过命令
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (combobox.SelectedItem != null)
{
//Do something with the selected item
}
}
回答by Evgeniy Miroshnichenko
Every ComboBoxItem instance has PreviewMouseDown event. If you will subscribe your custom handler on this event on every ComboBoxItem you will have opportunity to handle every click on the dropdown list.
每个 ComboBoxItem 实例都有 PreviewMouseDown 事件。如果您将在每个 ComboBoxItem 上的此事件上订阅您的自定义处理程序,您将有机会处理下拉列表上的每次点击。
// Subscribe on ComboBoxItem-s events.
comboBox.Items.Cast<ComboBoxItem>().ToList().ForEach(i => i.PreviewMouseDown += ComboBoxItem_PreviewMouseDown);
private void ComboBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
// your handler logic...
}

