Problem with hidden WPF download

Suppose you have a ToggleButton to open a Popup , the same behavior as all known elements like a 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 the code behind you work with. IsOpen for Popup and. IsChecked for ToggleButton . Everything works, but the problem occurs when you open Popup and click outside the borders. Popup will close, but ToggleButton will remain checked .

You cannot set in the PopupOnClosed handler that ToggleButton.IsChecked = false , because when you click ToggleButton to close the Popup , Popup closes, sets ToggleButton.IsChecked = false , but at that time you clicked on ToggleButton , and it tries again open Popup . Therefore, you cannot close it.

1st ToggleButtonClick:

 -> ToggleButton IsChecked = true 

2nd ToggleButtonClick:

 -> ToggleButton IsChecked = false -> ToggleButton IsChecked = true 

So, if you press the Toggle button while opening the Popup, it will start flashing, but remain open.

How would you solve this problem, please?

Edition:

Try this in MyWindow.XAML and add the IsDropDownOpen dependency property 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)); 
+4
source share
6 answers

Ok, here is some code that works for me (those that are copied from the working code with some of the uninteresting parts are removed):

Here is the contents 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 the 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"> 
+2
source

I found a solution on this post: fooobar.com/questions/579508 / ...

Using the following class will allow you to process a click before clicking the toggle button. The popup closes due to a click, but then the click is processed, so it does not trigger a 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; } } 
+2
source

You can simply bind the Popups StaysOpen property to the Buttons IsMouseOver property. This way the popup closes whenever you click anything outside the popup ( IsMouseOver = false = StaysOpen ) and it closes the popup when you click ToggleButton ( IsMouseOver = true = StaysOpen ). In this way, even clicks outside the popup will be processed.

 <ToggleButton x:Name="Toggle" /> <Popup x:Name="Popup" IsOpen="{Binding ElementName=Toggle, Path=IsChecked, Mode=TwoWay}" StaysOpen="{Binding ElementName=Toggle, Path=IsMouseOver}" /> 
+1
source

It seems to me that there are two problems - one of them is to address the problem that clicks inside the pop-up window are potentially processed again according to their position in the visual tree.

The second problem - autoclining via click - happens really every time you click outside the pop-up window and can trigger additional events. Even you press the open button to close. The problem is that you do not know what value was set earlier in popup.isOpen - because it is always false for the event handler of pressing the open button.

I do not use toggleButton to save memory, but I think the key problem is the same. ToggleButton is already false the moment you click on it.

My popup example is defined as follows:

 <Popup Placement="Bottom" PopupAnimation="Slide" Name="PART_Popup" VerticalOffset="3" AllowsTransparency="True" StaysOpen="False"> 

If you click on the allocation target — which was the “open button”, the popup closes and the button event is handled at the same time, but the popup.IsOpen property is already “false” - so it was opened again.

What I did to solve this problem was to subscribe to the Closed pop-up event, they saved time for blocking for the second time.

 DateTime? LastClose = new DateTime?(); private void Popup_Closed(object sender, EventArgs e) { LastClose = DateTime.Now; } public bool AllowReopen { get { if ((popup == null) || (popup.IsOpen)) return false; //You cannot open, when the template isn't applied or it is already open return !LastClose.HasValue || (DateTime.Now - LastClose.Value) > new TimeSpan(0,0,1) /*1s*/; } } public void OpenPopup() { if (!AllowReopen) return; popup.IsOpen = true; } 
+1
source

I would bind both guys to the same property in ViewModel. You can find a good example in the default toolbar template:

 <ToggleButton x:Name="OverflowButton" FocusVisualStyle="{x:Null}" IsEnabled="{TemplateBinding HasOverflowItems}" Style="{StaticResource ToolBarHorizontalOverflowButtonStyle}" IsChecked="{Binding Path=IsOverflowOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/> <Popup x:Name="OverflowPopup" AllowsTransparency="true" Placement="Bottom" IsOpen="{Binding Path=IsOverflowOpen,RelativeSource={RelativeSource TemplatedParent}}" StaysOpen="false" Focusable="false" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}"> <theme:SystemDropShadowChrome Name="Shdw" Color="Transparent"> <Border Background="{StaticResource ToolBarSubMenuBackground}" BorderBrush="{StaticResource ToolBarMenuBorder}" BorderThickness="1"> <ToolBarOverflowPanel x:Name="PART_ToolBarOverflowPanel" Margin="2" WrapWidth="200" Focusable="true" FocusVisualStyle="{x:Null}" KeyboardNavigation.TabNavigation="Cycle" KeyboardNavigation.DirectionalNavigation="Cycle" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Border> </theme:SystemDropShadowChrome> </Popup> 

Hope this helps,

Greetings, Anwaka.

0
source

To prevent the popup from closing by clicking on its background, insert something that fills it.

In this example, pressing a blank space closes the popup:

 <Popup x:Key="MyPop" Width="200" Height="200" StaysOpen="False"> <CheckBox Content="abc" /> </Popup> 

In this example, pressing empty space DOES NOT close the popup:

 <Popup x:Key="MyPop" Width="200" Height="200" StaysOpen="False"> <StackPanel Background="Red" Width="200" Height="200"> <!--EXTRA PANEL --> <CheckBox Content="abc" /> </StackPanel> </Popup> 
0
source

Source: https://habr.com/ru/post/1302363/


All Articles