简体   繁体   English

如何使用BasedOn在Generic.xaml中设置切换按钮的模板?

[英]How to use BasedOn to template a toggle button in Generic.xaml?

wpf C# xaml WPF的C#XAML

In my Generic.xaml, I have many styles of the form: 在我的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>

The only difference between all these toggle buttons is the Path definition and the Fill color. 所有这些切换按钮之间的唯一区别是路径定义和填充颜色。

Could this style be templated/simplified in such a way where only the Path and Fill color need be supplied? 是否可以仅需要提供路径和填充颜色的方式对这种样式进行模板化/简化?

That is something along the lines of : 这与以下内容类似:

<Style x:Key="ToggleButtonStyle12" BasedOn(??????)>
    <Setter Property = "Path" Value="InsideQuarter3"/>
    <Setter Property = "Fill" Value="DarkOrange"/>
</Style>

Thank you for any help. 感谢您的任何帮助。

Edit#1 Well, I thought I had it--I was wrong. 编辑#1好吧,我以为自己有错–我错了。 The below code will correctly set the Path Data and Fill properties. 下面的代码将正确设置“路径数据”和“填充”属性。 However, only the first created ToggleButton keeps the "MouseOver" and other ControlTemplate.Triggers. 但是,只有第一个创建的ToggleButton会保留“ MouseOver”和其他ControlTemplate.Triggers。 I need ALL the toggle buttons in the RingControl to respect their own 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 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 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 -- Using the ModifiedButtonStyles in a custom control, RingControl Generic.xaml-在自定义控件RingControl中使用ModifiedButtonStyles

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

Using the RingControl2 in the user interface: 在用户界面中使用RingControl2:

       <w:RingButtons2/>

It would appear that clicking anywhere in the RingButtons2 control results only in the first defined togglebutton responding -- not any of the others. 似乎单击RingButtons2控件中的任何位置只会导致第一个定义的切换按钮做出响应-不会产生任何其他响应。

How can I fix this so that each of the togglebuttons acts independently of the others and respects its own controltemplate triggers? 我该如何解决这个问题,以使每个切换按钮都独立于其他按钮运行,并尊重自己的控制模板触发器?

Thanks again. 再次感谢。

Edit#2 编辑#2

Upon removing the TextBlock definition from the BaseButtonStyle, 从BaseButtonStyle删除TextBlock定义后,

 <TextBlock Text="Some Text">
                        <TextBlock.Foreground>
                            <SolidColorBrush Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:ButtonProperties.MyForegroundColor)}" />
                        </TextBlock.Foreground>
                    </TextBlock>

ALL WORKS! 所有工作! Why is this?? 为什么是这样??

Thanks. 谢谢。

If the target control has dependency properties that you can use for those custom bindings then you can use TemplateBinding, here's an example: 如果目标控件具有可用于这些自定义绑定的依赖项属性,则可以使用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>

Which you would then refer to like so: 然后您将这样引用:

<Grid>
    <Button Style="{StaticResource ModifiedButtonStyle}" />
</Grid>

However, in the example you've given above you're using a Path and a Fill inside a template, which I'm guessing don't have associated properties. 但是,在上面给出的示例中,您正在模板中使用“路径”和“填充”,我想它们没有关联的属性。 In this case your options are to either create a new control and add those properties to it or, preferably, use attached properties. 在这种情况下,您的选择是创建一个新控件并向其中添加这些属性,或者最好使用附加属性。 In the case of the latter you'd create an attached property like this: 对于后者,您将创建一个如下所示的附加属性:

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

And then you'd reference and override it like this in your XAML: 然后在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>

These are more-or-less the same, it's just that in the first case you're using existing properties already inside the control (or creating a new control that has them) whereas in the second case you're declaring and attaching them to an existing control externally. 这些大致相同,只是在第一种情况下,您使用控件中已经存在的现有属性(或创建一个包含它们的新控件),而在第二种情况下,您声明并将它们附加到外部现有的控件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM