Running on Empty

The few things I know, I like to share.

WPF Popup control. (Part 2, User controls as Popups)

Introduction

In Part 1 of this series I outlined a way of creating a Popup control using WPF.  In this article I will demonstrate creating a Popup using Dependency Properties, not quite so quick, but much more elegant.  The main benefit of creating user controls is reusability.

Creating a Popup User Control.

public class PopupTest : System.Windows.Controls.Control
{
    Popup _parentPopup;
    /// <summary>
    /// Constructor
    /// </summary>
    public PopupTest()
        : base()
    {
    }
 
    static PopupTest()
    {
        //This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
        //This style is defined in themes\generic.xaml
        DefaultStyleKeyProperty.OverrideMetadata(typeof(PopupTest), new FrameworkPropertyMetadata(typeof(PopupTest)));
    }
}

This is pretty much the template class for a user control with one small addition, the property Popup.  Note the visual style for the control will appear in Generic.xaml.

Adding Dependency Properties to add Popup Functionality.

Basically you have a shell for a User Control at this point.  All you need to add are some dependency properties to add Popup functionality to the control.

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

public bool StaysOpen
{
    get { return (bool)GetValue(StaysOpenProperty); }
    set { SetValue(StaysOpenProperty, value); }
}
#endregion
#region DependencyProperties
//Placement
public static readonly DependencyProperty PlacementProperty =
            Popup.PlacementProperty.AddOwner(typeof(PopupTest));
public PlacementMode Placement
{
    get { return (PlacementMode)GetValue(PlacementProperty); }
    set { SetValue(PlacementProperty, value); }
}
//PlacementTarget
public static readonly DependencyProperty PlacementTargetProperty =
            Popup.PlacementTargetProperty.AddOwner(typeof(PopupTest));
public UIElement PlacementTarget
{
    get { return (UIElement)GetValue(PlacementTargetProperty); }
    set { SetValue(PlacementTargetProperty, value); }
}
//PlacementRectangle
public static readonly DependencyProperty PlacementRectangleProperty =
            Popup.PlacementRectangleProperty.AddOwner(typeof(PopupTest));
public Rect PlacementRectangle
{
    get { return (Rect)GetValue(PlacementRectangleProperty); }
    set { SetValue(PlacementRectangleProperty, value); }
}
//HorizontalOffset
public static readonly DependencyProperty HorizontalOffsetProperty =
            Popup.HorizontalOffsetProperty.AddOwner(typeof(PopupTest));
public double HorizontalOffset
{
    get { return (double)GetValue(HorizontalOffsetProperty); }
    set { SetValue(HorizontalOffsetProperty, value); }
}
//VerticalOffset
public static readonly DependencyProperty VerticalOffsetProperty =
            Popup.VerticalOffsetProperty.AddOwner(typeof(PopupTest));
public double VerticalOffset
{
    get { return (double)GetValue(VerticalOffsetProperty); }
    set { SetValue(VerticalOffsetProperty, value); }
}
public static readonly DependencyProperty StaysOpenProperty =
Popup.StaysOpenProperty.AddOwner(
        typeof(PopupTest),
        new FrameworkPropertyMetadata(
                false,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                new PropertyChangedCallback(OnStaysOpenChanged)));
public static readonly DependencyProperty IsOpenProperty =
 Popup.IsOpenProperty.AddOwner(
         typeof(PopupTest),
         new FrameworkPropertyMetadata(
                 false,
                 FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                 new PropertyChangedCallback(OnIsOpenChanged)));
#endregion

Now add some event handlers for the PropertyChangedCallback events.

private static void OnStaysOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    PopupTest ctrl = (PopupTest)d;
 
    if ((bool)e.NewValue)
    {
        ctrl.StaysOpenParentPopop((bool)e.NewValue);
    }
}
private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    TenKeyPopup ctrl = (TenKeyPopup)d;
    if ((bool)e.NewValue)
    {
        if (ctrl._parentPopup == null)
        {
            ctrl.HookupParentPopup();
        }
    }
}
private void StaysOpenParentPopop(bool newValue)
{
    _parentPopup.StaysOpen = newValue;
}
private void HookupParentPopup()
{
    _parentPopup = new Popup();
    _parentPopup.AllowsTransparency = true;
    Popup.CreateRootPopup(_parentPopup, this);
}

Conclusion

This method of creating Popup controls is a little bit more difficult than the quick and dirty method described in Part 1.  However, we can now benefit from reusability and encapsulation of the control.  We could easily add dependency properties at this point to add functionality to the control as well as visual styles.

Actually using the Popup control is the same as what is describe in Part 1.  Please feel free to leave comments and suggestions.

Advertisements

January 8, 2008 - Posted by | C#, WPF, XAML

13 Comments »

  1. Hi,

    I am using same logic what u have descibe here… I have created custom control which contains Frame… On button click i am initialitng custom control, which internally place it self under popup using CreateRootPopup. But i am facing following issues, if you able to help me its gr8!!!
    1. I have put Thumb inside my control so i can move my popup as Dialog Window… which working fine but stuking on screen boundry lines.
    2. CreateRootPopup is not setting parent property nor i am able to set later so my popup doesn’t have parent which make its top most even i minimize my actual window and popup still stays on top of the screen!!!
    3. Is there any way i can make my popup as Model Dialog which Freeze the Background Window while working with popup!!!

    I do not want to use Window Dialog.

    It will be really gr8!!! if you help me out, if you need my code i am really happy to share with… plz plz need help!!!

    Shrenik

    Comment by Shrenik Jhaveri | January 10, 2008 | Reply

  2. Shrenik, I am pretty certain your requirements are closer to using a Window rather than a Popup. You can always create an empty window that contains your User Control, I have a lot of examples that do this.

    Requirement 3 from your comment dictates that you want to instantiate the window with ShowDialog(). I would be more than happy to write an article about this topic if you like.

    Comment by roecode | January 10, 2008 | Reply

  3. Shrenik, after giving this a second thought. You could always implement the user control on a Window or Page and have it “popup” and steal focus from the Parent Window.

    Look for a sample today that does this. Sorry for confusion in my previous comment.

    Comment by roecode | January 10, 2008 | Reply

  4. Great information on creating our own controls, man. I really appreciate you taking the time to share this knowledge.

    I have a question that I am sure has a simple answer, but I can’t quite figure it out yet. I’d like to fine-tune the behavior for the “stock” animations provided with the Popup control. For instance, I’d like to change the length of the fade effect, but for the life of me I can’t figure out how to do it. Would you kindly point me in the right direction? 🙂

    Thanks in advance for your help and keep on blogging!

    Cheers,
    Victor

    Comment by Victor | July 1, 2008 | Reply

  5. You will want to take a look at template animation.

    Comment by roecode | July 1, 2008 | Reply

  6. Is this popup part of the visual tree like a Custom Control, or is it outside the regular control flow like a true Popup?

    I’ll be checking this out, but if it’s the latter good find!

    Comment by David | November 25, 2008 | Reply

  7. Hi, I am using a popup to display error messages for a textbox data validation. When textbox validation fails I am displaying Popup; during this if I switch from this application to other application by moving mouse and pressing any application in the task bar popup remains open on top of other applications. How do I fix this?

    Comment by Abdul Sami | January 14, 2009 | Reply

    • Set the staysopen property to false.

      Comment by roecode | January 15, 2009 | Reply

  8. I kno that solution. But my application has lot of modules. Textbox is somewhere in the lower layer of the module. When application is switched then I cannot make staysopen in the any of the window event. I wanted to do this with in the text box code. Assume my text box is custom control.

    Comment by Abdul Sami | January 15, 2009 | Reply

  9. I’m running into a problem with this approach – i believe it has to do with the StaysOpen property setting. If I try and set a control to IsOpen=”true” and StaysOpen=”false”, it opens fine the FIRST time … but when you try and launch that same popup again (without recreating the control), it doesn’t open. For some reason the IsOpen property never really gets changed to False when it closes.

    Any thoughts?

    Comment by Dustin Kofoed | February 4, 2009 | Reply

    • Did you find any solution or explanation to that problem? I am having it too and still cannot solve it. Please share your experience.

      Comment by pavele | March 23, 2010 | Reply

  10. When there was switch to another application Popup stayed on top of switched to applicaiton. StayOpen=”false” did not produce desired behavior of Popup. So I did following:

    ctor:

    Application.Current.Deactivated += new EventHandler(Application_Deactivated);

    private void Application_Deactivated(object sender, EventArgs e)
    {
    if (SaveConfirmationPopup != null)
    {
    SaveConfirmationPopup.IsOpen = false;
    }
    }

    Comment by Eric Coulson | July 24, 2009 | Reply

  11. This is the exact copy of the Custom Popup Control Sample, and you can find it in the MSDN page of Popup.CreateRootPopup() method…

    but without proper explanation (like what you find in the MSDN) your example seems a kind of “magic” and it’s hard to find out why it works.

    P.

    Comment by Paolo | September 11, 2009 | Reply


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

%d bloggers like this: