Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dismiss a popup in Silverlight when clicking outside of the control?

In my Silverlight UI, I have a button that when clicked pops up a control with some filtering parameters. I would like this control to hide itself when you click outside of it. In other words, it should function in a manner similar to a combo box, but it's not a combo box (you don't select an item in it). Here's how I'm trying to capture a click outside of the control to dismiss it:

public partial class MyPanel : UserControl
{
    public MyPanel()
    {
        InitializeComponent();
    }

    private void FilterButton_Click(object sender, RoutedEventArgs e)
    {
        // Toggle the open state of the filter popup
        FilterPopup.IsOpen = !FilterPopup.IsOpen;
    }

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        // Capture all clicks and close the popup
        App.Current.RootVisual.MouseLeftButtonDown += delegate {
            FilterPopup.IsOpen = false; };
    }
}

Unfortunately, the event handler for MouseLeftButtonDown is never getting fired. Is there a well-established way of making a popup control that auto-dismisses when you click outside of it? If not, why isn't my MouseLeftButtonDown handler firing?

Solution:

I thought I'd post my entire solution in case others find it helpful. In my top-level visual, I declare a "shield" for the popups, like this:

<UserControl xmlns:my="clr-namespace:Namespace"
    x:Class="Namespace.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" 
    xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
>
  <Grid Background="Black" HorizontalAlignment="Stretch" 
          VerticalAlignment="Stretch">
    <my:MyStuff/>
    <Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
            x:Name="PopupShield" Background="Transparent" Width="Auto" 
            Height="Auto" Visibility="Collapsed"/>
  </Grid>
</UserControl>

Then, I added an extension method for the Popup class, like this:

public static class PopupUtils
{
    public static void MakeAutoDismissing(this Popup popup)
    {
        var shield = (App.Current.RootVisual as MainPage).PopupShield;

        // Whenever the popup opens, deploy the shield
        popup.HandlePropertyChanges(
            "IsOpen",
            (s, e) =>
            {
                shield.Visibility = (bool)e.NewValue 
                    ? Visibility.Visible : Visibility.Collapsed;
            }
        );

        // Whenever the shield is clicked, dismiss the popup
        shield.MouseLeftButtonDown += (s, e) => popup.IsOpen = false;
    }
}

public static class FrameworkUtils
{
    public static void HandlePropertyChanges(
        this FrameworkElement element, string propertyName, 
        PropertyChangedCallback callback)
    {
        //Bind to a depedency property
        Binding b = new Binding(propertyName) { Source = element };
        var prop = System.Windows.DependencyProperty.RegisterAttached(
            "ListenAttached" + propertyName,
            typeof(object),
            typeof(UserControl),
            new System.Windows.PropertyMetadata(callback));

        element.SetBinding(prop, b);
    }
}

The extension method is used like this:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    FilterPopup.MakeAutoDismissing();
}
like image 796
Jacob Avatar asked Feb 23 '10 22:02

Jacob


3 Answers

One way is to put your control on a transparent canvas that fills the entire Silverlight surface. When the canvas is clicked close the canvas and control. It is important to ensure that the Background brush of the canvas is set to "Transparent" if you want to receive mouse events.

An alternate method that I have not had success with is using mouse capture in Silverlight and detecting when the mouse is clicked outside of the popup.

like image 105
Doug Ferguson Avatar answered Oct 10 '22 18:10

Doug Ferguson


Did you set a background color on your RootVisual?

like image 32
Glenn Sandoval Avatar answered Oct 10 '22 17:10

Glenn Sandoval


I just created something similar and hopefully this could be of any help. :)

In my PopUp control, I have a Border which has a Grid that contains a number of textboxes. I named the Border 'PopUpBorder'.

In my UserControl's constructor, I have,

        this.PopUpBorder.MouseLeave += (s, e) =>
        {
            Application.Current.RootVisual.MouseLeftButtonDown += (s1, e1) =>
            {
                this.PopUp.IsOpen = false;
            };
        };

And looks like it is working as expected. Please let me know if this doesn't work in your case.

like image 3
Justin XL Avatar answered Oct 10 '22 18:10

Justin XL