2012-02-10 21 views
20

Tengo un estilo estándar para mis botones, pero quiero que ciertas partes del estilo sean configurables. p.ej. Aparece un borde cuando se activa MouseOver para el botón y quiero que el color del borde sea configurable.Enlace de plantilla con propiedades adjuntas

Siguiente artículo: http://www.thomaslevesque.com/2011/10/01/wpf-creating-parameterized-styles-with-attached-properties/ Pensé que podría utilizar las propiedades adjuntas y TemplateBinding para lograrlo.

que crean los siguientes bienes embargados:

public static class ThemeProperties 
{ 
    public static Brush GetButtonBorderColour(DependencyObject obj) 
    { 
     return (Brush)obj.GetValue(ButtonBorderColourProperty); 
    } 

    public static void SetButtonBorderColour(DependencyObject obj, Brush value) 
    { 
     obj.SetValue(ButtonBorderColourProperty, value); 
    } 

    public static readonly DependencyProperty ButtonBorderColourProperty = 
     DependencyProperty.RegisterAttached(
      "ButtonBorderColour", 
      typeof(Brush), 
      typeof(ThemeProperties), 
      new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.Inherits)); 
} 

que establece la propiedad de esta manera:

<Button Style="{StaticResource RedButton}" local:ThemeProperties.ButtonBorderColour="#B20000"/> 

Y mi estilo se parece a esto:

<Window.Resources> 
    <Style x:Key="RedButton" TargetType="Button"> 
     <Setter Property="OverridesDefaultStyle" Value="True"/> 
     <Setter Property="Margin" Value="2"/> 
     <Setter Property="FontFamily" Value="Tahoma"/> 
     <Setter Property="FontSize" Value="11px"/> 
     <Setter Property="FontWeight" Value="Bold"/> 
     <Setter Property="Foreground" Value="White"/> 
     <Setter Property="MinHeight" Value="25" /> 

     <Setter Property="FocusVisualStyle" Value="{StaticResource MyFocusVisual}" /> 
     <Setter Property="Background" > 
      <Setter.Value> 
       <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" > 
        <GradientStop Color="#FECCBF" Offset="0.2"/> 
        <GradientStop Color="Red" Offset="0.85"/> 
        <GradientStop Color="#FECCBF" Offset="1"/> 
       </LinearGradientBrush> 
      </Setter.Value> 
     </Setter> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="Button"> 
        <Border Name="border" BorderThickness="1" Padding="4,2" BorderBrush="Transparent" CornerRadius="3" Background="{TemplateBinding Background}"> 
         <Grid > 
          <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="content"/> 
         </Grid> 
        </Border> 
        <ControlTemplate.Triggers> 
         <Trigger Property="IsMouseOver" Value="True"> 
          <Setter TargetName="border" Property="BorderBrush" Value="{TemplateBinding local:ThemeProperties.ButtonBorderColour}" /> 
          <Setter Property="Foreground" Value="#B20000" /> 
         </Trigger> 
         <Trigger Property="IsPressed" Value="True"> 
          <Setter Property="Background" > 
           <Setter.Value> 
            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" > 
             <GradientStop Color="#FECCBF" Offset="0.35"/> 
             <GradientStop Color="Red" Offset="0.95"/> 
             <GradientStop Color="#FECCBF" Offset="1"/> 
            </LinearGradientBrush> 
           </Setter.Value> 
          </Setter> 
          <Setter TargetName="content" Property="RenderTransform" > 
           <Setter.Value> 
            <TranslateTransform Y="1.0" /> 
           </Setter.Value> 
          </Setter> 
         </Trigger> 
         <Trigger Property="IsDefaulted" Value="True"> 
          <Setter TargetName="border" Property="BorderBrush" Value="#B20000" /> 
         </Trigger> 
         <Trigger Property="IsFocused" Value="True"> 
          <Setter TargetName="border" Property="BorderBrush" Value="#B20000" /> 
         </Trigger> 
         <Trigger Property="IsEnabled" Value="False"> 
          <Setter TargetName="border" Property="Opacity" Value="0.7" /> 
          <Setter Property="Foreground" Value="Gray" /> 
         </Trigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</Window.Resources> 

Cuando la línea clave es

<Trigger Property="IsMouseOver" Value="True"> 
    <Setter TargetName="border" Property="BorderBrush" Value="{TemplateBinding local:ThemeProperties.ButtonBorderColour}" /> 
    <Setter Property="Foreground" Value="#B20000" /> 
</Trigger> 

Por lo que yo puedo ver esto debería funcionar, pero me sale el siguiente error en tiempo de ejecución en la línea de arriba:

No se puede convertir el valor en el atributo 'Valor' a objeto de tipo ''. Error en el objeto 'System.Windows.Setter' en el archivo de marcado

¿He hecho algo incorrecto aquí? Soy nuevo en WPF y no puedo entender qué está pasando, ya que el tipo de propiedad adjunta es un Pincel, que es lo que esperaría que la propiedad BorderBrush de un borde quisiera.

Respuesta

39

Creo que TemplateBinding se evalúa en tiempo de compilación para que no pueda establecer dinámicamente un TemplateBinding en su Setter, intente utilizar Binding en su lugar (ver a continuación).

<Setter TargetName="border" Property="BorderBrush" 
     Value="{Binding Path=(local:ThemeProperties.ButtonBorderColour), 
         RelativeSource={RelativeSource TemplatedParent}}"/> 

Espero que esto ayude.

+0

Hola, he editado mi respuesta, debería funcionar ahora. Fue un error de sintaxis, lo siento. –

+0

Gracias XiaoChuan, que funcionó a la perfección. También puedo ver la diferencia entre mi código y el ejemplo en la página web vinculada, ya que el ejemplo no es usar TemplateBinding en un setter que no aprecié antes. ¡Gracias de nuevo! – thudbutt

+0

No entiendo por qué mi caso idéntico no funciona en tiempo de diseño (pero lo hace en tiempo de ejecución) - http://stackoverflow.com/questions/41614676/binding-style-property-value-to-an-attached -property-causes-design-time-only-e/41617979 –

1

Prueba esto:

<Setter TargetName="border" Property="BorderBrush" Value="{TemplateBinding Path=(local:ThemeProperties.ButtonBorderColour)}" /> 

La diferencia es que los paréntesis alrededor de la propiedad indican que se trata de una propiedad adjunta.

+0

Desafortunadamente eso no parece ser reconocido como sintaxis válida y simplemente devuelve un error de tipo '(local: ThemeProperties' no se encontró. – thudbutt

+2

Lo sentimos, se necesita 'Path =' delante de él. una peculiaridad en el analizador XAML. Actualizaré mi respuesta. –

+0

Todavía no es un placer, todavía se marcó como sintaxis inválida con el error "La propiedad 'Ruta' no se encontró en el tipo 'Expresión de vinculación de la plantilla'". – thudbutt

Cuestiones relacionadas