WPF Checkbox Combobox direct click button after selection

0

I have some comboxboxes which I populate with checkboxes. After selecting the items click on search, however the first click is used to compress the combo and then I click again to activate the button.

Is there any way to avoid having to give 2 clicks to trigger a button after opening a combobox? Make the first click compress the combo and hit the button.

As it is: I click the combobox, select the items, click outside the combo box, click the button. (same click on the button, the first click is always to compress the combo).

How would it be: I click on the combobox, select the items, click the button.

<ComboBox 
    Grid.Column="3" 
    Grid.Row="1"
    x:Name="cmbGrupo" 
    IsEditable="True"
    IsReadOnly="False"                     
    Width="120" 
    SelectedIndex="0" 
    >
    <ComboBox.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="DarkGray"/>
    </ComboBox.Resources>

    <ComboBox.ItemTemplate>
        <DataTemplate>
            <CheckBox 
                x:Name="chkGrupo" 
                Content="{Binding Content}" 
                IsChecked="{Binding IsChecked}" 
                IsEnabled="{Binding IsEnabled}" 
                Checked="chk_Changed" 
                Unchecked="chk_Changed"
                />

        </DataTemplate>
    </ComboBox.ItemTemplate>
    <ComboBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel/>
        </ItemsPanelTemplate>
    </ComboBox.ItemsPanel>
</ComboBox>

<Button 
    x:Name="btnPesquisar" 
    Content="Pesquisar" 
    Grid.Column="17"
    Grid.Row="1"
    Width="130" 
    Click="btnPesquisar_Click"
    />
    
asked by anonymous 28.12.2016 / 13:34

1 answer

1

First, what happens is that the ComboBox has been implemented so that when the DropDown is open it captures the mouse. This is native to the ComboBox and means that:

Capture and Uncapture the Mouse :

  

When an object captures the mouse, all mouse related events are handled as if the object with the mouse capture executes the event, even if the mouse pointer is over another object.

So that's the reason for your problem.

Now about:

  

Is there any way to avoid having to give 2 clicks to trigger a button after opening a combobox? Make the first click compress the combo and hit the button.

As far as I know, there are two ways and several variations of them. I'll put both ways.

First method:

   private void Win_Loaded(object sender, RoutedEventArgs e)
    {
        cmbGrupo.ItemsSource = typeof(Colors).GetProperties();
        Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(cmbGrupo, OutsideControlClick);
    }

    public void OutsideControlClick(object sender, MouseButtonEventArgs e)
    {
        cmbGrupo.ReleaseMouseCapture();
    }
  • When loading the window it will add the event "AddPreviewMouseDownOutsideCaptured" to your ComboBox. This means that an event is running when some mouse button is pressed outside the element that is capturing mouse events ( reference ).
  • The event is only activated when you click inside Window . The "Close" and "Minimize" buttons of Window will not activate the event.

Second Method:

private void ComboBox_DropDownClosed(object sender, EventArgs e)
    {
        Point m = Mouse.GetPosition(this);
        VisualTreeHelper.HitTest(this, this.FilterCallback, this.ResultCallback, new PointHitTestParameters(m));
    }

    private HitTestFilterBehavior FilterCallback(DependencyObject obj)
    {
        Control control = obj as Control;
        if(control == null) return HitTestFilterBehavior.Continue;
        if(control is Window) return HitTestFilterBehavior.Continue;
        if(control is ComboBox) return HitTestFilterBehavior.Stop; 

        if (control.Focusable)
        {
            MouseDevice mouseDevice = Mouse.PrimaryDevice;
            MouseButtonEventArgs mouseButtonEventArgs = new MouseButtonEventArgs(mouseDevice, 0, MouseButton.Left)
            {
                RoutedEvent = Mouse.MouseDownEvent,
                Source = control
            };
            control.RaiseEvent(mouseButtonEventArgs);
            return HitTestFilterBehavior.Stop;
        }
        return HitTestFilterBehavior.Continue;
    }

    private HitTestResultBehavior ResultCallback(HitTestResult r)
    {
        return HitTestResultBehavior.Continue;
    }
  • Closing the DropDonw will focus on the control where the pointer is positioned before performing another action with the mouse.

In your case I would put some of these methods in a DepedencyProperty for reuse. If you do this, share it with us; D

I hope I have helped. Hugs

    
18.01.2017 / 14:49