Consider the following code-behind for displaying a child window after clicking a button in the Main Window. The desired result is to have the child window placement show up just to the right of the menu button, in-line with the top of the menu button. (So the window shows right next to the control that activated it.)
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();
}
The code as presented does work in the fashion needed, however I don't like using hard-coded values or magic numbers in code.
If you comment out the line with the hard-coded control width value (50) and un-comment the line using the button's width property, subsequent execution results in the menu window displaying in a sequence of locations that defy logic. It appears that it is getting a value from a random number generator rather than the control's width. I do see a pattern when its run several times, but getting 4 or 5 different locations because of a variation in property value responses each time the code is executed is quite frustrating.
What would be the RIGHT or correct approach here? How do I get a reliable value back from a WPF control property or am I asking too much?
XAML of Main 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 of Menu2 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>```
CodePudding user response:
Since you don't explicitly set the width of btnMenu2
, the value of its Width
property will be double.NaN
. Note that the Width
value is not the actual width, but the requested width. Use the ActualWidth
proeprty instead:
menu2.Left = scnLocation.X btnMenu2.ActualWidth;
CodePudding user response:
What about using Popup instead? You can put all you want on a Popup control instead of a window and set its StaysOpen property to true to make the user close it automatically through close button or whatever.