Suppose you have a ToggleButton
for opening a Popup
, same behaviour as all known elements as ComboBox
etc.
... which is this code:
<ToggleButton x:Name="PART_OpenToggleButton"
Focusable="False"
IsChecked="False"
Template="{StaticResource MyToggleButton}">
<Grid>
<Popup x:Name="PART_PopupControl"
Style="{StaticResource MyPopupStyle}"
StaysOpen="False"
VerticalAlignment="Bottom"
IsOpen="False"
PlacementTarget="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ToggleButton, AncestorLevel=1}}" />
</Grid>
</ToggleButton>
Then in code behind you work with .IsOpen
for Popup
and .IsChecked
for ToggleButton
.
Everything works, but the problem arrives when you Open the Popup
and click outside the borders.
The Popup
will be closed but the ToggleButton
stays checked.
You cannot set in the PopupOnClosed
Handler that ToggleButton.IsChecked = false
, because when you Click on the ToggleButton
to close the Popup
, the Popup
closes itself, sets ToggleButton.IsChecked = false
but at the sime time you clicked on the ToggleButton
and it tries to Open the Popup
again. So you cannot close it.
1st ToggleButtonClick:
-> ToggleButton IsChecked = true
2nd ToggleButtonClick:
-> ToggleButton IsChecked = false
-> ToggleButton IsChecked = true
So if you click on the Toggle Button while Popup being open, it blinks but stays open.
How would you solve this problem, please ?
EDITED:
Try this in a MyWindow.XAML and add the dependency property IsDropDownOpen in the code behind, please:
<Grid>
<ToggleButton x:Name="PART_OpenToggleButton"
Focusable="False"
Height="20"
Width="50"
IsChecked="{Binding ElementName=TestWindow, Mode=TwoWay, Path=IsDropDownOpen}">
<Grid>
<Popup x:Name="PART_PopupControl"
Width="100"
Height="100"
StaysOpen="False"
Focusable="False"
VerticalAlignment="Bottom"
IsOpen="{Binding ElementName=TestWindow, Path=IsDropDownOpen}"
PlacementTarget="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ToggleButton, AncestorLevel=1}}">
</Popup>
</Grid>
</ToggleButton>
</Grid>
public bool IsDropDownOpen
{
get { return (bool)GetValue(IsDropDownOpenProperty); }
set { SetValue(IsDropDownOpenProperty, value); }
}
public static readonly DependencyProperty IsDropDownOpenProperty =
DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(Window), new UIPropertyMetadata(false));
I found the solution on this post : https://stackoverflow.com/a/5821819/651161
Using the following class will permit to handle the click before the togglebutton is pressed. The popup is closed because of the click but the click is then handled, so it doesn't trigger the ToggleButton click.
public class MyPopup : Popup {
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) {
bool isOpen = this.IsOpen;
base.OnPreviewMouseLeftButtonDown(e);
if (isOpen && !this.IsOpen)
e.Handled = true;
}
}
Ok, here is some code that works for me (those are copy-pasted from working code with some of the not-interesting parts removed):
Here's the content of a ComboBox-like UserControl:
<ToggleButton x:Name="Button" Height="19">
<Grid>
<Label Name="DisplayList" Content="Whatever" />
<Popup Name="SelectionPopup" MinHeight="100" MinWidth="200"
StaysOpen="False" IsOpen="{Binding IsChecked, ElementName=Button}">
</Popup>
</Grid>
</ToggleButton>
And from a custom template to an actual ComboBox:
<ToggleButton
Name="ToggleButton"
Template="{StaticResource ComboBoxToggleButton}"
Grid.Column="2"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
</ToggleButton>
<Popup
Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With