Redgum
Redgum

Reputation: 398

How to correctly locate a control in a WPF window

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>```

Upvotes: 0

Views: 105

Answers (2)

Ahmed Alayat
Ahmed Alayat

Reputation: 182

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.

Upvotes: 0

Pharaz Fadaei
Pharaz Fadaei

Reputation: 1827

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;

Upvotes: 1

Related Questions