Dim
Dim

Reputation: 4807

WPF SelectionChanged to same value

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 fire no mater witch selection I do.

private void ComboBox_SelectionChanged4(object sender, SelectionChangedEventArgs e)
    {

      //do some stuff

    }

XAML:

<ComboBox   Height="30" Name="Combo4" Style="{StaticResource CategoryComboBox}"   SelectionChanged="ComboBox_SelectionChanged4" Grid.ColumnSpan="2"  Grid.Column="0">
            <ComboBoxItem Content="ComboBox Item 1 (Example)" />
            <ComboBoxItem Content="ComboBox Item 2 (Example)" />
            <ComboBoxItem Content="ComboBox Item 3 (Example)" />
            <ComboBoxItem Content="ComboBox Item 4 (Example)" />
        </ComboBox>

Adding items:

for (int i = 0; i < Pr4.Count(); i++)
        {
            ComboBoxItem item = new ComboBoxItem();
            item.Content = Pr4[i];
            Combo4.Items.Add(item);

        }

Upvotes: 6

Views: 5855

Answers (6)

deltonio2
deltonio2

Reputation: 1809

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

Upvotes: 4

aderesh
aderesh

Reputation: 957

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>

Upvotes: 3

Dim
Dim

Reputation: 4807

I used DropDownClosed, thank to - Clemens

Upvotes: 5

Rajeev Ranjan
Rajeev Ranjan

Reputation: 1036

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

Upvotes: 0

LateSLM
LateSLM

Reputation: 69

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

Upvotes: 0

David
David

Reputation: 863

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)

Upvotes: 1

Related Questions