locked
Positioning a Popup of undetermined size. RRS feed

  • Question

  • Scenario:

    I have a bottom app-bar, and certain of it's options require an extra dialog box to pop up for options. I have looked at the context menu, but it seems rather limited (So does everything in Windows.UI.Popups). Therefore, I decided to use the popup class. The thing is, I don't want to specify the width and height of my popups directly. I would prefer to have them auto-size to the content (this makes editing the content easier, it let's me use the same code to display different popups, and it would allow, for example, for the font size to be changed without any adverse effects).


    The problem is that my popups always have a fixed size of 1920 x 1080 (My screen resolution). So I added a border to my popup as the first child element. Now, the border has a size 0 until it is rendered. At which point it is too late to position it.

    Ideally, the code would work like this:

    Get rectangle enclosing object

    Set popup.HorizontalOffset to rectangle.X

    Set popup.VerticalOFfset to rectangle.y - border.ActualHeight

    popup.IsOpen = true


    However, since the border has ActualHeight 0, this can't be done.

    I've come up with a workaround which makes it transparent, and then I position it and make it opaque in the opened handler.

    Get rectangle enclosing object

    Set popup.HorizontalOffset to rectangle.X

    Set popup.VerticalOFfset to rectangle.y

    Set popup.opacity = 0

    popup.IsOpen = true

    ------------------------------------------------------------

    private void Popup_Opened(object sender, ...) {

    UpdateLayout(); // necessary for this to work

    popup.VerticalOffset -= Border.ActualHeigh

    popup.Opacity = 1

    This seems like it's way trickier than it should have to be. So I'm suspicious that I might be missing something really simple. Either it's possible to somehow anchor the popup which will make it take care of itself, or there are predefined classes somewhere else that can provide my functionality.

    Thanks,

    Tomas

    ---------------------------------------------------------------------------------------------------

    Additional info:

    I'm using WinRT and xaml, programming in C#.

    My popup is currently residing as a child element of the default grid.


    • Edited by Tumsh Wednesday, July 18, 2012 6:56 PM
    Wednesday, July 18, 2012 6:56 PM

Answers

  • The following is a more sophisticated example that takes screen size into account. However the principles remain the same: the PopUpPane1/2 perform the layout from the 'inside/out' within the parent PopUp.

    ---

    <Page
        x:Class="App1.MainPage"
        IsTabStop="false"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        <Page.BottomAppBar>
            <AppBar Padding="10,0,10,0" IsSticky="True">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                    <Button 
                        Click="Button_Click_1" 
                        IsEnabled="True" 
                        Style="{StaticResource PreviousAppBarButtonStyle}"/>
                    <Button 
                        IsEnabled="True" 
                        Click="Button_Click_2"
                        Style="{StaticResource NextAppBarButtonStyle}"/>
                </StackPanel>
            </AppBar>
        </Page.BottomAppBar>
        <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <ContentControl Grid.Row="0" x:Name="popUpHost" IsTabStop="False"/>
            <Grid Grid.Row="0" >
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <TextBox Grid.Row="0" Text="MyApplicationData"/>
            </Grid>
        </Grid>
    </Page>
        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
            }
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
            }
    
            private void Button_Click_1(object sender, RoutedEventArgs e)
            {
                Rect bounds = Window.Current.Bounds;
                double height = bounds.Height;
                double width = bounds.Width;
                PopupPane1 pup = new PopupPane1();
                pup.Width = bounds.Width;
                pup.Height = bounds.Height;
                // ...
                Popup pu = new Popup();
                pu.VerticalOffset = 0.0;
                pu.HorizontalOffset = 0.0;
                pu.HorizontalOffset = 0.0;
                pu.IsOpen = true;
                // ...
                popUpHost.Content = pu;
                pu.Child = pup;
            }
    
            private void Button_Click_2(object sender, RoutedEventArgs e)
            {
                Rect bounds = Window.Current.Bounds;
                double height = bounds.Height;
                double width = bounds.Width;
                PopupPane2 pup = new PopupPane2();
                pup.Width = bounds.Width;
                pup.Height = bounds.Height;
                // ...
                Popup pu = new Popup();
                pu.VerticalOffset = 0.0;
                pu.HorizontalOffset = 0.0;
                pu.HorizontalOffset = 0.0;
                pu.IsOpen = true;
                // ...
                popUpHost.Content = pu;
                pu.Child = pup;
            }
        }

    ---

    <UserControl
        x:Class="App1.PopupPane1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400">
        <StackPanel Background="GreenYellow" VerticalAlignment="Stretch">
            <Button Content="Hit to close" Click="ClosePopup" FontSize="11"/>
        </StackPanel>
    </UserControl>
    sealed partial class PopupPane1 : UserControl
        {
            public PopupPane1()
            {
                InitializeComponent();
            }
            private void ClosePopup(object sender, RoutedEventArgs e)
            {
                Popup popup = this.Parent as Popup;
                popup.IsOpen = false;
            }
        }

    ---

    <UserControl
        x:Class="App1.PopupPane2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400">
        <Grid Background="Orange" VerticalAlignment="Stretch">
            <Grid.RowDefinitions>
                <!-- Example-->
                <RowDefinition Height="*"/>
                <!-- Example-->
                <RowDefinition Height="3*"/>
                <!-- Example-->
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Button Grid.Row="0"  Content="Hit to close" Click="ClosePopup" FontSize="21"/>
            <Button Grid.Row="1"  Content="Hit to close Me too" Click="ClosePopup" FontSize="21"/>
            <Button Grid.Row="2"  Content="Hit to close Me also" Click="ClosePopup" FontSize="21"/>
        </Grid>
    </UserControl>
    sealed partial class PopupPane2 : UserControl
        {
            public PopupPane2()
            {
                InitializeComponent();
            }
            private void ClosePopup(object sender, RoutedEventArgs e)
            {
                Popup popup = this.Parent as Popup;
                popup.IsOpen = false;
            }
        }

    Does this suit your requirements ?







     



    • Edited by ForInfo Friday, July 20, 2012 5:45 AM
    • Marked as answer by Min ZhuMember Saturday, August 11, 2012 7:54 AM
    Friday, July 20, 2012 5:39 AM

All replies

  • <Page
        x:Class="PopUp.MainPage"
        IsTabStop="false"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:PopUp"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        <Page.BottomAppBar>
            <AppBar Padding="10,0,10,0" IsSticky="True">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                    <Button 
                        Click="Button_Click_1" 
                        IsEnabled="True" 
                        Style="{StaticResource PreviousAppBarButtonStyle}"/>
                    <Button 
                        IsEnabled="True" 
                        Click="Button_Click_2"
                        Style="{StaticResource NextAppBarButtonStyle}"/>
                </StackPanel>
            </AppBar>
        </Page.BottomAppBar>
        <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
            <Grid.RowDefinitions>
                <RowDefinition Height="0"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <ContentControl Grid.Row="0" x:Name="popUpHost" IsTabStop="False"/>
            <TextBox Grid.Row="1" Text="MyApplicationData"/>
        </Grid>
    </Page>

    ---

    namespace PopUp
    {
        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
            }
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
            }
    
            private void Button_Click_1(object sender, RoutedEventArgs e)
            {
                Popup pu = new Popup();
                PopupPane1 pup = new PopupPane1();
                // ...
                pu.VerticalOffset = 300.0;
                pu.HorizontalOffset = 100.0;
                pu.IsOpen = true;
                // ...
                popUpHost.Content = pu;
                pu.Child = pup;
            }
    
            private void Button_Click_2(object sender, RoutedEventArgs e)
            {
                Popup pu = new Popup();
                PopupPane2 pup = new PopupPane2();
                // ...
                pu.VerticalOffset = 300.0;
                pu.HorizontalOffset = 200.0;
                pu.IsOpen = true;
                // ...
                popUpHost.Content = pu;
                pu.Child = pup;
            }
        }
    }

    ---

    <UserControl x:Class="PopUp.PopupPane1"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
        <StackPanel Background="GreenYellow">
            <Button Content="Hit to close" Click="ClosePopup" FontSize="11"/>
        </StackPanel>
    </UserControl>
    namespace PopUp
    {
        sealed partial class PopupPane1 : UserControl
        {
            public PopupPane1()
            {
                InitializeComponent();
            }
            private void ClosePopup(object sender, RoutedEventArgs e)
            {
                Popup popup = this.Parent as Popup;
                popup.IsOpen = false;
            }
        }
    }

    ---

    <UserControl x:Class="PopUp.PopupPane2"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
        <StackPanel Background="Orange">
            <Button Content="Hit to close" Click="ClosePopup" FontSize="21"/>
        </StackPanel>
    </UserControl>
    namespace PopUp
    {
        sealed partial class PopupPane2 : UserControl
        {
            public PopupPane2()
            {
                InitializeComponent();
            }
            private void ClosePopup(object sender, RoutedEventArgs e)
            {
                Popup popup = this.Parent as Popup;
                popup.IsOpen = false;
            }
        }
    }

    ---

    This should put you in the right direction ...








    • Edited by ForInfo Thursday, July 19, 2012 8:40 AM
    Thursday, July 19, 2012 8:36 AM
  • So, when I go to position it on the screen, I still don't seem to have access to the height of the popup.

    Say:

    private void Button_Click_1(object sender, RoutedEventArgs e) {

    Rect rect = GetElementRect((FrameworkElement)sender); Popup pu = new Popup(); PopupPane1 pup = new PopupPane1(); // ... pu.VerticalOffset = rect.Y - [height of popup]; pu.HorizontalOffset = 100.0; pu.IsOpen = true; // ... popUpHost.Content = pu; pu.Child = pup; }

    Edit: I realize I can use a standard usercontrol and simply put it in my grid. It display's properly and can be aligned with, for example, the right side of the screen. Though now I am trying to figure out how to get it's dismiss properties to behave like a popup.

    • Edited by Tumsh Thursday, July 19, 2012 10:45 PM
    Thursday, July 19, 2012 10:42 PM
  • The following is a more sophisticated example that takes screen size into account. However the principles remain the same: the PopUpPane1/2 perform the layout from the 'inside/out' within the parent PopUp.

    ---

    <Page
        x:Class="App1.MainPage"
        IsTabStop="false"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        <Page.BottomAppBar>
            <AppBar Padding="10,0,10,0" IsSticky="True">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                    <Button 
                        Click="Button_Click_1" 
                        IsEnabled="True" 
                        Style="{StaticResource PreviousAppBarButtonStyle}"/>
                    <Button 
                        IsEnabled="True" 
                        Click="Button_Click_2"
                        Style="{StaticResource NextAppBarButtonStyle}"/>
                </StackPanel>
            </AppBar>
        </Page.BottomAppBar>
        <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <ContentControl Grid.Row="0" x:Name="popUpHost" IsTabStop="False"/>
            <Grid Grid.Row="0" >
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <TextBox Grid.Row="0" Text="MyApplicationData"/>
            </Grid>
        </Grid>
    </Page>
        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
            }
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
            }
    
            private void Button_Click_1(object sender, RoutedEventArgs e)
            {
                Rect bounds = Window.Current.Bounds;
                double height = bounds.Height;
                double width = bounds.Width;
                PopupPane1 pup = new PopupPane1();
                pup.Width = bounds.Width;
                pup.Height = bounds.Height;
                // ...
                Popup pu = new Popup();
                pu.VerticalOffset = 0.0;
                pu.HorizontalOffset = 0.0;
                pu.HorizontalOffset = 0.0;
                pu.IsOpen = true;
                // ...
                popUpHost.Content = pu;
                pu.Child = pup;
            }
    
            private void Button_Click_2(object sender, RoutedEventArgs e)
            {
                Rect bounds = Window.Current.Bounds;
                double height = bounds.Height;
                double width = bounds.Width;
                PopupPane2 pup = new PopupPane2();
                pup.Width = bounds.Width;
                pup.Height = bounds.Height;
                // ...
                Popup pu = new Popup();
                pu.VerticalOffset = 0.0;
                pu.HorizontalOffset = 0.0;
                pu.HorizontalOffset = 0.0;
                pu.IsOpen = true;
                // ...
                popUpHost.Content = pu;
                pu.Child = pup;
            }
        }

    ---

    <UserControl
        x:Class="App1.PopupPane1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400">
        <StackPanel Background="GreenYellow" VerticalAlignment="Stretch">
            <Button Content="Hit to close" Click="ClosePopup" FontSize="11"/>
        </StackPanel>
    </UserControl>
    sealed partial class PopupPane1 : UserControl
        {
            public PopupPane1()
            {
                InitializeComponent();
            }
            private void ClosePopup(object sender, RoutedEventArgs e)
            {
                Popup popup = this.Parent as Popup;
                popup.IsOpen = false;
            }
        }

    ---

    <UserControl
        x:Class="App1.PopupPane2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400">
        <Grid Background="Orange" VerticalAlignment="Stretch">
            <Grid.RowDefinitions>
                <!-- Example-->
                <RowDefinition Height="*"/>
                <!-- Example-->
                <RowDefinition Height="3*"/>
                <!-- Example-->
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Button Grid.Row="0"  Content="Hit to close" Click="ClosePopup" FontSize="21"/>
            <Button Grid.Row="1"  Content="Hit to close Me too" Click="ClosePopup" FontSize="21"/>
            <Button Grid.Row="2"  Content="Hit to close Me also" Click="ClosePopup" FontSize="21"/>
        </Grid>
    </UserControl>
    sealed partial class PopupPane2 : UserControl
        {
            public PopupPane2()
            {
                InitializeComponent();
            }
            private void ClosePopup(object sender, RoutedEventArgs e)
            {
                Popup popup = this.Parent as Popup;
                popup.IsOpen = false;
            }
        }

    Does this suit your requirements ?







     



    • Edited by ForInfo Friday, July 20, 2012 5:45 AM
    • Marked as answer by Min ZhuMember Saturday, August 11, 2012 7:54 AM
    Friday, July 20, 2012 5:39 AM