简体   繁体   中英

UWP XAML Popup not respecting VerticalAlignment?

I'm trying to center a Popup in a Windows Store/UWP app.

In brief, I'm taking MainPage and adding...

  • A TextBlock with some text
  • A Button with an event handler, Button_Click
  • A Popup named popupTest . It contains...
    • A Border with...
      • A StackPanel with
        • A TextBlock
        • A Button . This Button 's event handle sets the Popup 's IsOpen to false.

Button_Click calls _centerPopup , which tries to center the Popup and then sets IsOpen to true . I can't get this to work.

private void _centerPopup(Popup popup, Border popupBorder, FrameworkElement extraElement = null)
{
    double ratio = .9; // How much of the window the popup fills, give or take. (90%)

    Panel pnl = (Panel)popup.Parent;
    double parentHeight = pnl.ActualHeight;
    double parentWidth = pnl.ActualWidth;

    // Min 200 for each dimension.
    double width = parentWidth * ratio > 200 ? parentWidth * ratio : 200;
    double height = parentHeight * ratio > 200 ? parentHeight * ratio : 200;

    popup.Width = width;
    popup.Height = height;

    //popup.HorizontalAlignment = HorizontalAlignment.Center;
    popup.VerticalAlignment = VerticalAlignment.Top;    // <<< This is ignored?!

    // Resize the border too. Not sure how to get this "for free".
    popupBorder.Width = width;
    popupBorder.Height = height;

    // Not using this here, but if there's anything else that needs resizing, do it.
    if (null != extraElement)
    {
        extraElement.Width = width;
        extraElement.Height = height;
    }
}

If I don't try to resize and center the Popup in Button_Click, here's what I get after clicking "Click Me"...

private void Button_Click(object sender, RoutedEventArgs e)
{
    //_centerPopup(this.popupTest, this.popupTestBorder);
    this.popupTest.IsOpen = true;
}

单击我单击,没有调整大小或居中

If I uncomment out the call to _ centerPopup , I get this, with the popup staying under the button:

private void Button_Click(object sender, RoutedEventArgs e)
{
    _centerPopup(this.popupTest, this.popupTestBorder);
    this.popupTest.IsOpen = true;
}

随着重新定位和调整大小

That's no good. I thought popup.VerticalAlignment = VerticalAlignment.Top; would've fixed that.

FrameworkElement.VerticalAlignment Property

Gets or sets the vertical alignment characteristics applied to this element when it is composed within a parent element such as a panel or items control.


Move Popup to top of StackPanel?

Strangely, if I move the Popup up to the top of my StackPanel, it actually pushes the other controls down after being shown.

Clicking "Click Me" without _centerPopup :

看起来很有希望

That looks promising! It's floating over the other controls nicely, and there's no obvious impact to the layout after it's closed.

But add back _centerPopup , even after commenting out setting VerticalAlignment to Top , and things die a horrible, fiery death.

下推控件

It looks perfect until you notice that every other control was pushed down . ??? Here's after clicking "Click to close":

东西被永久压低

Other controls are pushed down permanently . Why does that happen? Shouldn't the popup float like it did before I resized it?


Full Source

XAML

<Page
    x:Class="PopupPlay.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PopupPlay"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <StackPanel Name="StackMain">
        <TextBlock>
            This is some text<LineBreak />
            This is some text<LineBreak />
            This is some text<LineBreak />
            This is some text<LineBreak />
        </TextBlock>
        <Button Click="Button_Click" Content="Click Me"></Button>

        <Popup x:Name="popupTest">
            <Border
                    Name="popupTestBorder"
                    Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
                    BorderBrush="{StaticResource ApplicationForegroundThemeBrush}"
                    BorderThickness="2">
                <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
                    <TextBlock Name="txtPopup"
                               Text="This is some text"
                               FontSize="24"
                               HorizontalAlignment="Center" />
                    <Button Name="btnClose"
                            Click="btnClose_Click"
                               Content="Click to close"></Button>
                </StackPanel>
            </Border>
        </Popup>
    </StackPanel>
</Page>

Full MainPage.xaml.cs code

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;

namespace PopupPlay
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            _centerPopup(this.popupTest, this.popupTestBorder);

            this.popupTest.IsOpen = true;
        }

        private void _centerPopup(Popup popup, Border popupBorder, FrameworkElement extraElement = null)
        {
            double ratio = .9; // How much of the window the popup fills, give or take. (90%)

            Panel pnl = (Panel)popup.Parent;
            double parentHeight = pnl.ActualHeight;
            double parentWidth = pnl.ActualWidth;

            // Min 200 for each dimension.
            double width = parentWidth * ratio > 200 ? parentWidth * ratio : 200;
            double height = parentHeight * ratio > 200 ? parentHeight * ratio : 200;

            popup.Width = width;
            popup.Height = height;

            //popup.HorizontalAlignment = HorizontalAlignment.Center;
            popup.VerticalAlignment = VerticalAlignment.Top;    // <<< This is ignored?!

            // Resize the border too. Not sure how to get this "for free".
            popupBorder.Width = width;
            popupBorder.Height = height;

            // Not using this here, but if there's anything else that needs resizing, do it.
            if (null != extraElement)
            {
                extraElement.Width = width;
                extraElement.Height = height;
            }
        }

        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            this.popupTest.IsOpen = false;
        }
    }
}

There are several questions that seem related. I do not see a viable fix. (Note: These are not all UWP specific.)

Painfully, this same setup is working for me in another app when it's positioned in a much more complicated grid with a Pivot, but I see that pivots are buggy .

Wpf's Placement stuff sounds promising , but doesn't exist in UWP-land.

Your Popup is inside a vertical StackPanel , which means the StackPanel will lay out the popup alongside the other child elements of the panel, which is why it pushes down the text.

Also, the VerticalAlignment is being ignored by the panel because the panel allocated exactly enough vertical space for the popup's size, and so there is no room for it to align the popup vertically within the space it was allocated.

I would suggest using a Grid as the root element for the Page , and putting the StackPanel and Popup directly inside the Grid , like this:

<Grid>
    <StackPanel Name="StackMain">
        <TextBlock>
        This is some text<LineBreak />
        This is some text<LineBreak />
        This is some text<LineBreak />
        This is some text<LineBreak />
        </TextBlock>
        <Button Click="Button_Click" Content="Click Me"></Button>
    </StackPanel>
    <Popup x:Name="popupTest">
        <Border
                Name="popupTestBorder"
                Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
                BorderBrush="{StaticResource ApplicationForegroundThemeBrush}"
                BorderThickness="2">
            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
                <TextBlock Name="txtPopup"
                           Text="This is some text"
                           FontSize="24"
                           HorizontalAlignment="Center" />
                <Button Name="btnClose"
                        Click="btnClose_Click"
                           Content="Click to close"></Button>
            </StackPanel>
        </Border>
    </Popup>
</Grid>

Grid s are good for this purpose, when you want to have overlapping elements or multiple elements that do not affect the position and size of any other child element. You want the layout of the popup to be separate from the layout of the stack panel and its children, so you should organize your XAML as such.

Try changing your xaml as follows...

<Page...>
    <Grid x:Name="LayoutRoot">
        <Popup>
        </Popup>

        <Grid x:Name="ContentPanel">
        </Grid>
    </Grid>
</Page>

So move the Popup control outside the content area and put your stacklayout with all content inside the ContentPanel Grid ( as shown in code sample above )

That should stop pushing the other controls down...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM