WPF SelectionChanged to same value

前端 未结 6 2008
执念已碎
执念已碎 2021-01-05 22:46

I am using SelectionChanged in ComboBox item, but when I select the same item again the SelectionChanged function does not fire and I need it to do so. How can I tell it to

相关标签:
6条回答
  • 2021-01-05 22:58

    Behavior which uses DropDownOpen and DropDwonClose

    public class InvokeIfSameElementSelectedBehavior : Behavior<ComboBox>
        {
            #region public ICommand Command
    
            private static readonly PropertyMetadata CommandMetaData = new PropertyMetadata(default(ICommand));
    
            public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command",
                typeof(ICommand), typeof(InvokeIfSameElementSelectedBehavior), CommandMetaData);
    
            public ICommand Command
            {
                get { return (ICommand)GetValue(CommandProperty); }
                set { SetValue(CommandProperty, value); }
            }
    
            #endregion //public ICommand Command
    
            private bool _skipSelectionChanged;
            private bool _popupMouseClicked;
            private Popup _popup;
            private object _previousValue;
    
            protected override void OnAttached()
            {
                base.OnAttached();
    
                if(AssociatedObject.IsLoaded)
                    AttachAllEvents();
                else 
                    AssociatedObject.Loaded += AssociatedObjectOnLoaded;
            }
    
            private void AssociatedObjectOnLoaded(object sender, RoutedEventArgs routedEventArgs)
            {
                AssociatedObject.Loaded -= AssociatedObjectOnLoaded;
                AttachAllEvents();
            }
    
            protected override void OnDetaching()
            {
                base.OnDetaching();
                AssociatedObject.SelectionChanged -= AssociatedObjectOnSelectionChanged;
                AssociatedObject.DropDownOpened -= AssociatedObjectOnDropDownOpened;
                AssociatedObject.DropDownClosed -= AssociatedObjectOnDropDownClosed;
    
                if(_popup != null)
                    _popup.PreviewMouseLeftButtonDown -= PopupOnPreviewMouseLeftButtonDown;
            }
    
            private void AttachAllEvents()
            {
                AssociatedObject.SelectionChanged += AssociatedObjectOnSelectionChanged;
                AssociatedObject.DropDownOpened += AssociatedObjectOnDropDownOpened;
                AssociatedObject.DropDownClosed += AssociatedObjectOnDropDownClosed;
    
                AssociatedObject.ApplyTemplate();
                _popup = (Popup)AssociatedObject.Template.FindName("PART_Popup", AssociatedObject);
                if(_popup != null)
                    _popup.PreviewMouseLeftButtonDown += PopupOnPreviewMouseLeftButtonDown;
            }
    
            private void AssociatedObjectOnDropDownOpened(object sender, EventArgs e)
            {
                _popupMouseClicked = false;
                _previousValue = AssociatedObject.SelectedItem;
            }
    
            private void AssociatedObjectOnDropDownClosed(object sender, EventArgs e)
            {
                try
                {
                    if (_popupMouseClicked && Equals(AssociatedObject.SelectedItem, _previousValue)) //SelectionChanged handles it if value are not the same
                        InvokeChangeCommand(AssociatedObject.SelectedItem);
                }
                finally
                {
                    _popupMouseClicked = false;
                }
            }
    
            private void PopupOnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                //ignore clicks on the scrollbars
                if(e.Source is ScrollViewer)
                    return;
    
                _popupMouseClicked = true;
            }
    
            private void AssociatedObjectOnSelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (_skipSelectionChanged)
                    return;
    
                try
                {
                    _skipSelectionChanged = true;
    
                    if (e.AddedItems.Count != 1)
                        return;
                    InvokeChangeCommand(e.AddedItems[0]);
                }
                finally
                {
                    _skipSelectionChanged = false;
                }
            }
    
            private void InvokeChangeCommand(object item)
            {
                if (Command == null)
                    return;
    
                if (!Command.CanExecute(item))
                    return;
    
                Command.Execute(item);
            }
        }
    

    Sample:

    <ComboBox>
        <i:Interaction.Behaviors>
            <behaviors:InvokeIfSameElementSelectedBehavior Command="{Binding SelectionChangedCommand}"/>
        </i:Interaction.Behaviors>
    </ComboBox>
    
    0 讨论(0)
  • 2021-01-05 23:03

    I used DropDownClosed, thank to - Clemens

    0 讨论(0)
  • 2021-01-05 23:13

    You could use the dropdown opened even to set the selection to -1. Then in the event handler you need to ignore that change. On the dropdown closed event you can restore the original value if the control is closed.(Also ignore this change)

    0 讨论(0)
  • 2021-01-05 23:15

    TO do it you will have to add an event for mouse up for every item you added in combo box.

    0 讨论(0)
  • 2021-01-05 23:19

    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;
      }
    }
    
    0 讨论(0)
  • 2021-01-05 23:23

    You can bind the event handler to the onclickevent of the combobox then check if the selected item is null

    0 讨论(0)
提交回复
热议问题