如何使用 BasedOn 模板化 Generic.xaml 中的切换按钮?
How to use BasedOn to template a toggle button in Generic.xaml?
wpf C#xaml
在我的 Generic.xaml 中,我有很多形式的样式:
<Style x:Key="ToggleButtonStyle12" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid>
<Path x:Name="path1" Data="{StaticResource InsideQuarter3}" Fill="DarkOrange" Stroke="Black" />
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="path1" Property = "Opacity" Value="0.4"/>
</Trigger>
<Trigger Property="IsChecked" Value="true">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Blink_On}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource Blink_Off}"/>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
所有这些切换按钮之间的唯一区别是路径定义和填充颜色。
这种样式可以 templated/simplified 只需要提供路径和填充颜色吗?
大致是这样的:
<Style x:Key="ToggleButtonStyle12" BasedOn(??????)>
<Setter Property = "Path" Value="InsideQuarter3"/>
<Setter Property = "Fill" Value="DarkOrange"/>
</Style>
感谢您的帮助。
编辑#1
好吧,我以为我有它——我错了。下面的代码将正确设置路径数据和填充属性。但是,只有第一个创建的 ToggleButton 保留 "MouseOver" 和其他 ControlTemplate.Triggers。我需要 RingControl 中的所有切换按钮 来遵守它们自己的触发器。
public static class ButtonProperties
{
public static Color GetMyForegroundColor(DependencyObject obj)
{
return (Color)obj.GetValue(MyForegroundColorProperty);
}
public static void SetMyForegroundColor(DependencyObject obj, Color value)
{
obj.SetValue(MyForegroundColorProperty, value);
}
// Using a DependencyProperty as the backing store for MyForegroundColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyForegroundColorProperty =
DependencyProperty.RegisterAttached("MyForegroundColor", typeof(Color), typeof(ButtonProperties), new PropertyMetadata(Colors.Black));
public static Geometry GetData(DependencyObject obj)
{
return (Geometry)obj.GetValue(DataProperty);
}
public static void SetData(DependencyObject obj, Geometry value)
{
obj.SetValue(DataProperty, value);
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.RegisterAttached("Data", typeof(Geometry), typeof(ButtonProperties), new PropertyMetadata(null));
public static Brush GetFill(DependencyObject obj)
{
return (Brush)obj.GetValue(FillProperty);
}
public static void SetFill(DependencyObject obj, Brush value)
{
obj.SetValue(FillProperty, value);
}
// Using a DependencyProperty as the backing store for Fill. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FillProperty =
DependencyProperty.RegisterAttached("Fill", typeof(Brush), typeof(ButtonProperties), new PropertyMetadata(null));
}
Generic.xaml -- BaseButtonStyle
<Style x:Key="BaseButtonStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="local:ButtonProperties.MyForegroundColor" Value="Blue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid>
<TextBlock Text="Some Text">
<TextBlock.Foreground>
<SolidColorBrush Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:ButtonProperties.MyForegroundColor)}" />
</TextBlock.Foreground>
</TextBlock>
<Path x:Name="path1" Data="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:ButtonProperties.Data)}"
Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:ButtonProperties.Fill)}"
Stroke="Black"/>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="path1" Property = "Opacity" Value="0.4"/>
</Trigger>
<Trigger Property="IsChecked" Value="true">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Blink_On}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource Blink_Off}"/>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Generic.xaml -- ModifiedButtonStyle1
<Style x:Key="ModifiedButtonStyle1" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="local:ButtonProperties.MyForegroundColor" Value="Red" />
<Setter Property="local:ButtonProperties.Data" Value="{StaticResource Arc0}" />
<Setter Property="local:ButtonProperties.Fill" Value="LightGreen"/>
</Style>
<Style x:Key="ModifiedButtonStyle2" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="local:ButtonProperties.MyForegroundColor" Value="Red" />
<Setter Property="local:ButtonProperties.Data" Value="{StaticResource Arc45}" />
<Setter Property="local:ButtonProperties.Fill" Value="LightPink"/>
</Style>
<Style x:Key="ModifiedButtonStyle3" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="local:ButtonProperties.MyForegroundColor" Value="Red" />
<Setter Property="local:ButtonProperties.Data" Value="{StaticResource Arc90}" />
<Setter Property="local:ButtonProperties.Fill" Value="LightCoral"/>
</Style>
Generic.xaml -- 在自定义控件中使用 ModifiedButtonStyles,RingControl
<Style TargetType="{x:Type local:RingButtons2}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:RingButtons2}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Viewbox>
<Grid>
<!--Outer Rim -->
<Path Data="{StaticResource OuterRim}" Fill="Silver" Stroke="Black" />
<Path Data="{StaticResource OuterWheelBackground}" Fill="White" Stroke="Black" />
<ToggleButton x:Name="PART_Button1" Style="{StaticResource ModifiedButtonStyle1}"/>
<ToggleButton x:Name="PART_Button2" Style="{StaticResource ModifiedButtonStyle2}"/>
<ToggleButton x:Name="PART_Button3" Style="{StaticResource ModifiedButtonStyle3}"/>
........................................................
</Grid>
</Viewbox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
在用户界面中使用 RingControl2:
<w:RingButtons2/>
似乎单击 RingButtons2 控件中的任意位置只会导致第一个定义的切换按钮响应 -- 而不是任何其他按钮。
如何解决这个问题,使每个切换按钮独立于其他按钮并遵守其自己的控制模板触发器?
再次感谢。
编辑#2
从 BaseButtonStyle 中删除 TextBlock 定义后,
<TextBlock Text="Some Text">
<TextBlock.Foreground>
<SolidColorBrush Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:ButtonProperties.MyForegroundColor)}" />
</TextBlock.Foreground>
</TextBlock>
一切正常!为什么是这样??
谢谢。
如果目标控件具有可用于这些自定义绑定的依赖属性,则可以使用 TemplateBinding,这是一个示例:
<Style x:Key="BaseButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock Text="Some Text" Foreground="{TemplateBinding Foreground}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ModifiedButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="Foreground" Value="Red" />
</Style>
你会这样指代:
<Grid>
<Button Style="{StaticResource ModifiedButtonStyle}" />
</Grid>
但是,在上面给出的示例中,您在模板中使用了 Path 和 Fill,我猜它们没有关联的属性。在这种情况下,您的选择是要么创建一个新控件并将这些属性添加到其中,要么最好使用附加属性。对于后者,您将创建一个附加的 属性,如下所示:
public static class ButtonProperties
{
public static Color GetMyForegroundColor(DependencyObject obj)
{
return (Color)obj.GetValue(MyForegroundColorProperty);
}
public static void SetMyForegroundColor(DependencyObject obj, Color value)
{
obj.SetValue(MyForegroundColorProperty, value);
}
// Using a DependencyProperty as the backing store for MyForegroundColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyForegroundColorProperty =
DependencyProperty.RegisterAttached("MyForegroundColor", typeof(Color), typeof(ButtonProperties), new PropertyMetadata(Colors.Black));
}
然后您将在 XAML:
中像这样引用并覆盖它
<Style x:Key="BaseButtonStyle" TargetType="{x:Type Button}">
<Setter Property="behaviors:ButtonProperties.MyForegroundColor" Value="Blue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock Text="Some Text">
<TextBlock.Foreground>
<SolidColorBrush Color="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=(behaviors:ButtonProperties.MyForegroundColor)}" />
</TextBlock.Foreground>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ModifiedButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="behaviors:ButtonProperties.MyForegroundColor" Value="Red" />
</Style>
它们或多或少是相同的,只是在第一种情况下,您使用的是控件中已有的现有属性(或创建一个包含它们的新控件),而在第二种情况下,您是在外部声明并将它们附加到现有控件。
wpf C#xaml
在我的 Generic.xaml 中,我有很多形式的样式:
<Style x:Key="ToggleButtonStyle12" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid>
<Path x:Name="path1" Data="{StaticResource InsideQuarter3}" Fill="DarkOrange" Stroke="Black" />
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="path1" Property = "Opacity" Value="0.4"/>
</Trigger>
<Trigger Property="IsChecked" Value="true">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Blink_On}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource Blink_Off}"/>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
所有这些切换按钮之间的唯一区别是路径定义和填充颜色。
这种样式可以 templated/simplified 只需要提供路径和填充颜色吗?
大致是这样的:
<Style x:Key="ToggleButtonStyle12" BasedOn(??????)>
<Setter Property = "Path" Value="InsideQuarter3"/>
<Setter Property = "Fill" Value="DarkOrange"/>
</Style>
感谢您的帮助。
编辑#1 好吧,我以为我有它——我错了。下面的代码将正确设置路径数据和填充属性。但是,只有第一个创建的 ToggleButton 保留 "MouseOver" 和其他 ControlTemplate.Triggers。我需要 RingControl 中的所有切换按钮 来遵守它们自己的触发器。
public static class ButtonProperties
{
public static Color GetMyForegroundColor(DependencyObject obj)
{
return (Color)obj.GetValue(MyForegroundColorProperty);
}
public static void SetMyForegroundColor(DependencyObject obj, Color value)
{
obj.SetValue(MyForegroundColorProperty, value);
}
// Using a DependencyProperty as the backing store for MyForegroundColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyForegroundColorProperty =
DependencyProperty.RegisterAttached("MyForegroundColor", typeof(Color), typeof(ButtonProperties), new PropertyMetadata(Colors.Black));
public static Geometry GetData(DependencyObject obj)
{
return (Geometry)obj.GetValue(DataProperty);
}
public static void SetData(DependencyObject obj, Geometry value)
{
obj.SetValue(DataProperty, value);
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.RegisterAttached("Data", typeof(Geometry), typeof(ButtonProperties), new PropertyMetadata(null));
public static Brush GetFill(DependencyObject obj)
{
return (Brush)obj.GetValue(FillProperty);
}
public static void SetFill(DependencyObject obj, Brush value)
{
obj.SetValue(FillProperty, value);
}
// Using a DependencyProperty as the backing store for Fill. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FillProperty =
DependencyProperty.RegisterAttached("Fill", typeof(Brush), typeof(ButtonProperties), new PropertyMetadata(null));
}
Generic.xaml -- BaseButtonStyle
<Style x:Key="BaseButtonStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="local:ButtonProperties.MyForegroundColor" Value="Blue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid>
<TextBlock Text="Some Text">
<TextBlock.Foreground>
<SolidColorBrush Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:ButtonProperties.MyForegroundColor)}" />
</TextBlock.Foreground>
</TextBlock>
<Path x:Name="path1" Data="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:ButtonProperties.Data)}"
Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:ButtonProperties.Fill)}"
Stroke="Black"/>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="path1" Property = "Opacity" Value="0.4"/>
</Trigger>
<Trigger Property="IsChecked" Value="true">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Blink_On}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource Blink_Off}"/>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Generic.xaml -- ModifiedButtonStyle1
<Style x:Key="ModifiedButtonStyle1" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="local:ButtonProperties.MyForegroundColor" Value="Red" />
<Setter Property="local:ButtonProperties.Data" Value="{StaticResource Arc0}" />
<Setter Property="local:ButtonProperties.Fill" Value="LightGreen"/>
</Style>
<Style x:Key="ModifiedButtonStyle2" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="local:ButtonProperties.MyForegroundColor" Value="Red" />
<Setter Property="local:ButtonProperties.Data" Value="{StaticResource Arc45}" />
<Setter Property="local:ButtonProperties.Fill" Value="LightPink"/>
</Style>
<Style x:Key="ModifiedButtonStyle3" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="local:ButtonProperties.MyForegroundColor" Value="Red" />
<Setter Property="local:ButtonProperties.Data" Value="{StaticResource Arc90}" />
<Setter Property="local:ButtonProperties.Fill" Value="LightCoral"/>
</Style>
Generic.xaml -- 在自定义控件中使用 ModifiedButtonStyles,RingControl
<Style TargetType="{x:Type local:RingButtons2}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:RingButtons2}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Viewbox>
<Grid>
<!--Outer Rim -->
<Path Data="{StaticResource OuterRim}" Fill="Silver" Stroke="Black" />
<Path Data="{StaticResource OuterWheelBackground}" Fill="White" Stroke="Black" />
<ToggleButton x:Name="PART_Button1" Style="{StaticResource ModifiedButtonStyle1}"/>
<ToggleButton x:Name="PART_Button2" Style="{StaticResource ModifiedButtonStyle2}"/>
<ToggleButton x:Name="PART_Button3" Style="{StaticResource ModifiedButtonStyle3}"/>
........................................................
</Grid>
</Viewbox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
在用户界面中使用 RingControl2:
<w:RingButtons2/>
似乎单击 RingButtons2 控件中的任意位置只会导致第一个定义的切换按钮响应 -- 而不是任何其他按钮。
如何解决这个问题,使每个切换按钮独立于其他按钮并遵守其自己的控制模板触发器?
再次感谢。
编辑#2
从 BaseButtonStyle 中删除 TextBlock 定义后,
<TextBlock Text="Some Text">
<TextBlock.Foreground>
<SolidColorBrush Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:ButtonProperties.MyForegroundColor)}" />
</TextBlock.Foreground>
</TextBlock>
一切正常!为什么是这样??
谢谢。
如果目标控件具有可用于这些自定义绑定的依赖属性,则可以使用 TemplateBinding,这是一个示例:
<Style x:Key="BaseButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock Text="Some Text" Foreground="{TemplateBinding Foreground}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ModifiedButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="Foreground" Value="Red" />
</Style>
你会这样指代:
<Grid>
<Button Style="{StaticResource ModifiedButtonStyle}" />
</Grid>
但是,在上面给出的示例中,您在模板中使用了 Path 和 Fill,我猜它们没有关联的属性。在这种情况下,您的选择是要么创建一个新控件并将这些属性添加到其中,要么最好使用附加属性。对于后者,您将创建一个附加的 属性,如下所示:
public static class ButtonProperties
{
public static Color GetMyForegroundColor(DependencyObject obj)
{
return (Color)obj.GetValue(MyForegroundColorProperty);
}
public static void SetMyForegroundColor(DependencyObject obj, Color value)
{
obj.SetValue(MyForegroundColorProperty, value);
}
// Using a DependencyProperty as the backing store for MyForegroundColor. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyForegroundColorProperty =
DependencyProperty.RegisterAttached("MyForegroundColor", typeof(Color), typeof(ButtonProperties), new PropertyMetadata(Colors.Black));
}
然后您将在 XAML:
中像这样引用并覆盖它<Style x:Key="BaseButtonStyle" TargetType="{x:Type Button}">
<Setter Property="behaviors:ButtonProperties.MyForegroundColor" Value="Blue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock Text="Some Text">
<TextBlock.Foreground>
<SolidColorBrush Color="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=(behaviors:ButtonProperties.MyForegroundColor)}" />
</TextBlock.Foreground>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ModifiedButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="behaviors:ButtonProperties.MyForegroundColor" Value="Red" />
</Style>
它们或多或少是相同的,只是在第一种情况下,您使用的是控件中已有的现有属性(或创建一个包含它们的新控件),而在第二种情况下,您是在外部声明并将它们附加到现有控件。