Search code examples
c#wpfwindows

Why my Wpf Popup is placed on the wrong side?


I make a Wpf code, which create the Popup from C# code. And I hope to place the Popup on the right side of a UserControl, but this only happens when I set popup.Placement = PlacementMode.Left; Quite strange!

Note:

  • MainWindow has a Grid called MyGrid.
  • A UserControl called MyUserControl will be embedded in MyGrid.

enter image description here

This is the UserControl xaml code:

<Grid Background="AliceBlue" Width="270" Height="100">
    <Button Width="50" 
            Height="20" 
            HorizontalAlignment="Right" 
            VerticalAlignment="Center"
            Click="TestButton_Click"/>
</Grid>

C# code as below.

  1. My idea is to transfer a parameter (MyGrid in MainWindow) to the UserControl (MyUserControl) when creating it in MainWindow.

    public partial class MyUserControl : UserControl
     {
         UIElement Parent = null;
         public delegate void TestButtonMouseClick(UIElement target);
         public static event TestButtonMouseClick ETestButtonMouseClick;
    
         public MyUserControl(UIElement parent)
         {
             InitializeComponent();
             this.Parent = parent;
         }
    
         private void TestButton_Click(object sender, RoutedEventArgs e)
         {
             ETestButtonMouseClick?.Invoke(Parent);
         }
     }
    

For the MainWindow, its xaml code is as below.

  1. This MyGrid could be anywhere in the MainWindow, and I use it as the container of the UserControl.

  2. When click the button, the delegate will transfer the paramter (MyGrid) as target of the Popup's PlacementTarget.

Finally, when I set popup.Placement = PlacementMode.Left; then as the picture shown above: the Popup appears on the right side of the UserControl. And if I set popup.Placement = PlacementMode.Right, then the Popup will appear on the left side of the UserControl. Why?

The workable demo project can be found here: https://github.com/tomxue/MyPopupIssue.git

<Grid>
    <Grid x:Name="MyGrid" 
          HorizontalAlignment="Center" 
          VerticalAlignment="Center" 
          Width="270"
          Height="100"/>
</Grid>

And its C# code behind is:

public MainWindow()
{
    InitializeComponent();
    MyUserControl userControl = new MyUserControl(MyGrid);
    MyGrid.Children.Add(userControl);
    MyUserControl.ETestButtonMouseClick += MyUserControl_ETestButtonMouseClick;
}

private void MyUserControl_ETestButtonMouseClick(UIElement target)
{
    Application.Current.Dispatcher.InvokeAsync(new Action(() =>
    {
        Popup popup = new Popup();
        popup.AllowsTransparency = true;
        popup.PlacementTarget = target;
        popup.HorizontalOffset = 10;
        popup.VerticalOffset = 41;
        popup.Placement = PlacementMode.Left;
        popup.StaysOpen = false;

        TextBlock myTextBlock = new TextBlock();
        myTextBlock.HorizontalAlignment = HorizontalAlignment.Center;
        myTextBlock.VerticalAlignment = VerticalAlignment.Center;
        myTextBlock.Width = 166;
        myTextBlock.Height = 170;
        myTextBlock.Text = "Just a test.";
        myTextBlock.FontSize = 22;
        myTextBlock.Foreground = new SolidColorBrush(Colors.Red);
        myTextBlock.Background = new SolidColorBrush(Colors.Yellow);
        popup.Child = myTextBlock;
        popup.IsOpen = true;
    }));
}

More: I tested yeaterday night at home. And just now I tested again at office. Below picture shows my issue again. And I use Visual Studio 2022 Community version. enter image description here


Solution

  • It's an issue with touch screen support. You have definitely touch screen support and "Sir Rufo" doesn't. So on touch devices Left and Right are swapped (right/left handedness support can maybe also impact the behavior).

    Workaround:

    var isTouchDev = Tablet.TabletDevices.OfType<TabletDevice>().Any(dev => dev.Type == TabletDeviceType.Touch);
    
    var popup = new Popup();
    popup.AllowsTransparency = true;
    
    popup.Placement = isTouchDev ? PlacementMode.Right : PlacementMode.Left;
    
    popup.PlacementTarget = target;
    popup.VerticalOffset = 41;
    
    popup.HorizontalOffset = isTouchDev ? -10 : 10;