Home > other >  Custom Popup control not closing
Custom Popup control not closing

Time:02-01

I'm trying to create a custom dropdown control that acts like a ComboBox, such that the Popup opens when you click mouse down (not up), and closes when you click outside of the control.

The problem is that it only behaves if I set ClickMode to "Release". But what I really want is ClickMode="Press", such that the Popup opens on MouseDown instead of MouseUp.

But when I set it to ClickMode="Press", the popup won't close when you click outside the control.

Any ideas how I can achieve this?

Usage :

          <StackPanel>
            <local:CustomDropdown Width="200"
                                  Height="50"
                                  Content="Custom!" />

            <ComboBox Width="200"
                      Margin="20"> 
                <ComboBoxItem>A</ComboBoxItem>
                <ComboBoxItem>B</ComboBoxItem>
                <ComboBoxItem>C</ComboBoxItem>
            </ComboBox>
        </StackPanel>

Class :

internal class CustomDropdown : ContentControl
{
    public bool IsOpen
    {
        get { return (bool)GetValue(IsOpenProperty); }
        set { SetValue(IsOpenProperty, value); }
    }

    public static readonly DependencyProperty IsOpenProperty =
        DependencyProperty.Register("IsOpen", typeof(bool), typeof(CustomDropdown), new PropertyMetadata(false));
}

Xaml :

<Style TargetType="{x:Type local:CustomDropdown}">
            <Style.Setters>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Grid>
                                <ToggleButton IsChecked="{Binding IsOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" 
                                              ClickMode="Press"/>
                                <ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"
                                                  HorizontalAlignment="Center"
                                                  VerticalAlignment="Center"/>
                                <Popup StaysOpen="False"
                                       Placement="Bottom"
                                       IsOpen="{Binding IsOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
                                    <Border Background="White"
                                            BorderBrush="Black"
                                            BorderThickness="1"
                                            Padding="50">
                                        <TextBlock Text="Popup!" />
                                    </Border>
                                </Popup>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style.Setters>
        </Style>

CodePudding user response:

If you want it to work as expected with ClickMode.Press, you should programmatically set the IsOpen property to false whenever you want to the close the Popup. For example whenever you detect a click outside of the ToggleButton.

You could for example handle the PreviewMouseLeftButtonDown event for the parent window in your control. Something like this:

internal class CustomDropdown : ContentControl
{
    private ToggleButton _toggleButton;

    public CustomDropdown()
    {
        Loaded  = onl oaded;
        Unloaded  = OnUnloaded;
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        _toggleButton = GetTemplateChild("toggleButton") as ToggleButton;
    }

    private void onl oaded(object sender, RoutedEventArgs e)
    {
        Window window = Window.GetWindow(this);
        window.PreviewMouseLeftButtonDown  = OnWindowPreviewMouseLeftButtonDown;
    }

    private void OnUnloaded(object sender, RoutedEventArgs e)
    {
        Window window = Window.GetWindow(this);
        window.PreviewMouseLeftButtonDown -= OnWindowPreviewMouseLeftButtonDown;
    }

    private void OnWindowPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        ToggleButton toggleButton = FindParent<ToggleButton>(e.OriginalSource as DependencyObject);
        if (toggleButton != _toggleButton)
            IsOpen = false;
    }

    private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
    {
        var parent = VisualTreeHelper.GetParent(dependencyObject);

        if (parent == null)
            return null;

        var parentT = parent as T;
        return parentT ?? FindParent<T>(parent);
    }

    public bool IsOpen
    {
        get { return (bool)GetValue(IsOpenProperty); }
        set { SetValue(IsOpenProperty, value); }
    }

    public static readonly DependencyProperty IsOpenProperty =
        DependencyProperty.Register("IsOpen", typeof(bool), typeof(CustomDropdown), new PropertyMetadata(false));
}

}

XAML:

<ControlTemplate>
    <Grid>
        <ToggleButton x:Name="toggleButton" ...
  • Related