2016-11-01 1 views
0

Comme sujet mentionné.Je veux utiliser une seule popup pour tous les boutons de mon application.Je ne sais pas comment obtenir ce que je veux. Voici ce que ma fenêtre ressemble:Un popup pour tous les boutons

enter image description here

Info 1:

enter image description here

Info 2:

enter image description here

Vous pouvez voir apparaître popup sur la mauvaise position.Je sais que je peux positionner un popup en réglant le PlacementTarget.But chaque Popup a une valeur différente pour la propriété de placement.C'est le problème.Je cherche une autre façon de le faire.

Voici une fenêtre contextuelle pour l'option 1:

<StackPanel Orientation="Horizontal"> 
<!--Option 1: text and button--> 
<TextBlock Text="Option 1" 
    Margin="10" 
    VerticalAlignment="Center" /> 
<Popup x:Name="popInfo" 
    PlacementTarget="{Binding ElementName=btnInfoOption1}" 
    IsOpen="{Binding IsShowInfo1}"> 
    <ContentControl Style="{StaticResource ContentInfoStyle}"> 
    <TextBlock Text="{Binding InfoContent}" 
     TextWrapping="Wrap" 
     Foreground="White" 
     Width="340" 
     Padding="10" 
     Margin="30,0,30,5" 
     FontSize="15" /> 
    </ContentControl> 
</Popup> 

<Button x:Name="btnInfoOption1" 
    Style="{StaticResource btnIcons}" 
    Background="#0063b1" 
    Width="30" 
    Height="30" 
    Margin="10,10,20,10" 
    Command="{Binding CmdShowInfo, Delay=1500}" 
    Tag="{StaticResource ic_ginfo}" /> 
</StackPanel> 

pop-up pour l'option 2:

<StackPanel Orientation="Horizontal"> 
<!--Option 2: text and button--> 
<TextBlock Text="Option 2" 
    Margin="10" 
    VerticalAlignment="Center" /> 
    <Button x:Name="btnOption2" 
    Style="{StaticResource btnIcons}" 
    Background="#0063b1" 
    Width="30" 
    Height="30" 
    Margin="10,10,20,10" 
    Command="{Binding CmdShowInfo, Delay=1500}" 
    Tag="{StaticResource ic_ginfo}" /> 
</StackPanel> 

ContentControl Style:

<Style TargetType="{x:Type ContentControl}" 
x:Key="ContentInfoStyle"> 
<Setter Property="ContentTemplate"> 
    <Setter.Value> 
    <DataTemplate> 
    <Border Background="Green" 
     CornerRadius="3" 
     Padding="10,0,12,10"> 
    <StackPanel> 
     <Button HorizontalAlignment="Right" 
     Tag="{StaticResource ic_gclear}" 
     Style="{StaticResource btnIcons}" 
     Background="White" 
     Margin="10,5,12,5" 
     Command="{Binding DataContext.CmdCloseInfo}" 
     Height="24" /> 
     <ContentPresenter x:Name="content" 
      TextBlock.FontSize="14" 
      TextBlock.Foreground="White" 
      TextBlock.FontFamily="Arial" 
      Content="{TemplateBinding ContentControl.Content}" /> 
    </StackPanel> 
    </Border> 
    </DataTemplate> 
    </Setter.Value> 
    </Setter> 
</Style> 

Bouton style icône:

<Style TargetType="Button" 
    x:Key="btnIcons">   
    <Setter Property="Template"> 
    <Setter.Value> 
    <ControlTemplate TargetType="{x:Type Button}"> 
     <Border x:Name="brd" Background="Transparent" 
     SnapsToDevicePixels="True"> 
     <VisualStateManager.VisualStateGroups> 
     <VisualStateGroup x:Name="CommonStates"> 
     <VisualState x:Name="Normal" /> 
     <VisualState x:Name="MouseOver" /> 
     <VisualState x:Name="Pressed" /> 
     </VisualStateGroup> 
     </VisualStateManager.VisualStateGroups> 
     <Path Stretch="Uniform" VerticalAlignment="Center" 
     Fill="{TemplateBinding Background}" 
     Data="{TemplateBinding Tag}" /> 
     </Border> 
    </ControlTemplate> 
    </Setter.Value> 
    </Setter> 
</Style> 

ViewModel.cs: le contenu de pop-up:

private string _InfoContent; 

public string InfoContent 
{ 
    get { return _InfoContent; } 
    set 
    { 
    if (value != _InfoContent) 
    { 
     _InfoContent = value; 
     OnRaise("InfoContent"); 
    } 
    } 
} 

montrent le menu contextuel pour option2 et option1:

private bool _IsShowInfo2; 

public bool IsShowInfo2 
{ 
    get { return _IsShowInfo2; } 
    set 
    { 
    if (value != _IsShowInfo2) 
    { 
     _IsShowInfo2 = value; 
     OnRaise("IsShowInfo2"); 
    } 
    } 
} 
//show the popup for option1 
private bool _IsShowInfo1; 

public bool IsShowInfo1 
{ 
    get { return _IsShowInfo1; } 
    set 
    { 
    if (value != _IsShowInfo1) 
    { 
     _IsShowInfo1 = value; 
     OnRaise("IsShowInfo1"); 
    } 
    } 
} 

la commande pour le bouton:

private ICommand _CmdShowInfo; 

public ICommand CmdShowInfo 
{ 
    get 
    { 
    _CmdShowInfo = _CmdShowInfo ?? new RelayCommand(x => this.ShowInfo(true, 1),() => true); 
    return _CmdShowInfo; 
    } 
} 

private ICommand _CmdShowInfo2; 

public ICommand CmdShowInfo2 
{ 
    get 
    { 
    _CmdShowInfo2 = _CmdShowInfo2 ?? new RelayCommand(x => this.ShowInfo(true, 0),() => true); 
    return _CmdShowInfo2; 
    } 
} 

private void ShowInfo(bool show = true, byte option = 0) 
{ 
    if (option == 0) 
    { 
    this.InfoContent = "Option 1..."; 
    } 
    else if (option == 1) 
    { 
    this.InfoContent = "Option 2..."; 
    } 
    this.IsShowInfo1 = show; 
} 
+0

Votre "popup pour l'option 2" n'est pas un popup. Il est difficile d'être sûr de ce que vous demandez, mais si vous voulez seulement avoir un seul élément 'Popup', et afficher un contenu différent, écrivez un style' HeaderedContentControl' avec un 'ContentTemplate' qui place son' Header' contenu dans un bouton et c'est 'Content' dans un' Popup'. –

+0

oui, je sais que c'est difficile à faire.pouvez-vous me donner plus de détails sur HeaderedContentControl vs popup? @EdPlunkett – Jandy

+0

Puis-je voir les définitions de ic_gclear et ic_ginfo? –

Répondre

1

Ma première pensée a été de le faire avec un style HeaderedContentControl, mais alors vous avez la couleur de remplissage de l'icône et les données de l'icône, et j'aurais dû ajouter des propriétés jointes pour ceux-ci. Une fois que vous y allez, vous pouvez tout aussi bien écrire un contrôle personnalisé.

Les propriétés de dépendance de IconPopupButton peuvent être liés comme une propriété de dépendance:

<hec:IconPopupButton 
    IsOpen="{Binding IsShowInfo1}" 
    IconFill="YellowGreen" 
    Content="Another Test Popup" 
    IconData="M -10,-10 M 0,3 L 17,20 L 20,17 L 3,0 Z M 0,0 L 0,20 L 20,20 L 20,0 Z" 
    /> 

Si vous souhaitez paramétrer le Style appliqué au ContentControl dans le Popup, ajoutez une autre propriété de dépendance. Cependant, vous aurez besoin de réfléchir, parce que vous avez besoin de cette ToggleButton pour être lié à IsOpen sur le parent modèle, d'une manière ou d'une autre. Peut-être pourriez-vous le lier à la propriété viewmodel liée au bouton contextuel IsOpen. Il y a toujours un moyen.

Alors voilà. Avec des extraits pour créer des propriétés de dépendance, il s'agit à peu près d'un exercice de remplissage des blancs. Beaucoup moins à cela qu'à l'œil.

IconPopupButton.cs

using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Controls.Primitives; 
using System.Windows.Media; 

namespace HollowEarth.Controls 
{ 
    public class IconPopupButton : ContentControl 
    { 
     static IconPopupButton() 
     { 
      DefaultStyleKeyProperty.OverrideMetadata(typeof(IconPopupButton), new FrameworkPropertyMetadata(typeof(IconPopupButton))); 
     } 

     #region IconData Property 
     public Geometry IconData 
     { 
      get { return (Geometry)GetValue(IconDataProperty); } 
      set { SetValue(IconDataProperty, value); } 
     } 

     public static readonly DependencyProperty IconDataProperty = 
      DependencyProperty.Register("IconData", typeof(Geometry), typeof(IconPopupButton), 
       new PropertyMetadata(null)); 
     #endregion IconData Property 

     #region IconFill Property 
     public Brush IconFill 
     { 
      get { return (Brush)GetValue(IconFillProperty); } 
      set { SetValue(IconFillProperty, value); } 
     } 

     public static readonly DependencyProperty IconFillProperty = 
      DependencyProperty.Register("IconFill", typeof(Brush), typeof(IconPopupButton), 
       new PropertyMetadata(SystemColors.ControlTextBrush)); 
     #endregion IconFill Property 

     #region IsOpen Property 
     public bool IsOpen 
     { 
      get { return (bool)GetValue(IsOpenProperty); } 
      set { SetValue(IsOpenProperty, value); } 
     } 

     public static readonly DependencyProperty IsOpenProperty = 
      DependencyProperty.Register("IsOpen", typeof(bool), typeof(IconPopupButton), 
       new PropertyMetadata(false)); 
     #endregion IsOpen Property 

     #region StaysOpen Property 
     public bool StaysOpen 
     { 
      get { return (bool)GetValue(StaysOpenProperty); } 
      set { SetValue(StaysOpenProperty, value); } 
     } 

     public static readonly DependencyProperty StaysOpenProperty = 
      DependencyProperty.Register("StaysOpen", typeof(bool), typeof(IconPopupButton), 
       new PropertyMetadata(false)); 
     #endregion StaysOpen Property 

     #region Placement Property 
     public PlacementMode Placement 
     { 
      get { return (PlacementMode)GetValue(PlacementProperty); } 
      set { SetValue(PlacementProperty, value); } 
     } 

     public static readonly DependencyProperty PlacementProperty = 
      DependencyProperty.Register("Placement", typeof(PlacementMode), typeof(IconPopupButton), 
       new PropertyMetadata(PlacementMode.Right)); 
     #endregion Placement Property 
    } 
} 

Thèmes \ Shared.xaml

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:HeaderedPopupTest.Themes" 
    > 
    <Geometry x:Key="ic_gclear">M56,4 52,0 28,24 4,0 0,4 24,28 0,52 4,56 28,32 52,56 56,52 32,28Z</Geometry> 
    <Geometry x:Key="ic_ginfo">M31,0C13.879,0,0,13.879,0,31s13.879,31,31,31s31-13.879,31-31S48.121,0,31,0z M34,46h-6V27.969h6V46z M34,21.969h-6V16h6V21.969z</Geometry> 

    <Style TargetType="ButtonBase" x:Key="btnIcons"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type ButtonBase}"> 
        <Border x:Name="brd" Background="Transparent" SnapsToDevicePixels="True"> 
         <VisualStateManager.VisualStateGroups> 
          <VisualStateGroup x:Name="CommonStates"> 
           <VisualState x:Name="Normal" /> 
           <VisualState x:Name="MouseOver" /> 
           <VisualState x:Name="Pressed" /> 
          </VisualStateGroup> 
         </VisualStateManager.VisualStateGroups> 
         <Grid> 
          <Path 
           x:Name="Path" 
           Stretch="Uniform" 
           VerticalAlignment="Center" 
           Fill="{TemplateBinding Background}" 
           Data="{TemplateBinding Tag}" 
           /> 
          <TextBlock 
           x:Name="MissingIconData" 
           Visibility="Collapsed" 
           Text="?" 
           FontWeight="Bold" 
           FontSize="30" 
           ToolTip="IconData (Tag) not set" 
           HorizontalAlignment="Center" 
           VerticalAlignment="Center" 
           /> 
         </Grid> 
        </Border> 
        <ControlTemplate.Triggers> 
         <Trigger Property="Tag" Value="{x:Null}"> 
          <Setter TargetName="MissingIconData" Property="Visibility" Value="Visible" /> 
         </Trigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 

</ResourceDictionary> 

Thèmes \ generic.xaml

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:HeaderedPopupTest.Themes" 
    xmlns:hec="clr-namespace:HollowEarth.Controls" 
    > 

    <ResourceDictionary.MergedDictionaries> 
     <!-- Change HeaderedPopupTest to the name of your own assembly --> 
     <ResourceDictionary Source="/HeaderedPopupTest;component/Themes/Shared.xaml" /> 
    </ResourceDictionary.MergedDictionaries> 

    <Style TargetType="hec:IconPopupButton"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="hec:IconPopupButton"> 
        <Grid x:Name="Grid"> 
         <ToggleButton 
          x:Name="OpenButton" 
          Style="{StaticResource btnIcons}" 
          Background="{TemplateBinding IconFill}" 
          Tag="{TemplateBinding IconData}" 
          IsChecked="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" 
          ToolTip="{TemplateBinding ToolTip}" 
          /> 
         <Popup 
          x:Name="Popup" 
          StaysOpen="{Binding StaysOpen, RelativeSource={RelativeSource TemplatedParent}}" 
          IsOpen="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" 
          PlacementTarget="{Binding ElementName=ToggleButton}" 
          Placement="{TemplateBinding Placement}" 
          > 
          <Border 
           Background="Green" 
           CornerRadius="3" 
           Padding="10,0,12,10"> 
           <StackPanel> 
            <ToggleButton 
             HorizontalAlignment="Right" 
             Tag="{StaticResource ic_gclear}" 
             Style="{StaticResource btnIcons}" 
             Background="White" 
             Margin="10,5,12,5" 
             IsChecked="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" 
             Height="24" 
             /> 
            <ContentPresenter 
             x:Name="content" 
             TextBlock.FontSize="14" 
             TextBlock.Foreground="White" 
             TextBlock.FontFamily="Arial" 
             Content="{TemplateBinding Content}" 
             /> 
           </StackPanel> 
          </Border> 
         </Popup> 
        </Grid> 
        <ControlTemplate.Triggers> 
         <MultiTrigger> 
          <MultiTrigger.Conditions> 
           <!-- 
           I don't understand this: If I use the templated parent's IsOpen, 
           the effect is as if it were never true. 
           --> 
           <Condition SourceName="Popup" Property="IsOpen" Value="True" /> 
           <Condition Property="StaysOpen" Value="False" /> 
          </MultiTrigger.Conditions> 
          <!-- 
          If StaysOpen is false and the button is enabled while the popup is open, 
          then clicking on it will cause the popup to flicker rather than close. 
          --> 
          <Setter TargetName="OpenButton" Property="IsEnabled" Value="False" /> 
         </MultiTrigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</ResourceDictionary> 

MainWindow.xaml Exemple d'utilisation:

<Window 
    x:Class="HeaderedPopupTest.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:HeaderedPopupTest" 
    xmlns:hec="clr-namespace:HollowEarth.Controls" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="350" Width="525" 
    > 
    <Window.Resources> 
     <ResourceDictionary> 
      <ResourceDictionary.MergedDictionaries> 
       <ResourceDictionary Source="Themes\Shared.xaml" /> 
      </ResourceDictionary.MergedDictionaries> 

      <Style 
       x:Key="InfoPopupButton" 
       TargetType="hec:IconPopupButton" 
       BasedOn="{StaticResource {x:Type hec:IconPopupButton}}" 
       > 
       <Setter Property="IconFill" Value="DeepSkyBlue" /> 
       <Setter Property="IconData" Value="{StaticResource ic_ginfo}" /> 
      </Style> 
     </ResourceDictionary> 
    </Window.Resources> 

    <Grid> 
     <StackPanel 
      Orientation="Vertical" 
      HorizontalAlignment="Left" 
      > 
      <hec:IconPopupButton 
       Style="{StaticResource InfoPopupButton}" 
       Content="This is a test popup" 
       ToolTip="Test Popup Tooltip" 
       /> 
      <hec:IconPopupButton 
       IconFill="YellowGreen" 
       Content="Another Test Popup" 
       IconData="M -10,-10 M 0,3 L 17,20 L 20,17 L 3,0 Z M 0,0 L 0,20 L 20,20 L 20,0 Z" 
       /> 
      <hec:IconPopupButton 
       IconFill="DarkRed" 
       Content="Missing IconData behavior example" 
       /> 
     </StackPanel> 
    </Grid> 
</Window> 

Vous remarquerez que j'ai changé vos boutons en ToggleButton. C'est pour plus de commodité dans leur câblage à la propriété IsOpen: Avec un ToggleButton, je viens de lier IsChecked et j'ai terminé. Pas besoin de commandes. Un effet secondaire de cela est que si StaysOpen est false, puis lorsque l'utilisateur clique sur le bouton ouvert pour un Popup, le changement de focus ferme le Popup, ce qui désélectionne le bouton, et puis le bouton obtient le message de la souris. Donc, le bouton ouvre à nouveau le popup. C'est un comportement bizarre du point de vue de l'utilisateur, donc vous ajoutez un déclencheur pour désactiver le bouton lorsque le popup est ouvert et StaysOpen est faux. Lorsque StaysOpen est vrai, le changement de focus ne ferme pas le Popup, vous voulez donc que le bouton soit activé dans ce cas.

J'ai changé le style btnIcons pour cibler ButtonBase, de sorte qu'il fonctionne de manière identique avec Button et ToggleButton.

+0

Je ne sais pas ce que c'est.Il ressemble à control.ToggleButton personnalisé et TextBox Collapsed.lol. – Jandy

+0

@Jandy Je n'ai aucune idée de ce que vous essayez de me dire. –

+0

Il disparaît lorsque la fenêtre est désactivée.Oui, Pas besoin de commandes.Seulement montrer le popup.Il est incroyable! Je vais essayer de le placer dans scrollviewer.J'espère que cela ne prend pas plus de mémoire.Merci beaucoup! @EdPlunkett – Jandy