如何在 WPF 中正确定位控件 window
How to correctly locate a control in a WPF window
考虑以下用于在单击 Main Window 中的按钮后显示子项 window 的代码隐藏。期望的结果是让子 window 位置显示在菜单按钮的右侧,与菜单按钮的顶部对齐。 (因此 window 显示在激活它的控件旁边。)
private void btnMenu2_Click(object sender, RoutedEventArgs e)
{
var menu2 = new Menu2Window();
//var winLocation = this.btnMenu2.TranslatePoint(new Point(0, 0), Application.Current.MainWindow);
//var winLocation = this.btnMenu2.TranslatePoint(new Point(0, 0), this.spLeftMenu);
//var winLocation = this.spLeftMenu.TranslatePoint(new Point(0, 0), this.btnMenu2);
var objLocation = this.spLeftMenu.TranslatePoint(new Point(0, 0), this.spLeftMenu);
var scnLocation = this.btnMenu2.PointToScreen(objLocation);
//menu2.Left = scnLocation.X + btnMenu2.Width;
menu2.Left = scnLocation.X + 50; // <- Why does this work but using btnMenu2.Width causes placement to be all over the place???
menu2.Top = scnLocation.Y;
menu2.ShowDialog();
}
所提供的代码确实以所需的方式工作,但我不喜欢在代码中使用硬编码值或幻数。
如果您注释掉带有硬编码控件宽度值 (50) 的行并使用按钮的宽度 属性 取消注释该行,则后续执行会导致菜单 window 显示在一系列违反逻辑的位置中。它似乎是从随机数生成器而不是控件的宽度获取值。当它 运行 几次时,我确实看到了一个模式,但是由于每次执行代码时 属性 值响应的变化而得到 4 或 5 个不同的位置是非常令人沮丧的。
这里正确或正确的方法是什么?如何从 WPF 控件返回可靠的值 属性 还是我要求太多?
XAML 主 Window:
<Window x:Class="LocateTest.MainWindow"
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"
xmlns:local="clr-namespace:LocateTest"
mc:Ignorable="d"
Background="DarkGray"
Title="MainWindow" Height="400" Width="750">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel x:Name="spLeftMenu"
DataContext="MainWindow"
Orientation="Vertical"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Height="325" Width="50">
<Button Content="B1" Height="50" Width="50"/>
<Button x:Name="btnMenu2"
Content="B2"
Height="50"
Click="btnMenu2_Click"/>
<Button Content="B3" Height="50"/>
</StackPanel>
</Grid>
</Window>
XAML 菜单 2 window:
<Window x:Class="LocateTest.Menu2Window"
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"
xmlns:local="clr-namespace:LocateTest"
mc:Ignorable="d"
WindowStyle="None"
AllowsTransparency="True"
WindowStartupLocation="Manual"
Height="150" Width="280">
<Window.Background>
<SolidColorBrush Opacity="0.5" Color="Black"></SolidColorBrush>
</Window.Background>
<Grid>
<Button x:Name="btnClose"
Click="btnClose_Click"
Width="25"
Height="25"
Content="X"
Background="Black"
Foreground="Red" Margin="245,10,10,115">
</Button>
</Grid>
</Window>```
改用 Popup 怎么样?您可以将您想要的所有内容放在 Popup 控件上而不是 window 并将其 StaysOpen 属性 设置为 true 以使用户通过关闭按钮或其他方式自动关闭它。
由于您没有明确设置 btnMenu2
的宽度,因此其 Width
属性 的值将是 double.NaN
。请注意,Width
值不是实际宽度,而是请求的宽度。请改用 ActualWidth
属性:
menu2.Left = scnLocation.X + btnMenu2.ActualWidth;
考虑以下用于在单击 Main Window 中的按钮后显示子项 window 的代码隐藏。期望的结果是让子 window 位置显示在菜单按钮的右侧,与菜单按钮的顶部对齐。 (因此 window 显示在激活它的控件旁边。)
private void btnMenu2_Click(object sender, RoutedEventArgs e)
{
var menu2 = new Menu2Window();
//var winLocation = this.btnMenu2.TranslatePoint(new Point(0, 0), Application.Current.MainWindow);
//var winLocation = this.btnMenu2.TranslatePoint(new Point(0, 0), this.spLeftMenu);
//var winLocation = this.spLeftMenu.TranslatePoint(new Point(0, 0), this.btnMenu2);
var objLocation = this.spLeftMenu.TranslatePoint(new Point(0, 0), this.spLeftMenu);
var scnLocation = this.btnMenu2.PointToScreen(objLocation);
//menu2.Left = scnLocation.X + btnMenu2.Width;
menu2.Left = scnLocation.X + 50; // <- Why does this work but using btnMenu2.Width causes placement to be all over the place???
menu2.Top = scnLocation.Y;
menu2.ShowDialog();
}
所提供的代码确实以所需的方式工作,但我不喜欢在代码中使用硬编码值或幻数。
如果您注释掉带有硬编码控件宽度值 (50) 的行并使用按钮的宽度 属性 取消注释该行,则后续执行会导致菜单 window 显示在一系列违反逻辑的位置中。它似乎是从随机数生成器而不是控件的宽度获取值。当它 运行 几次时,我确实看到了一个模式,但是由于每次执行代码时 属性 值响应的变化而得到 4 或 5 个不同的位置是非常令人沮丧的。
这里正确或正确的方法是什么?如何从 WPF 控件返回可靠的值 属性 还是我要求太多?
XAML 主 Window:
<Window x:Class="LocateTest.MainWindow"
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"
xmlns:local="clr-namespace:LocateTest"
mc:Ignorable="d"
Background="DarkGray"
Title="MainWindow" Height="400" Width="750">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel x:Name="spLeftMenu"
DataContext="MainWindow"
Orientation="Vertical"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Height="325" Width="50">
<Button Content="B1" Height="50" Width="50"/>
<Button x:Name="btnMenu2"
Content="B2"
Height="50"
Click="btnMenu2_Click"/>
<Button Content="B3" Height="50"/>
</StackPanel>
</Grid>
</Window>
XAML 菜单 2 window:
<Window x:Class="LocateTest.Menu2Window"
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"
xmlns:local="clr-namespace:LocateTest"
mc:Ignorable="d"
WindowStyle="None"
AllowsTransparency="True"
WindowStartupLocation="Manual"
Height="150" Width="280">
<Window.Background>
<SolidColorBrush Opacity="0.5" Color="Black"></SolidColorBrush>
</Window.Background>
<Grid>
<Button x:Name="btnClose"
Click="btnClose_Click"
Width="25"
Height="25"
Content="X"
Background="Black"
Foreground="Red" Margin="245,10,10,115">
</Button>
</Grid>
</Window>```
改用 Popup 怎么样?您可以将您想要的所有内容放在 Popup 控件上而不是 window 并将其 StaysOpen 属性 设置为 true 以使用户通过关闭按钮或其他方式自动关闭它。
由于您没有明确设置 btnMenu2
的宽度,因此其 Width
属性 的值将是 double.NaN
。请注意,Width
值不是实际宽度,而是请求的宽度。请改用 ActualWidth
属性:
menu2.Left = scnLocation.X + btnMenu2.ActualWidth;