53

目標:コンボボックスのドロップダウン リストの項目が選択されたときにイベントを発行します。

問題:ただし、"SelectionChanged" を使用すると、ユーザーが現在選択されているアイテムと同じアイテムを選択した場合、選択は変更されないため、このイベントはトリガーされません。

質問:選択したアイテムが変更されているかどうかに関係なく、イベントを発行するために使用できる他のイベント ハンドラー (または他の方法) は、マウスがそのアイテムをクリックし、そのアイテムが選択されている限りではありません。

(明確化: 問題は、同じアイテムが再度選択されたときに「何か」をトリガーする方法です。ドロップダウン リストに重複はありません。シナリオ: 最初にアイテム 1 を選択し、ドロップダウンを閉じます。次に、ドロップダウン ボックスを開いて選択します。何らかの機能がトリガーされた場合の項目 1)。

解決策: 今のところ、これを行う簡単な解決策はないようです。しかし、個々のプロジェクトに応じて、それを回避する方法があります。(実際にこれを行う良い方法がある場合は更新してください)。ありがとう。

4

13 に答える 13

33

同じ質問があり、最終的に答えを見つけました:

次のように、SelectionChanged イベントと DropDownClosed の両方を処理する必要があります。

XAML の場合:

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

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;
  }
}
于 2014-10-31T13:10:06.257 に答える
14

私にとってComboBox.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;
        }
    }
于 2015-06-16T08:53:13.703 に答える
10

「ComboBoxItem.PreviewMouseDown」イベントを使用できます。したがって、マウスがアイテムの上に置かれるたびに、このイベントが発生します。

このイベントを 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>

通常どおりに処理します

void cmbItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    //...do your item selection code here...
}

MSDNに感謝

于 2014-08-15T12:46:50.333 に答える
3

UWP (Windows ストア) アプリの場合、上記のどれも機能しません (PointerPressed は起動しません。Preview、DropDownClosed、または SelectedIndexChanged イベントは存在しません)。

ComboBox をオーバーレイする透明なボタンに頼る必要がありました (ドロップダウン矢印ではありません)。矢印を押すと、通常どおりリストがドロップダウンし、コンボ ボックスの 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# コード:

    /// <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);
    }
于 2016-08-12T20:39:07.410 に答える
1

" " を試すことができますSelectedIndexChanged。同じアイテムが選択されていても、イベントがトリガーされます。

于 2013-06-06T15:41:49.650 に答える
0

回避策がどれもうまくいかなかったので、この問題は長い間私を悩ませていました:(

しかし、良いニュースは、次の方法が私のアプリケーションでうまく機能することです。

基本的な考え方は、EventManagerinを登録してすべてApp.xmal.csを sniffし、選択した項目が選択した項目と同じ場合にトリガーすることです。つまり、選択は index を変更せずに実行されますPreviewMouseLeftButtonDownEventComboBoxItemSelectionChangedEvent

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

ここで、2 つのインデックスが異なる場合、特別なことは何もなく、通常のイベント処理プロセスです。2 つのインデックスが同じ場合、アイテムのマウス イベントが最初に処理され、SelectionChangedEvent. このようにして、両方の状況がトリガーされSelectionChangedEventます:)

于 2014-11-14T23:07:29.183 に答える
0

これは、ComboBox にアタッチするための 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" />
于 2015-04-15T13:24:26.307 に答える