如上所述。我想在我的应用程序中只使用一个弹出按钮。我不知道如何得到我想要的东西。 这是我的窗口的样子:
信息1 :
信息2:
你可以看到弹出窗口显示在错误的位置。我知道我可以通过设置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;
}
答案 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"
/>
如果要参数化应用于Style
中ContentControl
的{{1}},请添加其他依赖项属性。但是,您需要考虑一下,因为您需要Popup
以ToggleButton
的方式绑定到模板化父级,无论如何。也许您可以将它绑定到绑定到弹出按钮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
即可。不需要命令。这样做的一个副作用是,如果IsChecked
为StaysOpen
,那么当用户点击false
的打开按钮时,焦点更改会关闭Popup
,这会取消选中按钮,然后按钮获取鼠标消息。因此该按钮再次打开弹出窗口。从用户的角度来看,这是一种奇怪的行为,因此当弹出窗口打开且Popup
为false时,您可以添加一个触发器来禁用该按钮。如果StaysOpen
为真,则焦点更改不会关闭StaysOpen
,因此您希望在该情况下启用该按钮。
我将Popup
样式更改为定位btnIcons
,因此它与ButtonBase
和Button
完全相同。