Click here to Skip to main content
Click here to Skip to main content
Go to top

Reusable Silverlight Popup Logic

, 22 May 2008
Rate this:
Please Sign up or sign in to vote.
Encapsulated Popup logic for easy reusable Silverlight popups

Introduction

This code allows you to hookup a popup control to any trigger within a Silverlight application. It prevents the developer from having to rewrite the same event handlers and timers that such controls need. It also gives a brief example of just how exactly to use the Popup primitive, but only so much as to get the purpose of the code across. I have called the code a PopupProvider.

Background

When I started working with the Popup primitive control for Silverlight, I realized I was going to be rewriting the same logic over and over to open and close the control. For all the usual reasons one decides to refactor and encapsulate logic (reduce source size, maintain single copy, etc.), I wrote this piece of code.

Using the Code

The code is very quick and easy to use. First create a simple Silverlight user control that contains a Popup primitive and a child control.

<UserControl x:Class="Example.Controls"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel x:Name="LayoutRoot" Orientation="Horizontal">
        <HyperlinkButton x:Name="TriggerButton" Content="Trigger"/>
        <Popup x:Name="PopupControl">
            <TextBlock x:Name="ChildText" Text="Popup Text"/>
        </Popup>
    </StackPanel>
</UserControl>

Next, add a private field to the code behind to keep a handle on the PopupProvider. And finally, intantiate the PopupProvider in the constuctor of your user control. The final code will look something like this:

    public ExampleControl()
    {
        InitializeComponent();

        _popupProvider = new PopupProvider
	(TriggerButton, TriggerButton, PopupControl, ChildText, Direction.Bottom);
    }

    private PopupProvider _popupProvider;

Notes on the constructor parameters (these are also available in the source file). The parameters below appear in the order in which they are used in the constructor.

  • owner - The owner is the FrameworkElement that will trigger the popup to close if the mouse leaves its screen area. The popup will only remain open after leaving the owner if the popupChild element is supplied in this constructor and the mouse immediately enters the screen area of the popupChild element after leaving the owner. The owner does not need to be the same control as the trigger, but it should contain the trigger. This is useful in situations such as when a search button should open some help text, but the help text should stay visible while the mouse is over the search text box as well. The owner in this case could be a panel that contains both the button and the text box.
  • trigger - The trigger is the FrameworkElement that triggers the popup panel to open. The popup will open on the MouseLeftButtonUp mouse event of the trigger.
  • popup - The popup is the Popup primitive control that contains the content to be displayed.
  • popupChild - The popupChild is the child control of the popup panel. The Popup control does not raise MouseEnter and MouseLeave events so the child control must be used to detect if the popup should remain open or closed in conjunction with the owner element. This value may be left null to create situations where only the owner element controls whether the popup closes or not. e.g. an image could trigger a popup that describes the image and the popup closes when the mouse leaves the image regardless of whether the mouse enters the description.
  • placement - Determines which side of the owner element the popup will appear on. This is an enum that is also included in the source code.

Points of Interest

The provider code itself is mostly just attaching events and handling state that is not too interesting. Probably the most valuable logic that I can share from within it is how the popup control is positioned.

FrameworkElement page = Application.Current.RootVisual as FrameworkElement;
GeneralTransform gt = _owner.TransformToVisual(page);
Point p;
p = gt.Transform(new Point(0, _owner.ActualHeight - 2));
_popup.VerticalOffset = p.Y;
_popup.HorizontalOffset = p.X;
_popup.IsOpen = true;

There is obviously some room for error handling in there, but you get the point.

Also, I have some words of warning. I haven't used this control in a terribly wide variety of situations yet. I know there are several bugs to be fixed, other events that could be handled and many usability tweaks to be made. If you have any suggestions, let me know or feel free to implement them yourself.

History

  • 2008-05-23: Made a couple of spelling fixes and added some description about the provider code

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Chuck Kinnan
Founder Milyli Inc.
United States United States
The first program I typed into a computer was a paint program I copied out of a magazine and into the family TRS80 at age 6. I've been writing programs ever since.
 
I have just started my own company, Milyli and my blog is at Cozened Cognizance.

Comments and Discussions

 
GeneralNo way to call it PinmemberMember 435881529-Jul-08 12:56 
AnswerRe: No way to call it PinmemberChuck Kinnan30-Jul-08 6:26 
QuestionHow to call it? Pinmemberdiegolaz29-May-08 8:22 
AnswerRe: How to call it? PinmemberChuck Kinnan2-Jun-08 3:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140905.1 | Last Updated 22 May 2008
Article Copyright 2008 by Chuck Kinnan
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid