none
Popup tracking position of PlacementTarget

    Question

  • If the UIElement that I've assigned to be a Popups PlacementTarget moves, the Popup itself doesn't move. Is there an easy way to make this work. The code below shows the problem - if you expand the Expander, the TextBox moves down but the Popup doesn't.
    <Window
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="WpfApplication3.MainWindow"
      x:Name="Window"
      Title="MainWindow"
      Width="640" Height="480">
      <StackPanel>
        <Expander Header="Test">
          <Rectangle Fill="Orange" Height="100"/>
        </Expander>
        <TextBox Name="_TheText">This is Some Text</TextBox>
        <Popup IsOpen="True" Placement="Bottom" PlacementTarget="{Binding ElementName=_TheText}">
          <Border Background="Green">
            <TextBlock>This is a Popup</TextBlock>
          </Border>
        </Popup> 
      </StackPanel>
    </Window>
    Friday, April 03, 2009 9:01 PM

Answers

  • One trick to solve this problem is to modify the PlacementRectangle of PopUp slightly and do not influence the layout.

    Below is a simple demo that show this trick. There are two factors that might change the position of PopUp: the movement of Window and the Visibility of Rectangle. I applied a method called ResetPopUp in the Window_LocationChanged and Rectangle_LayoutUpdated events. A random double number is used to force WPF re-layout the PopUp.

    Hope it helps.

    XAML
    <Window x:Class="_temple.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            LocationChanged="Window_LocationChanged"
            Loaded="Window_Loaded"
        Title="Window1" Height="300" Width="300">
        <StackPanel>
            <Expander   Header="Test"  >
                <Rectangle LayoutUpdated="Rectangle_LayoutUpdated" Fill="Orange" Height="100"/>
            </Expander>
            <TextBox   Width="200" Height="25" Name="_TheText">This is Some Text</TextBox>
            <Popup Name="MyPopUp" IsOpen="True" Placement="Bottom" PlacementTarget="{Binding ElementName=_TheText}">
                <Border Background="Green">
                    <TextBlock>This is a Popup</TextBlock>
                </Border>
            </Popup>
        </StackPanel>
    </Window>
    


    C#
    using System;
    using System.Windows;
    namespace _temple
    {
        /// <summary>
        /// Interaction logic for Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            public Point StartPoint = new Point(0, 0);
            public Point EndPoint = new Point(0, 0);
            public Window1()
            {
                InitializeComponent();
            }
            public void ResetPopUp()
            {
                Random random = new Random(); 
                MyPopUp.PlacementRectangle = new Rect(new Point(random.NextDouble() / 1000, 0), new Size(75, 25));
            }
            private void Window_LocationChanged(object sender, EventArgs e)
            {
                ResetPopUp();
            }
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                StartPoint = _TheText.PointToScreen(new Point(0, 0));
            }
            private void Rectangle_LayoutUpdated(object sender, EventArgs e)
            {
                ResetPopUp();
            }
        }
    }
    

    • Proposed as answer by Tao Liang Wednesday, April 08, 2009 9:02 AM
    • Marked as answer by John Dunn Wednesday, April 08, 2009 4:40 PM
    Wednesday, April 08, 2009 9:01 AM

All replies

  • One trick to solve this problem is to modify the PlacementRectangle of PopUp slightly and do not influence the layout.

    Below is a simple demo that show this trick. There are two factors that might change the position of PopUp: the movement of Window and the Visibility of Rectangle. I applied a method called ResetPopUp in the Window_LocationChanged and Rectangle_LayoutUpdated events. A random double number is used to force WPF re-layout the PopUp.

    Hope it helps.

    XAML
    <Window x:Class="_temple.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            LocationChanged="Window_LocationChanged"
            Loaded="Window_Loaded"
        Title="Window1" Height="300" Width="300">
        <StackPanel>
            <Expander   Header="Test"  >
                <Rectangle LayoutUpdated="Rectangle_LayoutUpdated" Fill="Orange" Height="100"/>
            </Expander>
            <TextBox   Width="200" Height="25" Name="_TheText">This is Some Text</TextBox>
            <Popup Name="MyPopUp" IsOpen="True" Placement="Bottom" PlacementTarget="{Binding ElementName=_TheText}">
                <Border Background="Green">
                    <TextBlock>This is a Popup</TextBlock>
                </Border>
            </Popup>
        </StackPanel>
    </Window>
    


    C#
    using System;
    using System.Windows;
    namespace _temple
    {
        /// <summary>
        /// Interaction logic for Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            public Point StartPoint = new Point(0, 0);
            public Point EndPoint = new Point(0, 0);
            public Window1()
            {
                InitializeComponent();
            }
            public void ResetPopUp()
            {
                Random random = new Random(); 
                MyPopUp.PlacementRectangle = new Rect(new Point(random.NextDouble() / 1000, 0), new Size(75, 25));
            }
            private void Window_LocationChanged(object sender, EventArgs e)
            {
                ResetPopUp();
            }
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                StartPoint = _TheText.PointToScreen(new Point(0, 0));
            }
            private void Rectangle_LayoutUpdated(object sender, EventArgs e)
            {
                ResetPopUp();
            }
        }
    }
    

    • Proposed as answer by Tao Liang Wednesday, April 08, 2009 9:02 AM
    • Marked as answer by John Dunn Wednesday, April 08, 2009 4:40 PM
    Wednesday, April 08, 2009 9:01 AM
  • Thanks, that worked perfectly.

    Wednesday, April 08, 2009 4:40 PM
  • hi Tao Liang,

    why this Same issue apply  on user control .  i am not getting  
    Window_LocationChanged event in User Control. 
    


    aniruddha

    Thursday, October 11, 2012 9:55 AM