C# 如何在窗口中居中弹出窗口(Windows应用商店应用程序)

C# 如何在窗口中居中弹出窗口(Windows应用商店应用程序),c#,xaml,windows-store-apps,C#,Xaml,Windows Store Apps,我有一个自定义弹出窗口(作为用户控件),我通过编程加载它。我不能使它在x轴上居中,只能在垂直方向上。弹出窗口不会添加到xaml文件中,而是添加到根窗口中 using System; using System.Collections.Generic; using System.IO; using System.Linq; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; us

我有一个自定义弹出窗口(作为用户控件),我通过编程加载它。我不能使它在x轴上居中,只能在垂直方向上。弹出窗口不会添加到xaml文件中,而是添加到根窗口中

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Windows;
using Windows.UI.Core;

// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236

namespace QSTLibrary.WIN8.Tools
{
    public sealed partial class CustomProgressRingPopup : UserControl
    {

        public CustomProgressRingPopup()
        {
            this.InitializeComponent();
        }

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
                        "Text", 
                        typeof(string), 
                        typeof(CustomProgressRingPopup),
                        new PropertyMetadata("", OnTextChanged));


        public void OpenPopup()
        {
            this.ParentPopup.IsOpen = true;
        }

        public void ClosePopup()
        {
            this.ParentPopup.IsOpen = false;
        }

        private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var instance = d as CustomProgressRingPopup;
            var newValue = e.NewValue as string;
            if (instance != null && newValue != null)
            {
                instance.CustomTextBlock.Text = newValue;
            }
        }

        private void OnPopupLoaded(object sender, RoutedEventArgs e)
        {
            this.ParentPopup.HorizontalOffset = (Window.Current.Bounds.Width - gdChild.ActualWidth) / 2;
            this.ParentPopup.VerticalOffset = (Window.Current.Bounds.Height - gdChild.ActualHeight) / 2;
        }
    }
}
userControl xaml:

<UserControl
    x:Class="QSTLibrary.WIN8.Tools.CustomProgressRingPopup"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:QSTLibrary.WIN8.Tools"
    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">

    <Popup x:Name="ParentPopup" HorizontalAlignment="Center" VerticalAlignment="Center" Loaded="OnPopupLoaded">
        <Grid x:Name="gdChild" Height="auto" Width="auto" Background="Blue" Margin="20">
            <Grid.RowDefinitions>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <ProgressRing x:Name="CustomProgressRing" Height="40" Width="40" IsActive="true" Grid.Column="0" Margin="20"/>
            <TextBlock x:Name="CustomTextBlock" Height="auto" Width="auto" FontSize="25" Grid.Column="1" Margin="20"/>
        </Grid>
    </Popup>    
</UserControl>

您可以在XAML文件中居中:

<Popup x:Name="ParentPopup" PlacementTarget="{Binding ElementName=MainPanel}" Placement="Center" />

我在cs文件中添加了弹出窗口的LayoutUpdate回调,现在可以工作了

private void OnLayoutUpdated(object sender, object e)
        {
            if(gdChild.ActualWidth == 0 && gdChild.ActualHeight == 0)
            {
                return;
            }

            double ActualHorizontalOffset = this.ParentPopup.HorizontalOffset;
            double ActualVerticalOffset = this.ParentPopup.VerticalOffset;

            double NewHorizontalOffset = (Window.Current.Bounds.Width - gdChild.ActualWidth) / 2;
            double NewVerticalOffset = (Window.Current.Bounds.Height - gdChild.ActualHeight) / 2;

            if (ActualHorizontalOffset != NewHorizontalOffset || ActualVerticalOffset != NewVerticalOffset)
            {
                this.ParentPopup.HorizontalOffset = NewHorizontalOffset;
                this.ParentPopup.VerticalOffset = NewVerticalOffset;
            }
        }
以及XAML中的弹出窗口:

<Popup x:Name="ParentPopup" LayoutUpdated="OnLayoutUpdated">

我修改了Butzke的答案,使之更具普遍性:

<Popup PlacementTarget="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" Placement="Center" />

在UWP Windows应用商店应用程序中定位一个
弹出窗口
,并不像可能的那样简单。下面是我最终如何解决它的。不要观察
LayoutUpdated
事件(这可能导致布局循环),而是观察视图顶级元素的
SizeChanged
事件,并使用此事件重新定位其中包含的弹出窗口

在本例中,我将对话框定位在窗口的中心,因此使用
window.Current
。您还需要转换坐标,因为弹出窗口将根据布局中实际定义的
弹出窗口
元素的位置使用自己的相对坐标系:

private void MyDialog_SizeChanged(object sender, SizeChangedEventArgs e) {
    var transform = Window.Current.Content.TransformToVisual(_popup);
    Point point = transform.TransformPoint(new Point(0, 0)); // gets the window's (0,0) coordinate relative to the popup

    double hOffset = (Window.Current.Bounds.Width - this.ActualWidth) / 2;
    double vOffset = (Window.Current.Bounds.Height - this.ActualHeight) / 2;

    _popup.HorizontalOffset = point.X + hOffset;
    _popup.VerticalOffset = point.Y + vOffset;
}

我发现错误:在类型“Popup”中找不到属性“PlacementTarget”。与“Placement”相同。@AlexandruCircus
PlacementTarget
是要居中的面板。主面板默认存在,但您可以在另一个面板中居中。好的,我理解。但似乎PlacementTarget属性无法应用于Popup元素,这是我从错误中理解的:“在类型'Popup'中找不到属性'PlacementTarget'。”此外,当我编写Placemen时,它无法在代码中自动完成。。。它应该向PlacementTarget提供自动完成建议该项目是一个Windows应用商店应用程序。可能PlacementTarget不适用于此类项目。我是C#,.NET的新手……我是java程序员您是否尝试过只使用
Grid
而不使用
Popup
?在
OpenPopup()
方法中,您需要设置
网格的
可见性。如果您仅使用
网格
“Window.Current.Bounds”导致我的应用程序崩溃,错误为“检测到布局周期。布局无法完成”。通过将其更改为我使用的顶级容器,您也不需要处理
弹出窗口
的偏移属性。我还更改了(NewHorizontalOffset!=double.NaN&(ActualHorizontalOffset!=NewHorizontalOffset | | ActualVerticalOffset!=NewVerticalOffset))-以检查是否也发生了NaN。@DaveFriedel我们面临同样的问题,但无法实施您的建议。我们有一个弹出窗口,其中我们正在使用一个包含此代码的用户控件,我们应该如何着手解决该问题,以避免出现循环布局异常thrown@Teja-你能发布一个示例吗(我不喜欢这样问,因为这样做太复杂了),我建议替换“Window.Current.Bounds.Width”使用位于堆栈顶部的网格根或其他对象的名称。我发现“窗口”导致了我的问题,但如果我命名了一个包装对象,它会起作用。Windows似乎不希望您在
LayoutUpdated
处理程序中调整影响属性的布局。我建议改为使用
SizeChanged
事件,它似乎没有这个问题。还存在“检测到布局周期。布局无法完成”问题,但通过将新的水平和垂直偏移量转换为intThis解决了这个问题。这对WPF有效,但PlacementTarget和FindAncestor模式在uwp应用程序中不可用
private void MyDialog_SizeChanged(object sender, SizeChangedEventArgs e) {
    var transform = Window.Current.Content.TransformToVisual(_popup);
    Point point = transform.TransformPoint(new Point(0, 0)); // gets the window's (0,0) coordinate relative to the popup

    double hOffset = (Window.Current.Bounds.Width - this.ActualWidth) / 2;
    double vOffset = (Window.Current.Bounds.Height - this.ActualHeight) / 2;

    _popup.HorizontalOffset = point.X + hOffset;
    _popup.VerticalOffset = point.Y + vOffset;
}