it-swarm.com.de

Welcher Event-Handler für das ausgewählte ComboBox-Element verwendet werden soll (das ausgewählte Element wurde nicht notwendigerweise geändert)

Ziel: ein Ereignis ausgeben, wenn Elemente in einer Auswahlliste ausgewählt werden.

Problem: Wenn Sie "SelectionChanged" verwenden, wählt der Benutzer jedoch das gleiche Element wie das Element, das gerade ausgewählt wird. Die Auswahl wird jedoch nicht geändert, und dieses Ereignis wird daher nicht ausgelöst.

Frage: Welche anderen Event-Handler (oder andere Möglichkeiten) kann ich zur Ausgabe eines Ereignisses verwenden, unabhängig davon, ob das ausgewählte Element geändert wurde oder nicht, solange der Mausklick auf dieses Element ausgeführt wird und dieses Element ausgewählt wird.

(Erläuterung: Das Problem besteht darin, "etwas" auszulösen, wenn derselbe Artikel erneut ausgewählt wird. Keine Duplikate in der Dropdown-Liste. Szenario: Wählen Sie zum ersten Mal Element 1 aus, schließen Sie das Dropdown-Menü.) Punkt 1, wenn eine Funktion ausgelöst wird.)

Lösung : Derzeit scheint es keine direkte Lösung dafür zu geben. Je nach Projekt kann es jedoch Umgehungsmöglichkeiten geben. (Bitte aktualisieren Sie, wenn es wirklich gute Möglichkeiten gibt, dies zu tun). Vielen Dank.

31
grc

Ich hatte die gleiche Frage und fand schließlich die Antwort:

Sie müssen BEIDE das SelectionChanged-Ereignis und DropDownClosed wie folgt behandeln:

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

Sie können das Ereignis "ComboBoxItem.PreviewMouseDown" verwenden. Jedes Mal, wenn die Maus bei einem Gegenstand gedrückt wird, wird dieses Ereignis ausgelöst.

Um dieses Ereignis in XAML hinzuzufügen, verwenden Sie "ComboBox.ItemContainerStyle" wie im nächsten Beispiel:

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

und handhaben wie gewohnt

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

Dank an MSDN

6
Vadim Levkovsky

Für mich ComboBox.DropDownClosed Event hat es geschafft.

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

Ich hoffe, dass Sie den folgenden Trick hilfreich finden werden.

Sie können beide Ereignisse binden

combobox.SelectionChanged += OnSelectionChanged;
combobox.DropDownOpened += OnDropDownOpened;

Und erzwingen Sie, dass das ausgewählte Element in OnDropDownOpened auf null gesetzt wird

private void OnDropDownOpened(object sender, EventArgs e)
{
    combobox.SelectedItem = null;
}

Und machen Sie, was Sie mit dem Element innerhalb von OnSelectionChanged benötigen .. __ Die OnSelectionChanged wird jedes Mal ausgelöst, wenn Sie die Combobox öffnen. Sie können jedoch überprüfen, ob SelectedItem in der Methode null ist, und den Befehl überspringen

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

Für UWP-Apps (Windows Store) funktioniert keine der oben genannten Funktionen (PointerPressed wird nicht ausgelöst; es sind keine Ereignisse in der Vorschau, DropDownClosed oder SelectedIndexChanged vorhanden.)

Ich musste auf einen transparenten Button zurückgreifen, der die ComboBox überlagerte (aber nicht den Dropdown-Pfeil). Wenn Sie auf den Pfeil drücken, wird die Liste wie üblich heruntergesetzt und das SelectionChanged-Ereignis der Combo Box wird ausgelöst. Wenn Sie irgendwo auf die Combo-Box klicken, wird das Click-Event der transparenten Schaltfläche ausgelöst, sodass Sie den aktuellen Wert der Combo-Box erneut auswählen können.

Einige funktionierende XAML-Codes:

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

Einige funktionierende C # -Codes:

    /// <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);
    }
2
Robert

Sie können "SelectedIndexChanged" versuchen. Das Ereignis wird auch dann ausgelöst, wenn dasselbe Element ausgewählt wird.

1
Vas Vasanth

Verwenden Sie SelectionChangeCommitted(object sender, EventArgs e) event hier

0
Zack

Dies ist ein DependencyObject zum Anhängen an eine ComboBox.

Es zeichnet das aktuell ausgewählte Element auf, wenn die Dropdown-Liste geöffnet ist, und löst das SelectionChanged-Ereignis aus, wenn derselbe Index beim Schließen der Dropdown-Liste noch ausgewählt ist. Es muss möglicherweise geändert werden, damit es mit der Tastaturauswahl funktioniert.

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

und fügen Sie Ihr Namespace-Präfix hinzu, um es zugänglich zu machen.

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

und dann müssen Sie es so anbringen

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

Jede ComboBoxItem-Instanz hat ein PreviewMouseDown-Ereignis. Wenn Sie Ihren benutzerdefinierten Handler für dieses Ereignis bei jedem ComboBoxItem abonnieren, haben Sie die Möglichkeit, jeden Klick in der Dropdownliste zu bearbeiten.

// 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...         
}

Dieses Problem nervt mich schon lange, da bei mir keine Abhilfe geleistet hat :(

Aber eine gute Nachricht ist, dass die folgende Methode für meine Anwendung gut funktioniert.

Die Grundidee ist, ein EventManager in App.xmal.cs Zu registrieren, um PreviewMouseLeftButtonDownEvent für alle ComboBoxItem zu schnüffeln, und dann SelectionChangedEvent auszulösen, wenn das ausgewählte Element ist dasselbe wie das ausgewählte Element, dh die Auswahl wird ohne Änderung des Index durchgeführt.

In 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()));
        }
    }
}

Registrieren Sie dann für alle Kombinationsfelder SelectionChangedEvent auf normale Weise:

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

Wenn nun zwei Indizes unterschiedlich sind, gibt es nichts Besonderes als den normalen Prozess zur Ereignisbehandlung. Wenn zwei Indizes gleich sind, wird zuerst das Mausereignis auf dem Element behandelt und damit das SelectionChangedEvent ausgelöst. Auf diese Weise lösen beide Situationen SelectionChangedEvent :) aus.

0
nevets

Für UWP habe ich einen anderen Ansatz gewählt. Ich erweiterte die ComboBox-Klasse und verarbeitete die SelectionChanged- und OnKeyUp-Ereignisse in der ComboBox sowie das Tapped-Ereignis in den ComboBoxItems. Wenn ich ein Tapped-Event oder einen Enter- oder Space-Key bekomme, ohne zuvor einen SelectionChanged zu erhalten, weiß ich, dass das aktuelle Element erneut ausgewählt wurde und ich dementsprechend antworte.

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;
    }
}
0
Rich S