C# 用于所选组合框项的事件处理程序(所选项不必更改)

C# 用于所选组合框项的事件处理程序(所选项不必更改),c#,wpf,C#,Wpf,目标:选择组合框下拉列表中的项目时发出事件 问题:使用“SelectionChanged”,但是,如果用户选择与当前正在选择的项目相同的项目,则不会更改选择,因此不会触发此事件 问题:无论所选项目是否更改,只要鼠标单击该项目且该项目处于选中状态,我都可以使用哪些其他事件处理程序(或其他方式)来发出事件 (澄清:问题是如何在再次选择同一项时触发“某物”。下拉列表中没有重复项。场景:第一次选择项1,关闭下拉列表。然后再次打开下拉框,在触发某些功能时选择项1。) 解决方案:目前似乎没有直接的解决方案。

目标:选择组合框下拉列表中的项目时发出事件

问题:使用“SelectionChanged”,但是,如果用户选择与当前正在选择的项目相同的项目,则不会更改选择,因此不会触发此事件

问题:无论所选项目是否更改,只要鼠标单击该项目且该项目处于选中状态,我都可以使用哪些其他事件处理程序(或其他方式)来发出事件

(澄清:问题是如何在再次选择同一项时触发“某物”。下拉列表中没有重复项。场景:第一次选择项1,关闭下拉列表。然后再次打开下拉框,在触发某些功能时选择项1。)

解决方案:目前似乎没有直接的解决方案。但根据每个单独的项目,都有办法解决它。(如果确实有好的方法,请更新)。谢谢。

您可以尝试“
SelectedIndexChanged
”,即使选择了相同的项目,它也会触发事件。

您可以使用“ComboBoxItem.PreviewMouseDown”事件。因此,每次鼠标落在某个项目上时,都会触发此事件

要在XAML中添加此事件,请使用“ComboBox.ItemContainerStyle”,如下一个示例所示:


照常处理

void cmbItem_PreviewMouseDown(对象发送器,鼠标按钮ventargs e)
{
//…请在此处输入您的项目选择代码。。。
}

多亏了

我有了同样的问题,我终于找到了答案:

您需要像这样处理SelectionChanged事件和DropDownClosed:

在XAML中:

<ComboBox Name="cmbSelect" SelectionChanged="ComboBox_SelectionChanged" DropDownClosed="ComboBox_DropDownClosed">
    <ComboBoxItem>1</ComboBoxItem>
    <ComboBoxItem>2</ComboBoxItem>
    <ComboBoxItem>3</ComboBoxItem>
</ComboBox>

这个问题困扰了我很长一段时间,因为所有的工作都不适合我:(

但好消息是,下面的方法对我的应用程序非常有效

基本思想是在
App.xmal.cs
中注册
EventManager
以嗅探所有
ComboBoxItem
PreviewMouseLeftButtonDownEvent
,然后在选择项与所选项相同的情况下触发
SelectionChangedEvent
,即在不更改索引的情况下执行选择

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()));
        }
    }
}
然后,对于所有组合框,以正常方式注册
SelectionChangedEvent

<ComboBox ItemsSource="{Binding BindList}"
          SelectionChanged="YourSelectionChangedEventHandler"/>


现在,如果两个索引不同,除了普通的事件处理过程之外没有什么特别的;如果两个索引相同,则首先处理项目上的鼠标事件,从而触发
SelectionChangedEvent
。这样,两种情况都将触发
SelectionChangedEvent
:)

这是用于附加到组合框的DependencyObject

当下拉列表打开时,它会记录当前选定的项目,如果在下拉列表关闭时仍选择相同的索引,则会激发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);
        }
    }
}
并添加名称空间前缀以使其可访问

<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>

然后你需要像这样附加它

<ComboBox ut:ComboAlwaysFireSelection.Active="True" />

对于我
组合框。DropDownClosed
事件完成了它

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;
        }
    }

使用
SelectionChangeCommitted(对象发送方,事件参数)
event

对于UWP(Windows应用商店)应用程序,上述各项均无效(PointerPressed不启动;不存在预览、DropDownClosed或SelectedIndexChanged事件)

我不得不求助于覆盖组合框的透明按钮(但不是它的下拉箭头)。按箭头时,列表会像往常一样下拉,组合框的SelectionChanged事件会触发。单击组合框上的任何其他位置时,将触发透明按钮的单击事件,允许您重新选择组合框的当前值

一些工作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>

一些工作C#代码:

//
///不可能简单地单击组合框来再次选择显示的值。它总是下拉选项列表,但是
///如果从列表中选择的值与以前相同,则不会引发SelectionChanged事件
///     
///为了处理这个问题,一个透明按钮覆盖在组合框上(但不是它的下拉箭头),以允许重新选择旧值
///因此,点击下拉箭头允许用户从列表中选择一个新选项,但是
///单击组合框中的任何其他位置可重新选择上一个值
/// 
private void ClickedComboButValueHasntChanged(对象发送者,路由目标)
{
//您还可以虚拟SelectionChangedEvent事件,并引发它以调用下面的函数\u SelectionChanged handler
输入函数(NewFunctionSelect.SelectedValue作为字符串);
}
私有无效函数\u SelectionChanged(对象发送方,SelectionChangedEventArgs e)
{
输入的函数(例如,作为字符串的AddedItems[0];
}

我希望下面的技巧能对您有所帮助

您可以绑定这两个事件

combobox.SelectionChanged += OnSelectionChanged;
combobox.DropDownOpened += OnDropDownOpened;
并强制所选项目在OnDropDownOpen中为空

private void OnDropDownOpened(object sender, EventArgs e)
{
    combobox.SelectedItem = null;
}
并对OnSelectionChanged中的项目执行所需操作。 每次打开组合框时都会引发OnSelectionChanged,但您可以检查方法内的SelectedItem是否为null并跳过该命令

private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (combobox.SelectedItem != null)
        {
           //Do something with the selected item
        }
    }

每个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...         
}
//订阅ComboBoxItem-s事件。
comboBox.Items.Cast().ToList().ForEach(i=>i.PreviewMouseDown+=ComboBoxItem\u PreviewMouseDown);
私人无效组合
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (combobox.SelectedItem != null)
        {
           //Do something with the selected item
        }
    }
// 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...         
}
class ExtendedComboBox : ComboBox
{
    public ExtendedComboBox()
    {
        SelectionChanged += OnSelectionChanged;
    }

    protected override void PrepareContainerForItemOverride(Windows.UI.Xaml.DependencyObject element, object item)
    {
        ComboBoxItem cItem = element as ComboBoxItem;
        if (cItem != null)
        {
            cItem.Tapped += OnItemTapped;
        }

        base.PrepareContainerForItemOverride(element, item);
    }

    protected override void OnKeyUp(KeyRoutedEventArgs e)
    {
        // if the user hits the Enter or Space to select an item, then consider this a "reselect" operation
        if ((e.Key == Windows.System.VirtualKey.Space || e.Key == Windows.System.VirtualKey.Enter) && !isSelectionChanged)
        {
            // handle re-select logic here
        }

        isSelectionChanged = false;

        base.OnKeyUp(e);
    }

    // track whether or not the ComboBox has received a SelectionChanged notification
    // in cases where it has not yet we get a Tapped or KeyUp notification we will want to consider that a "re-select"
    bool isSelectionChanged = false;
    private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        isSelectionChanged = true;
    }

    private void OnItemTapped(object sender, TappedRoutedEventArgs e)
    {
        if (!isSelectionChanged)
        {
            // indicates that an item was re-selected  - handle logic here
        }

        isSelectionChanged = false;
    }
}
        private  void ComboBox_Symbols_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.AddedItems.Count == 0) 
        return;
        //Some Other Codes
    }
private void OnDropDownClosed(object sender, EventArgs e)
{ 
     if (combobox.SelectedItem == null) return;
     // Do actions
}