I've got two controls, a TextBlock and a PopUp. When the user clicks (MouseDown) on the textblock, I want to display the popup. I would think that I could do this with an EventTrigger on the Popup, but I can't use setters in an EventTrigger, I can only start storyboards. I want to do this strictly in XAML, because the two controls are in a template and I don't know how I'd find the popup in code.
This is what conceptually I want to do, but can't because you can't put a setter in an EventTrigger (like you can with a DataTrigger):
<TextBlock x:Name="CCD">Some text</TextBlock>
<Popup>
<Popup.Style>
<Style>
<Style.Triggers>
<EventTrigger SourceName="CCD" RoutedEvent="MouseDown">
<Setter Property="Popup.IsOpen" Value="True" />
</EventTrigger>
</Style.Triggers>
</Style>
</Popup.Style>
...
What is the best way to show a popup strictly in XAML when an event happens on a different control?
I did something simple, but it works.
I used a typical ToggleButton, which I restyled as a textblock by changing its control template. Then I just bound the IsChecked property on the ToggleButton to the IsOpen property on the popup. Popup has some properties like StaysOpen that let you modify the closing behavior.
The following works in XamlPad.
I had some issues with the MouseDown part of this, but here is some code that might get your started.
another way to do it:
The following approach is the same as Helge Klein's, except that the popup closes automatically when you click anywhere outside the Popup (including the ToggleButton itself):
"BoolInverter" is used in the IsHitTestVisible binding so that when you click the ToggleButton again, the popup closes:
...which shows the handy technique of combining IValueConverter and MarkupExtension in one.
I did discover one problem with this technique: WPF is buggy when two popups are on the screen at the same time. Specifically, if your toggle button is on the "overflow popup" in a toolbar, then there will be two popups open after you click it. You may then find that the second popup (your popup) will stay open when you click anywhere else on your window. At that point, closing the popup is difficult. The user cannot click the ToggleButton again to close the popup because IsHitTestVisible is false because the popup is open! In my app I had to use a few hacks to mitigate this problem, such as the following test on the main window, which says (in the voice of Louis Black) "if the popup is open and the user clicks somewhere outside the popup, close the friggin' popup.":
The following uses
EventTrigger
to show thePopup
. This means we don't need aToggleButton
for state binding. In this example theClick
event of aButton
is used. You can adapt it to use another element/event combination.Please note that the
Popup
is referencing theButton
by name and vice versa. Sox:Name="..."
is required on both, thePopup
and theButton
.It can actually be further simplified by replacing the
Storyboard
stuff with a customSetProperty
EventTrigger Action described in this SO Answer