How do I make a WPF popup appear in the lower right corner of an application?
I am using a WPF Popup control. I want it to appear inside my application window, anchored in the bottom right corner of the window. The actual height and Width of the popup will change depending on the message that is being displayed.
If it matters, the content of 开发者_C百科the popup are a Border, wrapping a StackPanel, holding multiple TextBlocks.
Thank you for any help.
Use PlacementTarget, Placement=Left, Horizontal/VerticalOffset
<Popup IsOpen="{Binding ElementName=togglebutton, Path=IsChecked, Mode=TwoWay}"
PlacementTarget="{Binding ElementName=togglebutton}"
Placement="Left"
HorizontalOffset="{Binding ActualWidth, ElementName=togglebutton}"
VerticalOffset="{Binding ActualHeight, ElementName=togglebutton}">
I just did something like this, and it's really not that tricky, but it does require custom placement of your popup. When you declare your popup just set the PlacementMode property to Custom, then set the CustomPopupPlacementCallback property to the method you want to use.
this.trayPopup.CustomPopupPlacementCallback = GetPopupPlacement;
private static CustomPopupPlacement[] GetPopupPlacement(Size popupSize, Size targetSize, Point offset)
{
var point = SystemParameters.WorkArea.BottomRight;
point.Y = point.Y - popupSize.Height;
return new[] { new CustomPopupPlacement(point, PopupPrimaryAxis.Horizontal) };
}
This is quite tricky, and there's no simple answer. On your question, you state:
The actual height and Width of the popup will change depending on the message that is being displayed.
You should have no worries, this is the default behavior of WPF Popup control.
The steps to ensure the positions you want to be are:
- Set the PlacementTarget to the application window
- The popup will be placed using relative instead of the absolute, because the starting position is always the upper left. But the exact placement is also relative to the edge of your application, this means you have to use custom placement.
For more information about using custom placement of Popup, see:
How to: Specify a Custom Popup Position
I have also been trying to do something like this as well and preferred doing things in XAML. I had problems with using Placement=Left
on multi-monitors because the popup will jump to another screen and it'll be way off in the middle. It was more reliable doing Position=Relative
and adjusting the offset using a binding to the container it will aling with.
<Popup x:Name="RightPopupContainer"
StaysOpen="False"
Placement="Relative"
PlacementTarget="{Binding ElementName=BigContainer}"
Height="{Binding ElementName=BigContainer, Path=ActualHeight}"
AllowsTransparency="True"
PopupAnimation="Fade">
<Popup.HorizontalOffset>
<MultiBinding Converter="{StaticResource SubtractionConverter}">
<MultiBinding.Bindings>
<Binding ElementName="BigContainer" Path="ActualWidth" />
<Binding ElementName="RightPopupContainer" Path="Child.ActualWidth" />
</MultiBinding.Bindings>
</MultiBinding>
</Popup.HorizontalOffset>
</Popup>
The SubtractionConverter
is a simple multibinding converter that subtracts the BigContainer.ActualWidth
from the RightPopupContainer.Child.ActualWidth
(popup always has width = 0, the child has the size). This allows it to be placed exactly to the edge of the container and it automatically updates when either container size changes.
Instead of multi-bindings, here is another option that performs the same results.
In the UserControl or Window that contains your Popup, create an event listener for LayoutUpdated
in the code-behind. In the code behind you can do logic such as:
private void UpdateElementLayouts(object sender, System.EventArgs e)
{
if (RightPopupContainer?.IsOpen == true && RightPopupContainer.Child is UserControl content)
{
RightPopupContainer.HorizontalOffset = BigContainer.ActualWidth - content.ActualWidth;
}
}
精彩评论