2010-02-25 6 views
4

Supposons que vous ayez un ToggleButton pour ouvrir un Popup, même comportement que tous les éléments connus comme ComboBox etc.WPF problème Popup cachette

... qui est ce 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> 

Puis dans le code derrière vous travaillez avec . IsOpen pour Popup et. IsChecked pour ToggleButton. Tout fonctionne, mais le problème arrive lorsque vous ouvrez le Popup et cliquez en dehors des frontières. Le Popup sera fermé mais le ToggleButtonsera vérifié.

Vous ne pouvez pas définir dans le gestionnaire PopupOnClosed que ToggleButton.IsChecked = false, parce que lorsque vous cliquez sur le ToggleButton pour fermer la Popup, le Popup se ferme, définit ToggleButton.IsChecked = false mais au moment de Sime vous avez cliqué sur le ToggleButton et essaie d'ouvrir le à nouveau. Donc vous ne pouvez pas le fermer.

1er ToggleButtonClick:

-> ToggleButton IsChecked = true 

2ème ToggleButtonClick:

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

Donc, si vous cliquez sur le bouton à bascule en Popup étant ouvert, il clignote, mais reste ouvert.

Comment pourriez-vous résoudre ce problème, s'il vous plaît?

ÉDITÉE:

Essayez ceci dans un MyWindow.XAML et ajouter la propriété de dépendance IsDropDownOpen dans le code derrière, s'il vous plaît:

<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)); 
+0

Prenez un coup d'oeil à: http://stackoverflow.com/questions/13687463/wpf-popup-staysopen-false-still-keep-the-popup-open-while-clicking-outside – SepehrM

Répondre

0

Je lierait les deux gars à la même propriété le ViewModel. Vous pouvez trouver bon exemple dans le modèle par défaut Boîte à outils:

<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,

Cheers, Anvaka.

+0

J'ai déjà essayé ceci approche et le problème est le suivant: 1er ToggleButtonClick: >> ToggleButton IsChecked = true ------ 2md ToggleButtonClick: >> ToggleButton IsChecked = false >> ToggleButton IsChecked = true ----- - Donc, si vous cliquez sur le bouton bascule alors que Popup est ouvert, il clignote mais reste ouvert. –

2

Ok, voici un code qui fonctionne pour moi (ceux-ci sont le code empâtée copie de travailler avec quelques-unes des pièces non-intéressantes enlevés):

Voici le contenu d'un UserControl comme ComboBox:

<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> 

Et à partir d'un modèle personnalisé à un ComboBox réelle:

<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"> 
+1

Oh bien ... et le mystère a été révélé. ClickMode = "Press" était la propriété qui le fait fonctionner! Je vous remercie ! –

+1

J'ai encore 1 question: Comment vous assurer que le popup est fermé automatiquement en cliquant dehors, ou en déplaçant toute la fenêtre? –

+0

Salut @ PaN1C_Showt1Me, Comment avez-vous résolu ce problème à la fin? En utilisant la solution ci-dessus "ClickMode = Press", je vois le même problème que vous faites à propos du Popup restant ouvert en cliquant à l'extérieur? – HipsterZipster

2

J'ai trouvé la solution sur ce post: https://stackoverflow.com/a/5821819/651161

L'utilisation de la classe suivante permettra de gérer le clic avant que le bouton bascule soit enfoncé. La fenêtre contextuelle est fermée en raison du clic, mais le clic est alors géré, de sorte qu'il ne déclenche pas le clic ToggleButton.

public class MyPopup : Popup { 
    protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) { 
     bool isOpen = this.IsOpen; 
     base.OnPreviewMouseLeftButtonDown(e); 

     if (isOpen && !this.IsOpen) 
      e.Handled = true; 
    } 
} 
+0

Cela a finalement résolu mon problème et est la solution la plus simple que je pense. –

+0

Ne fonctionne pas pour moi. –

1

Vous pouvez simplement lier la propriété popups StaysOpen aux boutons IsMouseOver propriété. De cette façon, le popup se fermera chaque fois que vous cliquerez sur quelque chose en dehors du popup (IsMouseOver = false = StaysOpen) et il fermera le popup en cliquant sur le ToggleButton (IsMouseOver = true = StaysOpen). De cette façon, même les clics en dehors du popup seront traités.

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

Cela a fonctionné pour moi quand aucun des autres correctifs ne fonctionnerait. –

1

Il me semble, il y a deux problèmes - on est à adresse le problème, qui clique dans le menu contextuel sont potentiellement à nouveau traitées en fonction de c'est la position dans l'arbre visuel.

Le deuxième problème est - autoclose via clic - arrive vraiment chaque fois que vous cliquez en dehors de la fenêtre contextuelle et peut déclencher des événements supplémentaires. Même vous cliquez sur le "bouton d'ouverture" pour fermer. Le problème est - vous ne savez pas quelle valeur a été définie auparavant sur popup.isOpen - car elle est toujours fausse pour le gestionnaire d'événement click du bouton d'ouverture.

Je n'utilise pas de toggleButton pour économiser de la mémoire, mais je pense que le problème principal est le même. Le toggleButton est déjà faux au moment où vous cliquez dessus.

Mon exemple pop-up est défini comme:

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

Si vous cliquez sur la cible de placement - qui était le « bouton d'ouverture » les ferme popup et en même temps l'événement de clic du bouton a été traité mais la propriété popup.IsOpen était déjà 'false' - elle a donc été rouverte à nouveau. Ce que j'ai fait pour résoudre ce problème était de souscrire aux popups "Closed" event, qui a sauvé le temps de réouverture du bloc pendant une seconde.

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; 
} 
0

Pour éviter la fermeture de la Popup en cliquant sur son arrière-plan, insérez quelque chose qui va le remplir.

Dans cet exemple, en cliquant sur l'espace non rempli fermera Popup:

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

Dans cet exemple, en cliquant sur l'espace non rempli ne se ferme pas 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>