所有按钮

时间:2016-11-01 13:01:31

标签: c# wpf-controls

如上所述。我想在我的应用程序中只使用一个弹出按钮。我不知道如何得到我想要的东西。 这是我的窗口的样子:

enter image description here

信息1

enter image description here

信息2:

enter image description here

你可以看到弹出窗口显示在错误的位置。我知道我可以通过设置PlacementTarget来定位弹出窗口。但是每个Popup都有一个不同的放置属性值。这就是问题。我正在寻找另一种方式做到这一点。

以下是选项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>
选项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 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>

按钮图标样式:

<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: 弹出窗口的内容:

private string _InfoContent;

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

显示 option2 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");
    }
  }
}

按钮命令:

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

1 个答案:

答案 0 :(得分:1)

我最初的想法是使用样式HeaderedContentControl执行此操作,但是您已经获得了图标填充颜色和图标数据,并且我必须为这些添加附加属性。一旦你去那里,你也可以写一个自定义控件。

IconPopupButton的依赖属性可以像任何依赖属性一样绑定:

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

如果要参数化应用于StyleContentControl的{​​{1}},请添加其他依赖项属性。但是,您需要考虑一下,因为您需要PopupToggleButton的方式绑定到模板化父级,无论如何。也许您可以将它绑定到绑定到弹出按钮IsOpen的viewmodel属性。总有办法。

所以,就是这样。使用片段创建依赖项属性,这几乎只是一个空白填充练习。远远不如满足于眼睛。

IconPopupButton.cs

IsOpen

主题\ Shared.xaml

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

主题\ 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"
    >
    <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>

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

您会注意到我已将按钮更改为<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> 。这是为了方便将它们连接到ToggleButton属性:使用IsOpen,我只需绑定ToggleButton即可。不需要命令。这样做的一个副作用是,如果IsCheckedStaysOpen,那么当用户点击false的打开按钮时,焦点更改会关闭Popup,这会取消选中按钮,然后按钮获取鼠标消息。因此该按钮再次打开弹出窗口。从用户的角度来看,这是一种奇怪的行为,因此当弹出窗口打开且Popup为false时,您可以添加一个触发器来禁用该按钮。如果StaysOpen为真,则焦点更改不会关闭StaysOpen,因此您希望在该情况下启用该按钮。

我将Popup样式更改为定位btnIcons,因此它与ButtonBaseButton完全相同。