CustomControl 中带有弹出窗口的行为 ToggleButton
Behaviour ToggleButton with Popup in CustomControl
所以我在 wpf 中有以下 xaml 代码。这使我的 DropdownButton 行为符合我的预期。
<ToggleButton Content="Test"
VerticalAlignment="Center"
Focusable="False"
IsChecked="{Binding IsOpen, ElementName=Popup, Mode=TwoWay}"
Height="25"
Width="20"
x:Name="btn">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsOpen, ElementName=Popup}" Value="True">
<Setter Property="IsHitTestVisible" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
<Popup Placement="Bottom"
PlacementTarget="{Binding ElementName=btn}"
x:Name="Popup"
StaysOpen="False">
<TextBlock Background="AliceBlue">Bla</TextBlock>
</Popup>
既然我使用了几次,我想创建一个自定义控件。
到目前为止 class 看起来像这样:
public class CustomDropdownButton : ToggleButton
{
public static readonly DependencyProperty DropdownContentProperty = DependencyProperty.Register("DropdownContent", typeof(UIElement), typeof(CustomDropdownButton));
static CustomDropdownButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomDropdownButton), new FrameworkPropertyMetadata(typeof(CustomDropdownButton)));
}
public UIElement DropdownContent
{
get
{
return (UIElement)GetValue(DropdownContentProperty);
}
set
{
SetValue(DropdownContentProperty, value);
}
}
}
然后我编辑了样式,它看起来像这样:
<Style x:Key="ButtonFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle StrokeDashArray="1 2" StrokeThickness="1"
Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"
SnapsToDevicePixels="true" Margin="2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#F3F3F3" Offset="0"/>
<GradientStop Color="#EBEBEB" Offset="0.5"/>
<GradientStop Color="#DDDDDD" Offset="0.5"/>
<GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>
<Style TargetType="{x:Type local:CustomDropdownButton}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="ClickMode" Value="Press"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="IsChecked" Value="{Binding IsOpen, ElementName=Popup, Mode=TwoWay}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomDropdownButton}">
<themes:ButtonChrome x:Name="Chrome"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
RenderMouseOver="{TemplateBinding IsMouseOver}"
SnapsToDevicePixels="true">
<StackPanel Orientation="Horizontal"
IsHitTestVisible="True">
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="5,0,0,0"/>
<Path x:Name="ArrowPath"
Margin="7,3,3,2"
Fill="Gray"
Stroke="Gray"
StrokeThickness="1"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
Stretch="Uniform"
VerticalAlignment="Center"
HorizontalAlignment="Center"
RenderTransformOrigin=".5,.5"
Data="M0,0 L2,0 L4,2 L5,3 L6,2 L8,0 L10,0 L8,2 L5,7 L2,2 z">
<Path.RenderTransform>
<RotateTransform Angle="-90"/>
</Path.RenderTransform>
</Path>
<Popup Placement="Bottom"
x:Name="Popup"
StaysOpen="False"
Child="{TemplateBinding DropdownContent}"/>
</StackPanel>
</themes:ButtonChrome>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsOpen, ElementName=Popup}" Value="True">
<Setter Property="IsHitTestVisible" Value="False" />
</DataTrigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="RenderDefaulted" TargetName="Chrome" Value="true"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#ADADAD"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ArrowPath"
Storyboard.TargetProperty="RenderTransform.(RotateTransform.Angle)"
To="-90"
Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ArrowPath"
Storyboard.TargetProperty="RenderTransform.(RotateTransform.Angle)"
To="0"
Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
弹出按钮的示例代码运行良好。
我想我会通过使用 Setter 将弹出窗口的 IsOpen 属性 绑定到 ToggleButton 的 IsChecked 属性 来获得相同的效果。
我是否缺少需要添加的触发行为?我不太明白为什么打不开。
通过删除 IsChecked 和 ClickMode Setter 来修复它,从弹出窗口绑定 IsOpen 属性 不是使用模板绑定,而是使用建议的 RelativeSource 绑定到 IsChecked,模式设置为 TwoWay。 StaysOpen 和 DataTrigger 被保留。
由于我为 ListView 中的 ListViewItems 设置了边距,弹出窗口仍然关闭。为内容持有者设置一个填充(总是可点击)或边距(什么都没有)。对我来说,它是 ListView 中的复选框。
将模板中Popup
的IsOpen
属性绑定到控件的IsChecked
属性:
<Popup Placement="Bottom"
x:Name="Popup"
StaysOpen="False"
IsOpen="{Binding Path=IsChecked, RelativeSource={RelativeSource AncestorType=local:CustomDropdownButton}, Mode=TwoWay}"
Child="{TemplateBinding DropdownContent}"/>
这行不通:
<Setter Property="IsChecked" Value="{Binding IsOpen, ElementName=Popup, Mode=TwoWay}"/>
所以我在 wpf 中有以下 xaml 代码。这使我的 DropdownButton 行为符合我的预期。
<ToggleButton Content="Test"
VerticalAlignment="Center"
Focusable="False"
IsChecked="{Binding IsOpen, ElementName=Popup, Mode=TwoWay}"
Height="25"
Width="20"
x:Name="btn">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsOpen, ElementName=Popup}" Value="True">
<Setter Property="IsHitTestVisible" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
<Popup Placement="Bottom"
PlacementTarget="{Binding ElementName=btn}"
x:Name="Popup"
StaysOpen="False">
<TextBlock Background="AliceBlue">Bla</TextBlock>
</Popup>
既然我使用了几次,我想创建一个自定义控件。
到目前为止 class 看起来像这样:
public class CustomDropdownButton : ToggleButton
{
public static readonly DependencyProperty DropdownContentProperty = DependencyProperty.Register("DropdownContent", typeof(UIElement), typeof(CustomDropdownButton));
static CustomDropdownButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomDropdownButton), new FrameworkPropertyMetadata(typeof(CustomDropdownButton)));
}
public UIElement DropdownContent
{
get
{
return (UIElement)GetValue(DropdownContentProperty);
}
set
{
SetValue(DropdownContentProperty, value);
}
}
}
然后我编辑了样式,它看起来像这样:
<Style x:Key="ButtonFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle StrokeDashArray="1 2" StrokeThickness="1"
Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"
SnapsToDevicePixels="true" Margin="2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#F3F3F3" Offset="0"/>
<GradientStop Color="#EBEBEB" Offset="0.5"/>
<GradientStop Color="#DDDDDD" Offset="0.5"/>
<GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>
<Style TargetType="{x:Type local:CustomDropdownButton}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="ClickMode" Value="Press"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="IsChecked" Value="{Binding IsOpen, ElementName=Popup, Mode=TwoWay}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomDropdownButton}">
<themes:ButtonChrome x:Name="Chrome"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
RenderMouseOver="{TemplateBinding IsMouseOver}"
SnapsToDevicePixels="true">
<StackPanel Orientation="Horizontal"
IsHitTestVisible="True">
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="5,0,0,0"/>
<Path x:Name="ArrowPath"
Margin="7,3,3,2"
Fill="Gray"
Stroke="Gray"
StrokeThickness="1"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
Stretch="Uniform"
VerticalAlignment="Center"
HorizontalAlignment="Center"
RenderTransformOrigin=".5,.5"
Data="M0,0 L2,0 L4,2 L5,3 L6,2 L8,0 L10,0 L8,2 L5,7 L2,2 z">
<Path.RenderTransform>
<RotateTransform Angle="-90"/>
</Path.RenderTransform>
</Path>
<Popup Placement="Bottom"
x:Name="Popup"
StaysOpen="False"
Child="{TemplateBinding DropdownContent}"/>
</StackPanel>
</themes:ButtonChrome>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsOpen, ElementName=Popup}" Value="True">
<Setter Property="IsHitTestVisible" Value="False" />
</DataTrigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="RenderDefaulted" TargetName="Chrome" Value="true"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#ADADAD"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ArrowPath"
Storyboard.TargetProperty="RenderTransform.(RotateTransform.Angle)"
To="-90"
Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ArrowPath"
Storyboard.TargetProperty="RenderTransform.(RotateTransform.Angle)"
To="0"
Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
弹出按钮的示例代码运行良好。 我想我会通过使用 Setter 将弹出窗口的 IsOpen 属性 绑定到 ToggleButton 的 IsChecked 属性 来获得相同的效果。
我是否缺少需要添加的触发行为?我不太明白为什么打不开。
通过删除 IsChecked 和 ClickMode Setter 来修复它,从弹出窗口绑定 IsOpen 属性 不是使用模板绑定,而是使用建议的 RelativeSource 绑定到 IsChecked,模式设置为 TwoWay。 StaysOpen 和 DataTrigger 被保留。
由于我为 ListView 中的 ListViewItems 设置了边距,弹出窗口仍然关闭。为内容持有者设置一个填充(总是可点击)或边距(什么都没有)。对我来说,它是 ListView 中的复选框。
将模板中Popup
的IsOpen
属性绑定到控件的IsChecked
属性:
<Popup Placement="Bottom"
x:Name="Popup"
StaysOpen="False"
IsOpen="{Binding Path=IsChecked, RelativeSource={RelativeSource AncestorType=local:CustomDropdownButton}, Mode=TwoWay}"
Child="{TemplateBinding DropdownContent}"/>
这行不通:
<Setter Property="IsChecked" Value="{Binding IsOpen, ElementName=Popup, Mode=TwoWay}"/>