首页 > 解决方案 > 是什么让我的 WPF 弹出窗口与其 PlacementTarget 的右边缘对齐?

问题描述

我试图理解为什么我的 WPF 弹出窗口似乎与其 PlacementTarget 的右边缘对齐:

在此处输入图像描述

通常,弹出窗口应与左侧对齐。

这是在一个更大的项目中,我用大量的代码、样式等进行了交互。我试图简化并提取一个示例,并且 - 令我惊讶的是 - 如果它在另一个空白的单独应用程序中运行,那么它会正确对齐:

在此处输入图像描述

我已经搜索了要排除的代码:

我几乎尝试从项目中删除所有 ResourceDictionaries,但项目甚至无法构建或启动的除外。

我还通过 snoop 调查了弹出窗口,它具有正确的放置目标,没有偏移和正确的放置。

我在这里迷路了。关于什么可能导致这种情况的任何理论?

这是示例代码(可能看起来有点复杂,因为原始代码将此作为用户控件):

<Window x:Class="PopupIssue.client.Window1"
        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"
        Title="Window1" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="80" />
            <ColumnDefinition Width="3" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <StackPanel Orientation="Vertical">
            <Border Background="Blue" Height="40"/>

            <Button x:Name="DropdownParent" Click="Button_OnClick" Focusable="True" KeyboardNavigation.AcceptsReturn="False" >
                <Button.Template>
                    <ControlTemplate TargetType="Button">
                        <StackPanel>
                            <Border Margin="2" Background="AliceBlue">
                                <Grid x:Name="DropdownMain" >
                                    <!-- Background="#FFE3E8EA">-->
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="20" MaxWidth="20" />
                                    </Grid.ColumnDefinitions>
                                    <Border Grid.Column="0" Grid.ColumnSpan="2">
                                        <TextBlock Text="" />
                                    </Border>
                                    <Border Grid.Column="1" Margin="2" Padding="5" Background="LightSalmon">
                                        <Path x:Name="Arrow" Fill="Gray" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M 0 0 L 4 4 L 8 0 Z" />
                                    </Border>
                                </Grid>
                            </Border>
                            <Popup  Placement="Bottom" IsOpen="{Binding ShowPopup}" PlacementTarget="{Binding ElementName=DropdownParent}" PopupAnimation="Fade" StaysOpen="True" MinWidth="{Binding ActualWidth, ElementName=DropdownParent}" Closed="Popup_OnClosed"  Opened="Popup_OnOpened" KeyDown="Popup_OnKeyDown">
                                <Border  Background="White" Padding="5,2,5,2" BorderBrush="Red" BorderThickness="1">
                                    <StackPanel>
                                        <StackPanel.Resources>
                                            <Style TargetType="{x:Type RadioButton}">
                                                <Setter Property="Margin" Value="0,10,0,0"/>
                                            </Style>
                                        </StackPanel.Resources>

                                        <RadioButton Content="Lorem Ipsum Dolor Ahmed Quid Prio" GroupName="rbGroup" ></RadioButton>
                                        <RadioButton Content="Lorem Ipsum Dolor Ahmed Quid Prio" GroupName="rbGroup" ></RadioButton>
                                        <RadioButton Content="Lorem Ipsum Dolor Ahmed Quid Prio" GroupName="rbGroup" ></RadioButton>
                                        <RadioButton Content="Lorem Ipsum Dolor Ahmed Quid Prio" GroupName="rbGroup" ></RadioButton>
                                        <RadioButton Content="Lorem Ipsum Dolor Ahmed Quid Prio" GroupName="rbGroup" ></RadioButton>
                                    </StackPanel>
                                </Border>
                            </Popup>
                        </StackPanel>
                    </ControlTemplate>
                </Button.Template>
            </Button>

            <Border Background="Blue" Height="40"/>
        </StackPanel>


        <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
        <Border Background="Beige" Grid.Column="2" />
    </Grid>
</Window>
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Threading;

namespace PopupIssue.client
{
    /// <summary>
    /// Interaktionslogik für Window1.xaml
    /// </summary>
    public partial class Window1 : Window, INotifyPropertyChanged
    {
        public Window1()
        {
            this.DataContext = this;
            InitializeComponent();
        }

        private bool showPopup;
        public bool ShowPopup { get => showPopup; set { showPopup = value; NotifyPropertyChanged("ShowPopup"); } }

        public event PropertyChangedEventHandler PropertyChanged;


        private void NotifyPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }


        private DateTime lastClosed = DateTime.MinValue;

        private void Popup_OnClosed(object sender, EventArgs e)
        {
            lastClosed = DateTime.Now;
            var tmp = OnPopupClosed;
            if (tmp != null)
                tmp(this, new EventArgs());

            Action a = () => this.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
            Dispatcher.BeginInvoke(DispatcherPriority.Background, a);
        }

        public event EventHandler<EventArgs> OnPopupClosed;
        public event EventHandler<EventArgs> OnPopupOpened;



        private void Button_OnClick(object sender, RoutedEventArgs e)
        {
            // When button is clicked while the popup is already open, then the popup is closed automatically by the system before this event handler.
            // So when this method is executed, the popup is always closed. 
            // However if the user clicked the button while the popup was open, then he expects the popup to close (which the system does automatically) and not to immediately re-open.

            // The only viable way is to check if the popup closed immediately (<200 ms) before the click and not open the popup then
            var millisSinceClose = (DateTime.Now - lastClosed).TotalMilliseconds;

            if (millisSinceClose > 200)
                ShowPopup = true;
        }

        private void Popup_OnOpened(object sender, EventArgs e)
        {
            var f = Content as FrameworkElement;
            if (f != null)
            {
                Action a = () => f.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
                Dispatcher.BeginInvoke(DispatcherPriority.Background, a);

                var tmp = OnPopupOpened;
                if (tmp != null)
                    tmp(this, new EventArgs());
            }
        }

        private void Popup_OnKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                ((Popup)sender).IsOpen = false;
                e.Handled = true;
            }
        }

    }
}

标签: c#wpf

解决方案


我相信我找到了不同行为的原因:Windows 对齐弹出窗口(主要是菜单)的方式似乎有一个系统范围的设置,专门用于触摸。您可以将其设置为左手或右手(搜索 MenuDropAlignment)。

WPF 弹出窗口似乎尊重此设置,并且以一种方式或另一种方式对齐。WPF Popup 文档中几乎没有记录这一点。

我更改了 Windows 中的设置,现在我的真实应用程序按预期运行。


推荐阅读