I am trying to understand why my WPF popup appears to align to the right edge of its PlacementTarget:
Normally, a popup would be expected to align to the left side.
This is in a larger project I interited with lots of code, styles, etc. I have tried to simplify and extract an example and - to my surprise - if that runs in an otherwise blank separate application, then it aligns correctly:
I have searched through the code to exclude:
- there is no HorizontalOffset anywhere in the code or resources
- there is no FlowDirection="RightToLeft" anywhere in the code or resources
I pretty much tried to remove all ResourceDictionaries from the project except for those where the project would not even build or start.
I also investigated the popup via snoop and it has the correct placement target, no offset and the correct placement.
I am lost here. Any theory of what could cause this?
Here is the example code (which may look a little complicated, since the original code has this as a user control):
<Window x:Class="PopupIssue.client.Window1"
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"
mc:Ignorable="d"
Title="Window1" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="3" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical">
<Border Background="Blue" Height="40"/>
<Button x:Name="DropdownParent" Click="Button_OnClick" Focusable="True" KeyboardNavigation.AcceptsReturn="False" >
<Button.Template>
<ControlTemplate TargetType="Button">
<StackPanel>
<Border Margin="2" Background="AliceBlue">
<Grid x:Name="DropdownMain" >
<!-- Background="#FFE3E8EA">-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20" MaxWidth="20" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Grid.ColumnSpan="2">
<TextBlock Text="" />
</Border>
<Border Grid.Column="1" Margin="2" Padding="5" Background="LightSalmon">
<Path x:Name="Arrow" Fill="Gray" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M 0 0 L 4 4 L 8 0 Z" />
</Border>
</Grid>
</Border>
<Popup Placement="Bottom" IsOpen="{Binding ShowPopup}" PlacementTarget="{Binding ElementName=DropdownParent}" PopupAnimation="Fade" StaysOpen="True" MinWidth="{Binding ActualWidth, ElementName=DropdownParent}" Closed="Popup_OnClosed" Opened="Popup_OnOpened" KeyDown="Popup_OnKeyDown">
<Border Background="White" Padding="5,2,5,2" BorderBrush="Red" BorderThickness="1">
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="Margin" Value="0,10,0,0"/>
</Style>
</StackPanel.Resources>
<RadioButton Content="Lorem Ipsum Dolor Ahmed Quid Prio" GroupName="rbGroup" ></RadioButton>
<RadioButton Content="Lorem Ipsum Dolor Ahmed Quid Prio" GroupName="rbGroup" ></RadioButton>
<RadioButton Content="Lorem Ipsum Dolor Ahmed Quid Prio" GroupName="rbGroup" ></RadioButton>
<RadioButton Content="Lorem Ipsum Dolor Ahmed Quid Prio" GroupName="rbGroup" ></RadioButton>
<RadioButton Content="Lorem Ipsum Dolor Ahmed Quid Prio" GroupName="rbGroup" ></RadioButton>
</StackPanel>
</Border>
</Popup>
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
<Border Background="Blue" Height="40"/>
</StackPanel>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<Border Background="Beige" Grid.Column="2" />
</Grid>
</Window>
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Threading;
namespace PopupIssue.client
{
/// <summary>
/// Interaktionslogik für Window1.xaml
/// </summary>
public partial class Window1 : Window, INotifyPropertyChanged
{
public Window1()
{
this.DataContext = this;
InitializeComponent();
}
private bool showPopup;
public bool ShowPopup { get => showPopup; set { showPopup = value; NotifyPropertyChanged("ShowPopup"); } }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
private DateTime lastClosed = DateTime.MinValue;
private void Popup_OnClosed(object sender, EventArgs e)
{
lastClosed = DateTime.Now;
var tmp = OnPopupClosed;
if (tmp != null)
tmp(this, new EventArgs());
Action a = () => this.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
Dispatcher.BeginInvoke(DispatcherPriority.Background, a);
}
public event EventHandler<EventArgs> OnPopupClosed;
public event EventHandler<EventArgs> OnPopupOpened;
private void Button_OnClick(object sender, RoutedEventArgs e)
{
// When button is clicked while the popup is already open, then the popup is closed automatically by the system before this event handler.
// So when this method is executed, the popup is always closed.
// However if the user clicked the button while the popup was open, then he expects the popup to close (which the system does automatically) and not to immediately re-open.
// The only viable way is to check if the popup closed immediately (<200 ms) before the click and not open the popup then
var millisSinceClose = (DateTime.Now - lastClosed).TotalMilliseconds;
if (millisSinceClose > 200)
ShowPopup = true;
}
private void Popup_OnOpened(object sender, EventArgs e)
{
var f = Content as FrameworkElement;
if (f != null)
{
Action a = () => f.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
Dispatcher.BeginInvoke(DispatcherPriority.Background, a);
var tmp = OnPopupOpened;
if (tmp != null)
tmp(this, new EventArgs());
}
}
private void Popup_OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
((Popup)sender).IsOpen = false;
e.Handled = true;
}
}
}
}


Placement=Bottomand Placement Target toDropdownParentand it is showing like that . so what's wrong ?<ColumnDefinition Width="80" />you have set basically width ofDropdownParentparent to 80 and now popup not finding enough space to be completely left aligned and it's overflowing it ..HorizontalOffsetto manually show it like you want.