Popup and Togglebutton interaction in wpf
Asked Answered
F

3

11

I have a control that contains a Togglebutton and a Popup. When the ToggleButton is clicked on, the popup appears. When the ToggleButton is unchecked, the popup should close. Additionally, clicking away from the popup should cause it to close, and cause the Togglebutton to uncheck.

I've set this up by setting the StaysOpen property of the Popup to false, and setting the IsChecked property of the toggle button to be two-way bound to the IsOpen property of the Popup.

All is well, apart from one case - with the button checked and the popup open, clicking the button does not cause the popup to close, or the button to return to unchecked.

I believe this must be because clicking the button causes the StaysOpen logic of the Popup to set the Popup's IsOpen property to false. In turn, this sets the Togglebutton to unchecked. This must happen before my click on the button is processed - so the click re-checks the button, ie a race condition.

Any idea how I can get the behaviour I want?

Filar answered 28/4, 2011 at 16:12 Comment(0)
S
10

If your assumption is correct, you'd need a custom Popup class like the following:

public class MyPopup : Popup {
    protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) {
        bool isOpen = this.IsOpen;
        base.OnPreviewMouseLeftButtonDown(e);

        if (isOpen && !this.IsOpen)
            e.Handled = true;
    }
}

You may need to remove the !this.IsOpen from the if-statement. If you use MyPopup instead, it will prevent the MouseLeftButtonDown event from reaching the ToggleButton.

Sanctify answered 28/4, 2011 at 16:20 Comment(1)
A problem with this approach is that if you click outside the popup, it doesn't actually click on anything. You don't want to click on the ToggleButton, but you want to click on everything elseHuntsman
B
8

Both the solutions above have issues. Here's another solution that uses event handlers instead of binding, but does avoid the lost click issue that svick pointed out with the MyPopup solution and the issues with ClickMode=Press. The xaml looks like:

<ToggleButton Name="OptionsButton" Checked="OptionsButton_OnChecked" Unchecked="OptionsButton_OnUnchecked" />
<Popup Name="OptionsPopup" StaysOpen="False" Closed="OptionsPopup_OnClosed"/>

And code :

    void OptionsPopup_OnClosed(object sender, EventArgs e)
    {
        if (OptionsButton != Mouse.DirectlyOver)
            OptionsButton.IsChecked = false;
    }

    void OptionsButton_OnChecked(object sender, RoutedEventArgs e)
    {
        OptionsPopup.IsOpen = true;
    }

    void OptionsButton_OnUnchecked(object sender, RoutedEventArgs e)
    {
        OptionsPopup.IsOpen = false;
    }
Beaston answered 5/11, 2013 at 14:26 Comment(1)
You can get rid of the OnChecked and OnUnchecked handlers by binding OptionsPopup.IsOpen to OptionsButton.IsChecked, a.la. <Popup x:Name="OptionsPopup" IsOpen="{Binding ElementName=OptionsButton, Path=IsChecked, Mode=OneWay}" />. Make sure you set Mode=OneWay.Pryor
P
1

The solution is to set a TwoWay binding between the IsOpen property of the Popup and the IsChecked property of the ToggleButton - THEN set the ClickMode property of the ToggleButton to Press. Voila !

Privilege answered 19/11, 2012 at 10:28 Comment(1)
doesn't work either..clicking outside popup does not close popupLatoria

© 2022 - 2024 — McMap. All rights reserved.