Code Reference A collection of code for my reference (and perhaps other people too)

23Jul/090

UserControl as a Popup (WPF, C#) – Part 1

The built in Popup in WPF is ok, but it needs to do a LOT more. It would be nice if it could also do the following:
- one popup that can be used anywehre easily in any user control
- modal-like (can disable the background and force the user to interact with the popup)
- can be defined in xaml or prgrammatically
- is movable
- and can (in xaml) be wrapped around UIElements or can have elements added in programmatically

In this post I will take care of the first 3 items.

I got a few of my ideas from Roecode’s nice post on his blog at:

http://roecode.wordpress.com/?s=WPF+Popup+control#

I didn’t see the need for most of the dependency properties. Most of the functionality could be defined in the properties.

Here is the PopupControl class:

public partial class PopupControl : UserControl
    {
        private Grid mainGrid = null;

        public PopupControl()
        {
            InitializeComponent();

            Window mainWindow = Application.Current.MainWindow as Window;
            if (mainWindow != null && mainWindow.Content is Grid)
                mainGrid = mainWindow.Content as Grid; // Main Window's first UIElement must be a Grid
            else
                mainGrid = new Grid(); // This will prevent and error if the main window's first element is not a Grid
        }

        ///
        /// Opens/closes the popup on true/false
        ///
        public bool IsOpen
        {
            get
            {
                if (Visibility == Visibility.Visible)
                    return true;

                return false;
            }
            set
            {
                if (value == true)
                {
                    mainGrid.Children.Remove(this); // Remove the popup - in case they click the open button more than once
                    mainGrid.Children.Add(this); // Add to the end of the bottom of the list so it is above all other items
                    Visibility = Visibility.Visible;
                }
                else
                {
                    mainGrid.Children.Remove(this); // Remove the popup
                    Visibility = Visibility.Collapsed;
                }
            }
        }

        // Clicking outside the popup closes the popup when 'false'
        public bool StaysOpen
        {
            get; set;
        }

        // Set a title for the popup
        public string Title
        {
            get { return (string)lblPopupTitle.Content; }
            set { lblPopupTitle.Content = value; }
        }

        // This hides the Width for the UserControl - this is a good thing
        public double Width
        {
            get { return borderOutside.Width;  }
            set { borderOutside.Width = value; }
        }

        // This hides the Height for the UserControl - this is a good thing
        public double Height
        {
            get { return borderOutside.Height; }
            set { borderOutside.Height = value; }
        }

        public UIElementCollection Children
        {
            get { return contentContainer.Children;  }
        }

        ///
        /// Places a rectangle over the page to prevent access
        ///
        public bool ForceFocus
        {
            get
            {
                if (MainRectangle.Visibility == Visibility.Collapsed)
                    return false;
                return true;
            }
            set
            {
                if (value == true)
                    MainRectangle.Visibility = Visibility.Visible;
                else
                    MainRectangle.Visibility = Visibility.Collapsed;
            }
        }

        ///
        /// Close the popup
        ///
        ///
        ///
        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            IsOpen = false;
        }

    }

In the main window, I define the popup in code. I add a simple button to open it.
Each time it is used, I will create a new instance of it.

public partial class Window1 : Window
    {
        private PopupControl popup = null;

        public Window1()
        {
            InitializeComponent();
            popup = new PopupControl();
            popup.Width = 300;
            popup.Height = 300;
            popup.Title = "This is the popup";
        }

        private void ShopPopup_Click(object sender, RoutedEventArgs e)
        {
            popup.IsOpen = true;
        }
    }

When it is opened and closed, I am adding and removed the popup dynamically to/from the main window’s Grid.
This will not work if the main window’s first element is not a grid. I am check for this. If it is not, nothing will happen.
Because I am add it dynamically to the main window, the PopupControl and MainWindow must be initialized first.
For this reason, in Window1, I declare the PopupControl and assign ‘null’. I cannot initialize it at that point because the MainWidnow’s Grid has not yet been created.

The XAML for the PopupContainer is simple.
These are all defined in the XAML:

<UserControl x:Class="Sandbox.PopupControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    HorizontalAlignment="Stretch" Margin="0" VerticalAlignment="Stretch"
    Width="Auto" Height="Auto" Visibility="Collapsed">

    <UserControl.Resources>
        <Style x:Key="UserControlOverlayRectangleStyle" TargetType="{x:Type Rectangle}">
            <Setter Property="Fill" Value="silver"/>
            <Setter Property="Opacity" Value="0.61"/>
        </Style>
    </UserControl.Resources>

    <Grid Opacity="1" Width="Auto" Height="Auto" Background="{x:Null}">
        <Rectangle Name="MainRectangle" Margin="0" Style="{DynamicResource UserControlOverlayRectangleStyle}"/>
        <Border x:Name="borderOutside" BorderThickness="1" BorderBrush="DarkGray" Background="White" Margin="0">
            <Grid>
                <Button Content="Close" Click="CancelButton_Click" Width="75" Height="30"/>
                <StackPanel Name="contentContainer" MinWidth="150" MinHeight="50" />
            </Grid>
        </Border>
    </Grid>
</UserControl>

In the XAML you will see the 'Rectangle' that covers the main content and prevents it from being accessed - forcing the focus on the popup.

Tagged as: , Leave a comment
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

No trackbacks yet.