一个弹出所有按钮 [英] One popup for all button

查看:26
本文介绍了一个弹出所有按钮的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如所提到的主题.我只想为我的应用程序中的所有按钮使用一个弹出窗口.我不知道如何获得我想要的.这是我的窗口的样子:

As topic mentioned.I want to use only one popup for all button in my application.I don't know how to get what I want. Here is what my window looks like:

信息 1:

信息 2:

您可以看到弹出窗口出现在错误的位置.我知道我可以通过设置 PlacementTarget 来定位弹出窗口.但是每个弹出窗口的放置属性值都不同.这就是问题所在.我正在寻找另一种方法来做到这一点.

You can see popup appear on wrong position.I know I can position a popup by setting the PlacementTarget.But each Popup has a different value for the placement property.That is the problem.I'm looking another way to do it.

这是选项 1 的弹出窗口:

Here is a popup for 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>

选项 2 的弹出窗口:

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

内容控件样式:

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

ViewModel.cs: the content of popup:

private string _InfoContent;

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

显示 option2option1 的弹出窗口:

show the popup for option2 and 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;
}

推荐答案

我最初的想法是使用样式化的 HeaderedContentControl 来做到这一点,但随后您就获得了图标填充颜色和图标数据,我不得不为这些添加附加属性.一旦你去了那里,你不妨写一个自定义控件.

My initial thought was to do this with a styled HeaderedContentControl, but then you've got the icon fill color and the icon data, and I'd have had to add attached properties for those. Once you go there, you may as well just write a custom control.

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

The dependency properties of IconPopupButton can be bound like any dependency property:

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

如果要参数化应用于 Popup 中的 ContentControlStyle,请添加另一个依赖项属性.不过,您需要考虑一下,因为您需要将 ToggleButton 以一种或另一种方式绑定到模板化父级上的 IsOpen.也许您可以将它绑定到绑定到弹出按钮的 IsOpen 的 viewmodel 属性.总有办法.

If you want to parameterize the Style applied to the ContentControl in the Popup, add another dependency property. You'll need to give that some thought, though, because you need that ToggleButton to be bound to IsOpen on the templated parent, one way or another. Perhaps you could bind it to the viewmodel property that's bound to the popup button's IsOpen. There's always a way.

就是这样.使用片段来创建依赖属性,这几乎只是一个填空练习.远远少于它的眼睛.

So here's that. With snippets to create dependency properties, this is pretty much just a fill-in-the-blanks exercise. Much less to it than meets the eye.

图标弹出按钮.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
    }
}

主题\共享.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>

主题\通用.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 示例用法:

MainWindow.xaml example usage:

<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,我只需绑定 IsChecked 就完成了.不需要命令.这样做的一个副作用是,如果 StaysOpenfalse,那么当用户单击 Popup 的打开按钮时,焦点更改关闭Popup,取消选中按钮,然后然后按钮获取鼠标消息.所以按钮再次打开弹出窗口.从用户的角度来看,这是一种奇怪的行为,因此您添加了一个触发器以在弹出窗口打开且 StaysOpen 为 false 时禁用按钮.当 StaysOpen 为 true 时,焦点更改不会关闭 Popup,因此您希望在这种情况下启用按钮.

You'll notice I changed your buttons to ToggleButton. This is for convenience in wiring them up to the IsOpen property: With a ToggleButton, I just bind IsChecked and I'm done. No need for commands. One side effect of that is that if StaysOpen is false, then when the user clicks on the open button for a Popup, the focus change closes the Popup, which unchecks the button, and then the button gets the mouse message. So the button opens the popup again. This is bizarre behavior from the user's perspective, so you add a trigger to disable the button when the popup is open and StaysOpen is false. When StaysOpen is true, focus change doesn't close the Popup, so you want the button to be enabled in that case.

我将 btnIcons 样式更改为针对 ButtonBase,因此它与 ButtonToggleButton 的工作方式相同.

I changed the btnIcons style to target ButtonBase, so it works identically with Button and ToggleButton.

这篇关于一个弹出所有按钮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆