来自现有Color的新颜色,在xaml

时间:2015-07-28 20:02:38

标签: wpf xaml colors alias solidcolorbrush

我试图遵循XAML的“不要重复自己”的原则,但我已经达到了我正在努力的地步。

我正在为蒙皮定义颜色。 假设我已经定义了我想要基于皮肤的颜色:

<ResourceDictionary>
    ...
    <Color x:Key="B+">#FF999999</Color>
    <Color x:Key="B">#FF808080</Color>
    <Color x:Key="B-">#FF666666</Color>
    ...
</ResourceDictionary>

现在说我想使用颜色B作为我的边框颜色,我会设置文本框,按钮等的BorderBrush样式:

<Style TargetType="TextBox">
    <Setter Property="BorderBrush">
        <Setter.Value>
            <SolidColorBrush Color="{StaticResource B}" />
        </Setter.Value>
    </Setter> 
</Style>
<Style TargetType="Button">
    <Setter Property="BorderBrush">
        <Setter.Value>
            <SolidColorBrush Color="{StaticResource B}" />
        </Setter.Value>
    </Setter> 
</Style>

现在假设我想使用更暗的音调,B-,而不是(记住)更改所有控件的资源,我宁愿有一个替代名为“占位符”的颜色来自B,所以我只需要改变一次:

<Color x:Key="controlBorderColor">B</Color><!-- Not working -->

我对如何做到这一点感到茫然。在XAML中是否有一般的“模式”或定义“常量”的方法?

解决方案解决方案

不可能以我想要的方式,看到答案。

简而言之解决方法(感谢@dotsven处理亮度的巧妙技巧):将所有颜色定义为画笔,并使用标记扩展来检索Color属性。

AFAIK Color不支持内容分配,因此XAML没有简单的方法来定义或绑定它,而无需单独对A,R,G,B等属性进行分类。画笔类型在这里用作包装器,因此我们可以绑定到Color。

将所有颜色定义为Brush es

<SolidColorBrush x:Key="B">
    <SolidColorBrush.Color>
        #FF808080
    </SolidColorBrush.Color>
</SolidColorBrush>

创建MarkupExtension以从Color

中检索SolidColorBrush
[MarkupExtensionReturnType(typeof(Color))]
public class SkinColorExtension : MarkupExtension {
  public SkinColorExtension() {
  }

  public SkinColorExtension(SolidColorBrush baseColor, int brightness) {
    this.BaseColor = baseColor;
    this.Brightness = brightness;
  }

  [ConstructorArgument("baseColor")]
  public SolidColorBrush BaseColor { get; set; }
  [ConstructorArgument("brightness")]
  public int Brightness { get; set; }

  public override object ProvideValue(IServiceProvider serviceProvider) {
    return SkinColor_Helper.ApplyBrightness(BaseColor.Color, Brightness);
  }
}

static class SkinColor_Helper {
  public static Color ApplyBrightness(Color c, int b) {
    Func<int, byte> Scale = (val) => {
      int scaledVal = val + b;
      if (scaledVal < 0) return 0;
      else if (scaledVal > 255) return 255;
      else return (byte)scaledVal;
    };
    return Color.FromArgb(c.A, Scale(c.R), Scale(c.G), Scale(c.B));
  }
}

然后按照亮度偏移创建我的蒙皮颜色:

<SolidColorBrush x:Key="controlBorder" Color="{ext:SkinColor BaseColor={StaticResource B}, Brightness=-25}"/>
<SolidColorBrush x:Key="controlBackground" Color="{ext:SkinColor BaseColor={StaticResource B}, Brightness=-100}" />

当控件需要画笔时,例如Background,只需绑定到{StaticResource controlBackground}

如果必须绑定到需要Color的内容,请绑定到{ext:SkinColor BaseColor={StaticResource controlBackground}}以从刷子中检索它。

2 个答案:

答案 0 :(得分:2)

不幸的是,无法创建一个属于另一个的别名的静态资源。至少不在XAML中。

如果您可以从代码访问资源字典,那么您可以使用其Add方法。毕竟它是一本字典。

对于某些类型,例如Style,您可以使用继承伪造别名。例如:

<Style x:Key="Foo">...</Style>
<Style x:Key="Bar" BasedOn="{StaticResource Foo}"/>
<!-- now Bar is an "alias" for Foo -->

答案 1 :(得分:2)

不幸的是,没有直接的支持。但是通过使用自定义标记扩展,您可以获得灵活的解决方法。创建一个这样的标记扩展:

[MarkupExtensionReturnType(typeof(Color))]
public class RelativeColorExtension : MarkupExtension
{
    public RelativeColorExtension()
    {
    }

    public RelativeColorExtension(Color baseColor)
    {
        this.BaseColor = baseColor;
    }

    [ConstructorArgument("baseColor")]
    public Color BaseColor { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return Color.FromArgb(this.BaseColor.A, (Byte)(this.BaseColor.R / 2), (Byte)(this.BaseColor.G /2), (Byte)(this.BaseColor.B / 2));
    }
}

然后您可以按如下方式使用它:

    <Grid.Resources>
        <Color x:Key="Color1" R="10" G="10" B="128" A="255" />
        <SolidColorBrush x:Key="Color1Brush" Color="{StaticResource Color1}" />
        <SolidColorBrush x:Key="Color2Brush" Color="{ext:RelativeColor BaseColor={StaticResource Color1}}" />            
    </Grid.Resources>

请注意,您必须在单独的程序集中实现标记扩展。您可以使用允许您以多种方式调暗,变亮或操纵基色的属性来扩展markuop扩展。