ControlTemplate 在 Blend 中正常工作但在实际应用程序中不正确

ControlTemplate working correctly in Blend but not in actual application

我创建了一个自定义按钮,没什么特别的,只是 mahApps SquareButton 的扩展,左侧有一个小彩色标记。

我在 Blend 中设计它,并在 Visual Studio 中将代码复制到我的实际应用程序中。在 Blend 中启动时它工作得很好,在 Visual Studio 中启动时标记不可见并且文本左对齐,按钮看起来几乎像一个普通的 SquareButton。我做错了什么?


我把XAML复制自Blend:

<Style x:Key="MarkerButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="MinHeight" Value="25"/>
    <Setter Property="FontFamily" Value="{DynamicResource DefaultFont}"/>
    <Setter Property="FontWeight" Value="SemiBold"/>
    <Setter Property="Background" Value="{DynamicResource WhiteBrush}"/>
    <Setter Property="BorderBrush" Value="{DynamicResource BlackBrush}"/>
    <Setter Property="Foreground" Value="{DynamicResource TextBrush}"/>
    <Setter Property="Padding" Value="5,6"/>
    <Setter Property="BorderThickness" Value="2"/>
    <Setter Property="SnapsToDevicePixels" Value="True"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Grid Background="{TemplateBinding Background}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="DisabledVisualElement">
                                        <SplineDoubleKeyFrame KeyTime="0" Value="0.7"/>
                                    </DoubleAnimationUsingKeyFrames>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="PART_ContentPresenter">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="0.3"/>
                                    </DoubleAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="FocusStates">
                            <VisualState x:Name="Focused"/>
                            <VisualState x:Name="Unfocused"/>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="ValidationStates">
                            <VisualState x:Name="Valid"/>
                            <VisualState x:Name="InvalidFocused"/>
                            <VisualState x:Name="InvalidUnfocused"/>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Border x:Name="Background" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{x:Null}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    <Rectangle Fill="#FFAA2222" HorizontalAlignment="Left" Width="15" Margin="{Binding BorderThickness, ElementName=Background}" StrokeThickness="0" IsHitTestVisible="False"/>
                    <Rectangle x:Name="DisabledVisualElement" Fill="{DynamicResource ControlsDisabledBrush}" IsHitTestVisible="False" Opacity="0"/>
                    <Custom:ContentControlEx x:Name="PART_ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="{DynamicResource GrayBrush8}"/>
                        <Setter Property="Foreground" Value="{DynamicResource BlackBrush}"/>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter Property="Background" Value="{DynamicResource BlackBrush}"/>
                        <Setter Property="Foreground" Value="{DynamicResource WhiteBrush}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

只是按钮的自定义部分:

<Rectangle Fill="#FFAA2222" HorizontalAlignment="Left" Width="15" Margin="{Binding BorderThickness, ElementName=Background}" StrokeThickness="0" IsHitTestVisible="False"/>

以及我将其放入 VS 的代码:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
                xmlns:view="clr-namespace:MyApplication.View">
    <Style x:Key="MarkerButtonStyle" TargetType="{x:Type view:MarkerButton}">
    ...
    </Style>
    <Style TargetType="{x:Type view:MarkerButton}" BasedOn="{StaticResource MarkerButtonStyle}"/>
</ResourceDictionary>

然后我使用了这样的按钮:

<view:MarkerButton MarkerColor="{Binding Color}" Content="{Binding Name}" MarkerWidth="15" .... />

使用 Punker76 的扩展按钮解决方案,我得到了这个:

定位错了,不过xaml好像是对的....


修复了我的旧解决方案,问题是我的宽度:我将其声明为 uint 而不是 double。不过,该按钮看起来与普通方形样式不同(不同的边框、焦点矩形、文本对齐方式),我不知道为什么。

首先你给我们看这个

<Style x:Key="MarkerButtonStyle" TargetType="{x:Type Button}">

然后这个

<Style x:Key="MarkerButtonStyle" TargetType="{x:Type view:MarkerButton}">

如果 MarkerButton 是一个按钮,那么如果您使用第一个针对该按钮的样式,这应该可以工作

<Style TargetType="{x:Type view:MarkerButton}"
       BasedOn="{StaticResource MarkerButtonStyle}">
       <Setter Property="MarkerColor" Value="#FFAA2222" />
       <Setter Property="MarkerWidth" Value="15" />
</Style>

<Button Content="Test" HorizontalAlignment="Center" VerticalAlignment="Center" Width="100" />

编辑

您还可以使用附加属性和继承样式来代替创建新按钮 class。

public static class ButtonsHelper
{
    public static readonly DependencyProperty MarkerColorProperty
        = DependencyProperty.RegisterAttached("MarkerColor", typeof(Brush), typeof(ButtonsHelper), new FrameworkPropertyMetadata(Brushes.Transparent));

    public static void SetMarkerColor(DependencyObject obj, Brush value)
    {
        obj.SetValue(MarkerColorProperty, value);
    }

    public static Brush GetMarkerColor(DependencyObject obj)
    {
        return (Brush)obj.GetValue(MarkerColorProperty);
    }

    public static readonly DependencyProperty MarkerWidthProperty
        = DependencyProperty.RegisterAttached("MarkerWidth", typeof(double), typeof(ButtonsHelper), new FrameworkPropertyMetadata(15d));

    public static void SetMarkerWidth(DependencyObject obj, double value)
    {
        obj.SetValue(MarkerWidthProperty, value);
    }

    public static double GetMarkerWidth(DependencyObject obj)
    {
        return (double)obj.GetValue(MarkerWidthProperty);
    }
}

用法

<Style x:Key="MarkerButtonStyle" BasedOn="{StaticResource SquareButtonStyle}" TargetType="{x:Type Button}">
    <Setter Property="ButtonsHelper.MarkerColor" Value="#FFAA2222"/>
    <Setter Property="ButtonsHelper.MarkerWidth" Value="15"/>
    <Setter Property="Padding" Value="2"/>
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <Grid HorizontalAlignment="Stretch">
                    <Rectangle Width="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=(ButtonsHelper.MarkerWidth), Mode=OneWay}"
                               HorizontalAlignment="Left"
                               Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=(ButtonsHelper.MarkerColor), Mode=OneWay}"
                               IsHitTestVisible="False"
                               StrokeThickness="0" />
                    <TextBlock HorizontalAlignment="Center"
                               VerticalAlignment="Center"
                               Text="{Binding Mode=OneWay}" />
                </Grid>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style BasedOn="{StaticResource MarkerButtonStyle}" TargetType="{x:Type Button}" />

您现在可以像这样在 XAML 中更改颜色

<Button Content="Test" ButtonsHelper.MarkerColor="YellowGreen" />