c# - 是什么让我的 WPF 弹出窗口与其 PlacementTarget 的右边缘对齐?
问题描述
我试图理解为什么我的 WPF 弹出窗口似乎与其 PlacementTarget 的右边缘对齐:
通常,弹出窗口应与左侧对齐。
这是在一个更大的项目中,我用大量的代码、样式等进行了交互。我试图简化并提取一个示例,并且 - 令我惊讶的是 - 如果它在另一个空白的单独应用程序中运行,那么它会正确对齐:
我已经搜索了要排除的代码:
- 代码或资源中的任何地方都没有 HorizontalOffset
- 代码或资源中的任何地方都没有 FlowDirection="RightToLeft"
我几乎尝试从项目中删除所有 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;
}
}
}
}
解决方案
我相信我找到了不同行为的原因:Windows 对齐弹出窗口(主要是菜单)的方式似乎有一个系统范围的设置,专门用于触摸。您可以将其设置为左手或右手(搜索 MenuDropAlignment)。
WPF 弹出窗口似乎尊重此设置,并且以一种方式或另一种方式对齐。WPF Popup 文档中几乎没有记录这一点。
我更改了 Windows 中的设置,现在我的真实应用程序按预期运行。
推荐阅读
- excel - 使用 for 循环在 excel 中创建运行总计
- google-analytics-api - 开发 Google Analytics Reporting API v4 错误:JsonParseException: Unexpected character ((CTRL-CHAR, code 130))
- java - JavaFX 按钮操作未访问 ListView 选定项
- windows - 如何将 WiFi 网络适配器添加到 VMware 播放器上的虚拟 Windows 10
- linux - 在文件上使用粘贴命令并将结果保存到同一文件
- c# - Entity Framework Core - 附加条件 where 子句
- python - 从曲线创建距离矩阵
- javascript - 有没有更快的方法来隐藏/显示 html 元素?
- javascript - 字符串不替换单词
- javascript - 关键事件在 Chrome 中有效,但在 Internet Explorer 11 中无效