A Better Popup Control for WPF

I never did like WPF’s built in Popup Control, so I decided to build my own. I wanted something that would

  • Not be on top of other windows when my application was minimized
  • Would have a semi-transparent background so you could see the application in the background but not interact with it
  • That could be placed within a panel on a form so that only part of the form is disabled.

So this is what I came up with my own UserControl to accomplish it. It can be used with the following bit of XAML

<local:PopupPanel Content="{Binding PopupContent}"
    local:PopupPanel.PopupParent="{Binding ElementName=CalendarPanel}"
    local:PopupPanel.IsPopupVisible="{Binding IsPopupVisible}"
    local:PopupPanel.BackgroundOpacity=".5"
    local:PopupPanel.PopupEnterKeyCommand="{Binding SaveCommand}"
    local:PopupPanel.PopupEscapeKeyCommand="{Binding CancelCommand}" />

It’s pretty straight forward. The PopupParent is the Panel you want to host the Popup in, the Content is what is stored in the Content of the panel, and the IsPopupVisible determines if the popup is up or not.

The Background Opacity, EnterKey, and EscapeKey are all optional. BackgroundOpacity determines how transparent the background should be, and Enter/Escape key commands determine what command to execute when the Enter/Escape key is pressed. By default, the Escape key will hide the popup, and the EnterKeyCommand will not fire if focus is in a TextBox with AllowsReturn=True

Sample Code

Here’s some sample code that uses the Popup Control. I used DataTemplates inside of <local:PopupPanel.Resources> to define how the PopupContent should look.

MainWindow.xaml

<Window x:Class="PopupPanelSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        x:Name="RootWindow"
        xmlns:local="clr-namespace:PopupPanelSample">

    <DockPanel>
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Background="LightSteelBlue">

            <TextBlock Text="Select Popup Content" VerticalAlignment="Center" Margin="5" />

            <ComboBox x:Name="PropertyComboBox" Margin="10" Width="150"
                      ItemsSource="{Binding PopupContentOptions}"
                      SelectedItem="{Binding PopupContent}" />

            <ToggleButton IsChecked="{Binding IsPopupVisible}" Content="Toggle Popup Visibility" VerticalAlignment="Center" />

        </StackPanel>

        <DockPanel DockPanel.Dock="Left" Width="50" Background="LightSteelBlue" />

        <Grid x:Name="InfoPanel">

            <!-- Sample for Background Example -->
                <Label Content="Background Sample" Height="150" Width="150"
                       HorizontalAlignment="Center" VerticalAlignment="Center"
                       Background="LightSteelBlue"/>

            <!-- Popup -->
            <local:PopupPanel local:PopupParent="{Binding ElementName=InfoPanel}"
                              local:PopupPanel.IsPopupVisible="{Binding IsPopupVisible}"
                              Content="{Binding PopupContent}">

                <local:PopupPanel.Resources>
                    <DataTemplate DataType="{x:Type local:Address}">
                        <Border BorderBrush="Red" BorderThickness="2" Background="White" Padding="20">
                            <Label Content="{Binding Name}" />
                        </Border>
                    </DataTemplate>
                    <DataTemplate DataType="{x:Type local:Phone}">
                        <Border BorderBrush="Blue" BorderThickness="2" Background="White" Padding="20">
                            <Label Content="{Binding Name}" />
                        </Border>
                    </DataTemplate>
                    <DataTemplate DataType="{x:Type local:Email}">
                        <Border BorderBrush="Green" BorderThickness="2" Background="White" Padding="20">
                            <Label Content="{Binding Name}" />
                        </Border>
                    </DataTemplate>
                </local:PopupPanel.Resources>

            </local:PopupPanel>

        </Grid>
    </DockPanel>
</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.ComponentModel;

namespace PopupPanelSample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.RootWindow.DataContext = new SampleViewModel();
        }
    }

    public class SampleViewModel : INotifyPropertyChanged
    {
        #region Fields

        private object _popupContent;
        private bool _isPopupVisible;
        private List<object> _popupContentOptions;

        #endregion

        public SampleViewModel()
        {
            PopupContentOptions = new List<object>
            {
                new Address(),
                new Phone(),
                new Email()
            };
        }

        #region Properties

        public object PopupContent
        {
            get { return _popupContent; }
            set
            {
                if (value != _popupContent)
                {
                    _popupContent = value;
                    OnPropertyChanged("PopupContent");
                }
            }
        }

        public List<object> PopupContentOptions
        {
            get { return _popupContentOptions; }
            set
            {
                if (value != _popupContentOptions)
                {
                    _popupContentOptions = value;
                    OnPropertyChanged("PopupContentOptions");
                }
            }
        }

        public bool IsPopupVisible
        {
            get { return _isPopupVisible; }
            set
            {
                if (value != _isPopupVisible)
                {
                    _isPopupVisible = value;
                    OnPropertyChanged("IsPopupVisible");
                }
            }
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        #endregion // INotifyPropertyChanged Members
    }

    public class Address
    {
        public string Name { get { return "An Address"; } }
        public override string ToString()
        {
            return Name;
        }
    }
    public class Phone
    {
        public string Name { get { return "A Phone"; } }
        public override string ToString()
        {
            return Name;
        }
    }
    public class Email
    {
        public string Name { get { return "An Email"; } }
        public override string ToString()
        {
            return Name;
        }
    }
}

The end result looks like this

Popup Collapsed

Popup Collapsed

Popup Visible

Popup Visible

You can style your Popups to look however you want. I’ve done ones with Title Bars and Ok/Close buttons, and I’ve done non-square shaped popups with the Close button in a round X button at the top right. In this case, I’ve simply displayed the popups as a Border and Label with the Popup Content.

Here’s the actual Popup Panel code

PopupPanel.xaml

<UserControl x:Class="PopupPanelSample.PopupPanel"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:PopupPanelSample"
             FocusManager.IsFocusScope="True"
             >

    <UserControl.Template>
        <ControlTemplate TargetType="{x:Type local:PopupPanel}">
            <ControlTemplate.Resources>
                <!-- Converter to get Popup Positioning -->
                <local:ValueDividedByParameterConverter x:Key="ValueDividedByParameterConverter" />

                <!-- Popup Visibility -->
                <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
                <Style x:Key="PopupPanelContentStyle" TargetType="{x:Type Grid}">
                    <Setter Property="Grid.Visibility" Value="{Binding Path=IsPopupVisible,
                        RelativeSource={RelativeSource AncestorType={x:Type local:PopupPanel}},
                        Converter={StaticResource BooleanToVisibilityConverter}}"/>
                </Style>
            </ControlTemplate.Resources>

            <Grid x:Name="PopupPanelContent" Style="{StaticResource PopupPanelContentStyle}">
                <Grid.Resources>
                    <!-- Storyboard to show Content -->
                    <Storyboard x:Key="ShowEditPanelStoryboard" SpeedRatio="5">
                        <DoubleAnimation
                            Storyboard.TargetName="PopupPanelContent"
                            Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleX)"
                            From="0.00" To="1.00" Duration="00:00:01"
                            />
                        <DoubleAnimation
                            Storyboard.TargetName="PopupPanelContent"
                            Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleY)"
                            From="0.00" To="1.00" Duration="00:00:01"
                            />
                    </Storyboard>
                </Grid.Resources>

                <!-- Setting up RenderTransform for Popup Animation -->
                <Grid.RenderTransform>
                    <ScaleTransform
                        CenterX="{Binding Path=PopupParent.ActualWidth, Converter={StaticResource ValueDividedByParameterConverter}, ConverterParameter=2, RelativeSource={RelativeSource AncestorType={x:Type local:PopupPanel}}}"
                        CenterY="{Binding Path=PopupParent.ActualHeight, Converter={StaticResource ValueDividedByParameterConverter}, ConverterParameter=2, RelativeSource={RelativeSource AncestorType={x:Type local:PopupPanel}}}"
                        />
                </Grid.RenderTransform>

                <!-- Grayscale background & prevents mouse input -->
                <Rectangle
                    Fill="Gray"
                    Opacity="{Binding Path=BackgroundOpacity, RelativeSource={RelativeSource AncestorType={x:Type local:PopupPanel}}}"
                    Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:PopupPanel}}, Path=Height}"
                    Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:PopupPanel}}, Path=Width}"
                    />

                <!-- Popup Content -->
                <ContentControl x:Name="PopupContentControl"
                                KeyboardNavigation.TabNavigation="Cycle"
                                PreviewKeyDown="PopupPanel_PreviewKeyDown"
                                PreviewLostKeyboardFocus="PopupPanel_LostFocus"
                                IsVisibleChanged="PopupPanel_IsVisibleChanged"
                                HorizontalAlignment="Center" VerticalAlignment="Center"
                                >
                    <ContentPresenter Content="{TemplateBinding Content}" />
                </ContentControl>
            </Grid>
        </ControlTemplate>
    </UserControl.Template>
</UserControl>

PopupPanel.xaml.cs

using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;

namespace PopupPanelSample
{
    /// <summary>
    /// Panel for handling Popups:
    /// - Control with name PART_DefaultFocusControl will have default focus
    /// - Can define PopupParent to determine if this popup should be hosted in a parent panel or not
    /// - Can define the property EnterKeyCommand to specifify what command to run when the Enter key is pressed
    /// - Can define the property EscapeKeyCommand to specify what command to run when the Escape key is pressed
    /// - Can define BackgroundOpacity to specify how opaque the background will be. Value is between 0 and 1.
    /// </summary>
    public partial class PopupPanel : UserControl
    {
        #region Fields

        bool _isLoading = false;                    // Flag to tell identify when DataContext changes
        private UIElement _lastFocusControl;        // Last control that had focus when popup visibility changes, but isn't closed

        #endregion // Fields

        #region Constructors

        public PopupPanel()
        {
            InitializeComponent();
            this.DataContextChanged += Popup_DataContextChanged;

            // Register a PropertyChanged event on IsPopupVisible
            DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(PopupPanel.IsPopupVisibleProperty, typeof(PopupPanel));
            if (dpd != null) dpd.AddValueChanged(this, delegate { IsPopupVisible_Changed(); });

            dpd = DependencyPropertyDescriptor.FromProperty(PopupPanel.ContentProperty, typeof(PopupPanel));
            if (dpd != null) dpd.AddValueChanged(this, delegate { Content_Changed(); });

        }

        #endregion // Constructors

        #region Events

        #region Property Change Events

        // When DataContext changes
        private void Popup_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            DisableAnimationWhileLoading();
        }

        // When Content Property changes
        private void Content_Changed()
        {
            DisableAnimationWhileLoading();
        }

        // Sets an IsLoading flag so storyboard doesn't run while loading
        private void DisableAnimationWhileLoading()
        {
            _isLoading = true;
            this.Dispatcher.BeginInvoke(DispatcherPriority.Render,
                new Action(delegate() { _isLoading = false; }));
        }

        // Run storyboard when IsPopupVisible property changes to true
        private void IsPopupVisible_Changed()
        {
            bool isShown = GetIsPopupVisible(this);

            if (isShown && !_isLoading)
            {
                FrameworkElement panel = FindChild<FrameworkElement>(this, "PopupPanelContent");
                if (panel != null)
                {
                    // Run Storyboard
                    Storyboard animation = (Storyboard)panel.FindResource("ShowEditPanelStoryboard");
                    animation.Begin();
                }
            }

            // When hiding popup, clear the LastFocusControl
            if (!isShown)
            {
                _lastFocusControl = null;
            }
        }

        #endregion // Change Events

        #region Popup Events

        // When visibility is changed, set the default focus
        void PopupPanel_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue)
            {
                ContentControl popupControl = FindChild<ContentControl>(this, "PopupContentControl");
                this.Dispatcher.BeginInvoke(DispatcherPriority.Render,
                    new Action(delegate()
                    {
                        // Verify object really is visible because sometimes it's not once we switch to Render
                        if (!GetIsPopupVisible(this))
                        {
                            return;
                        }

                        if (_lastFocusControl != null && _lastFocusControl.Focusable)
                        {
                            _lastFocusControl.Focus();
                        }
                        else
                        {
                            _lastFocusControl = FindChild<UIElement>(popupControl, "PART_DefaultFocusControl") as UIElement;

                            // If we can find the part named PART_DefaultFocusControl, set focus to it
                            if (_lastFocusControl != null && _lastFocusControl.Focusable)
                            {
                                _lastFocusControl.Focus();
                            }
                            else
                            {
                                _lastFocusControl = FindFirstFocusableChild(popupControl);

                                // If no DefaultFocusControl found, try and set focus to the first focusable element found in popup
                                if (_lastFocusControl != null)
                                {
                                    _lastFocusControl.Focus();
                                }
                                else
                                {
                                    // Just give the Popup UserControl focus so it can handle keyboard input
                                    popupControl.Focus();
                                }
                            }
                        }
                    }
                    )
                );
            }
        }

        // When popup loses focus but isn't hidden, store the last element that had focus so we can put it back later
        void PopupPanel_LostFocus(object sender, RoutedEventArgs e)
        {
            DependencyObject focusScope = FocusManager.GetFocusScope(this);
            _lastFocusControl = FocusManager.GetFocusedElement(focusScope) as UIElement;
        }

        // Keyboard Events
        private void PopupPanel_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                PopupPanel popup = FindAncester<PopupPanel>((DependencyObject)sender);
                ICommand cmd = GetPopupEscapeKeyCommand(popup);
                if (cmd != null && cmd.CanExecute(null))
                {
                    cmd.Execute(null);
                    e.Handled = true;
                }
                else
                {
                    // By default the Escape Key closes the popup when pressed
                    var expression = this.GetBindingExpression(PopupPanel.IsPopupVisibleProperty);
                    var dataType = expression.DataItem.GetType();
                    dataType.GetProperties().Single(x => x.Name == expression.ParentBinding.Path.Path)
                        .SetValue(expression.DataItem, false, null);
                }
            }
            else if (e.Key == Key.Enter)
            {
                // Don't want to run Enter command if focus is in a TextBox with AcceptsReturn = True
                if (!(e.KeyboardDevice.FocusedElement is TextBox &&
                     (e.KeyboardDevice.FocusedElement as TextBox).AcceptsReturn == true))
                {
                    PopupPanel popup = FindAncester<PopupPanel>((DependencyObject)sender);
                    ICommand cmd = GetPopupEnterKeyCommand(popup);
                    if (cmd != null && cmd.CanExecute(null))
                    {
                        cmd.Execute(null);
                        e.Handled = true;
                    }
                }

            }
        }

        #endregion // Popup Events

        #endregion // Events

        #region Dependency Properties

        // Parent for Popup
        #region PopupParent

        public static readonly DependencyProperty PopupParentProperty =
            DependencyProperty.Register("PopupParent", typeof(FrameworkElement),
            typeof(PopupPanel), new PropertyMetadata(null, null, CoercePopupParent));

        private static object CoercePopupParent(DependencyObject obj, object value)
        {
            // If PopupParent is null, return the Window object
            return (value ?? FindAncester<Window>(obj));
        }

        public FrameworkElement PopupParent
        {
            get { return (FrameworkElement)this.GetValue(PopupParentProperty); }
            set { this.SetValue(PopupParentProperty, value); }
        }

        // Providing Get/Set methods makes them show up in the XAML designer
        public static FrameworkElement GetPopupParent(DependencyObject obj)
        {
            return (FrameworkElement)obj.GetValue(PopupParentProperty);
        }

        public static void SetPopupParent(DependencyObject obj, FrameworkElement value)
        {
            obj.SetValue(PopupParentProperty, value);
        }

        #endregion

        // Popup Visibility - If popup is shown or not
        #region IsPopupVisibleProperty

        public static readonly DependencyProperty IsPopupVisibleProperty =
            DependencyProperty.Register("IsPopupVisible", typeof(bool),
            typeof(PopupPanel), new PropertyMetadata(false, null));

        public static bool GetIsPopupVisible(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsPopupVisibleProperty);
        }

        public static void SetIsPopupVisible(DependencyObject obj, bool value)
        {
            obj.SetValue(IsPopupVisibleProperty, value);
        }

        #endregion // IsPopupVisibleProperty

        // Transparency level for the background filler outside the popup
        #region BackgroundOpacityProperty

        public static readonly DependencyProperty BackgroundOpacityProperty =
            DependencyProperty.Register("BackgroundOpacity", typeof(double),
            typeof(PopupPanel), new PropertyMetadata(.5, null));

        public static double GetBackgroundOpacity(DependencyObject obj)
        {
            return (double)obj.GetValue(BackgroundOpacityProperty);
        }

        public static void SetBackgroundOpacity(DependencyObject obj, double value)
        {
            obj.SetValue(BackgroundOpacityProperty, value);
        }

        #endregion ShowBackgroundProperty

        // Command to execute when Enter key is pressed
        #region PopupEnterKeyCommandProperty

        public static readonly DependencyProperty PopupEnterKeyCommandProperty =
            DependencyProperty.RegisterAttached("PopupEnterKeyCommand", typeof(ICommand),
            typeof(PopupPanel), new PropertyMetadata(null, null));

        public static ICommand GetPopupEnterKeyCommand(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(PopupEnterKeyCommandProperty);
        }

        public static void SetPopupEnterKeyCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(PopupEnterKeyCommandProperty, value);
        }

        #endregion PopupEnterKeyCommandProperty

        // Command to execute when Enter key is pressed
        #region PopupEscapeKeyCommandProperty

        public static readonly DependencyProperty PopupEscapeKeyCommandProperty =
            DependencyProperty.RegisterAttached("PopupEscapeKeyCommand", typeof(ICommand),
            typeof(PopupPanel), new PropertyMetadata(null, null));

        public static ICommand GetPopupEscapeKeyCommand(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(PopupEscapeKeyCommandProperty);
        }

        public static void SetPopupEscapeKeyCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(PopupEscapeKeyCommandProperty, value);
        }

        #endregion PopupEscapeKeyCommandProperty

        #endregion Dependency Properties

        #region Visual Tree Helpers

        public static UIElement FindFirstFocusableChild(DependencyObject parent)
        {
            // Confirm parent is valid.
            if (parent == null) return null;

            UIElement foundChild = null;

            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < childrenCount; i++)
            {
                UIElement child = VisualTreeHelper.GetChild(parent, i) as UIElement;

                // This is returning me things like ContentControls, so for now filtering to buttons/textboxes only
                if (child != null && child.Focusable && child.IsVisible)
                {
                    foundChild = child;
                    break;
                }
                // recursively drill down the tree
                foundChild = FindFirstFocusableChild(child);

                // If the child is found, break so we do not overwrite the found child.
                if (foundChild != null) break;
            }
            return foundChild;
        }

        public static T FindAncester<T>(DependencyObject current)
        where T : DependencyObject
        {
            // Need this call to avoid returning current object if it is the same type as parent we are looking for
            current = VisualTreeHelper.GetParent(current);

            while (current != null)
            {
                if (current is T)
                {
                    return (T)current;
                }
                current = VisualTreeHelper.GetParent(current);
            };
            return null;
        }

        /// <summary>
        /// Looks for a child control within a parent by name
        /// </summary>
        public static T FindChild<T>(DependencyObject parent, string childName)
        where T : DependencyObject
        {
            // Confirm parent and childName are valid.
            if (parent == null) return null;

            T foundChild = null;

            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i);
                // If the child is not of the request child type child
                T childType = child as T;
                if (childType == null)
                {
                    // recursively drill down the tree
                    foundChild = FindChild<T>(child, childName);

                    // If the child is found, break so we do not overwrite the found child.
                    if (foundChild != null) break;
                }
                else if (!string.IsNullOrEmpty(childName))
                {
                    var frameworkElement = child as FrameworkElement;
                    // If the child's name is set for search
                    if (frameworkElement != null && frameworkElement.Name == childName)
                    {
                        // if the child's name is of the request name
                        foundChild = (T)child;
                        break;
                    }
                    else
                    {
                        // recursively drill down the tree
                        foundChild = FindChild<T>(child, childName);

                        // If the child is found, break so we do not overwrite the found child.
                        if (foundChild != null) break;
                    }
                }
                else
                {
                    // child element found.
                    foundChild = (T)child;
                    break;
                }
            }

            return foundChild;
        }

        #endregion

    }

    // Converter for Popup positioning
    public class ValueDividedByParameterConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            double n, d;
            if (double.TryParse(value.ToString(), out n)
                && double.TryParse(parameter.ToString(), out d)
                && d != 0)
            {
                return n / d;
            }

            return 0;
        }        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

Code for the Popup and the Sample can be found here

12 Responses to A Better Popup Control for WPF

  1. Hi Rachel
    I really like this as a mechanism for displaying simple data. I’m trying to extend it a little by incorporating a validated textbox entry field. Unfortunately I can’t name any elements within the popup, and so can’t specify what to validate! I’m coming up against the dreaded ‘X is under the scope of element Y, which already had a name registered…’ error. Do you have any thoughts on a workaround?

    • Rachel says:

      I forgot about that… I usually avoid named elements though if I can. The one time I needed to have a named element in the Popup content, I set the name property in the Loaded event of the object. It’s may not be pretty, but it worked.

      <TextBox Loaded="MyTextBox_Loaded" ... />

      void MyTextBox_Loaded(object sender, EventArgs e)
      {
      ((TextBox)sender).Name = "MyTextBox";
      }

  2. Speedy reply much appreciated! I’m making heavy use of IDataErrorInfo for validation, so named elements are unfortunately a requirement. I’ll do some more forceful prodding and see what I come up with. Many thanks!

  3. Willem says:

    Hi Rachel,

    Nice post. Thanks.

    I am trying to use this in my XBAP application, but it seems not to work. I added a IsPopupVisible property so i can set it in code. I want to use your PopupPanel to show a loading image.

    PopupPanel popupPanel = new PopupPanel();
    popupPanel.PopupParent = this;//This is a UserControl
    popupPanel.IsPopupVisible = true;

    Now in IsPopupVisible_Changed() on FrameworkElement panel = FindChild(this, “PopupPanelContent”);, panel is null.

    I can’t seem to work this out. What am i doing wrong?

    • Rachel says:

      Hi Willem,

      The PopupPanel works more like a UserControl than a Dialog box. You have to add it to your UI somewhere before it will show up

      <local:MyUserControl x:Name="MyUserControl">
          <local:PopupPanel x:Name="MyPopupPanel" local:PopupParent="{Binding ElementName=MyUserControl}" />
      </local:MyUserControl>

      Then you can set its visibility through a binding or in the code behind:

      MyPopupPanel.IsPopupVisible = true;

  4. j. says:

    Code for the Popup and the Sample can be found here
    is a link to download MediaFire:

    Does everything have to be a commercial?

  5. Hi Rachel,

    Great post. I use a very similar mechanism for displaying error messages. Our application consists of multiple windows, therefore I have to include PopupPanel view in every window that will require this functionality.

  6. gayotfow says:

    Rachel, your download link leads to a site requiring an exe download before it will work. The exe file flags up in AVG as a malware threat! Can you please port it to Git?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 100 other followers

%d bloggers like this: