Reputation: 2575
The Popup
control is left-aligned by default. Its left edge is aligned with the left edge of its parent.
What I would like to do is to have the control right-aligned so that its right edge is aligned with the right edge of its container.
I want this to be dynamic because I dynamically bind the data and I don't know how big the popup will be.
I tried playing with the Opened
, SizeChanged
and Loaded
event to get the Child
's width and set it to the HorizontalOffset
but there seems to be timing issues. Basically it works fine the first time the control is loaded and then never after (the HorizontalOffset
is set to 0).
Is this a bug? Am I doing it the wrong way?
EDIT I got it working. It seems that there are timing issues. If I hook up the Opened
event and set the HorizontalOffset
asynchronously using the Dispatcher
, then it works :(
private static void OnPopupOpened(object sender, System.EventArgs e)
{
var popup = (Popup)sender;
popup.Dispatcher.BeginInvoke(() => popup.HorizontalOffset = -popup.ActualWidth);
}
EDIT 2 I now realise that I was doing something stupid. I wanted the Popup
of the ComboBox
to be right-aligned. I didn't see that it was reinitialized in the ArrangePopup
private method call.
I tried inheriting from ComboBox
to override the placement function but I must be doing something wrong because it still doesn't seem to work although I overrode the methods that call ArrangePopup
Cheers.
Upvotes: 3
Views: 7318
Reputation: 301
What you can do is use MS Expression Blend to generate the default template for a ComboBox. In the template you will find a Popup named Popup, change it's FlowDirection attribute to RightToLeft...
<Popup x:Name="Popup" FlowDirection="RightToLeft">
Note the ScrollViewer object inside the Popup will inherit the FlowDirection set so you have to explicitly set its FlowDirection to LeftToRight...
<ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1" FlowDirection="LeftToRight">
...else it will fill from RightToLeft and the scrollbar will be on the left hand side.
Upvotes: 0
Reputation: 2575
I now realize that if I don't answer to my own question no one will be able to mark my work-around as an answer. So here's the full code. I implemented it as a PRISM behavior.
public static class PopupRightAlignBehavior
{
public static readonly DependencyProperty InstanceProperty =
DependencyProperty.RegisterAttached("Instance", typeof(object), typeof(PopupRightAlignBehavior), new PropertyMetadata(OnSetInstanceCallback));
public static object GetInstance(DependencyObject obj)
{
return (object)obj.GetValue(InstanceProperty);
}
public static void SetInstance(DependencyObject obj, object value)
{
obj.SetValue(InstanceProperty, value);
}
private static void OnSetInstanceCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var popup = (Popup)d;
popup.Opened -= OnPopupOpened;
popup.Opened += OnPopupOpened;
}
private static void OnPopupOpened(object sender, System.EventArgs e)
{
var popup = (Popup)sender;
popup.Dispatcher.BeginInvoke(() => popup.HorizontalOffset = -popup.ActualWidth);
}
}
Upvotes: 3