现有颜色的新颜色,在 xaml 中制作 renamed/copy/alias
New Color from existing Color, making a renamed/copy/alias in xaml
我试图遵循“不要重复自己”原则 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-,因此不必(记住)更改所有控件的资源,我宁愿使用一个名为 "placeholder" 颜色的替代方案B,所以我只需要更改一次:
<Color x:Key="controlBorderColor">B</Color><!-- Not working -->
我不知道该怎么做。在XAML中是否有通用的"pattern"或定义"constants"的方法?
解决方法
不可能按照我想要的方式,查看答案。
简而言之解决方法(感谢@dotsven 处理亮度的巧妙技巧):将所有颜色定义为画笔,并使用标记扩展来检索 Color
属性。
AFAIK Color
不支持它的内容分配,因此没有简单的方法从 XAML 定义或绑定它而不单独对 A、R、G、 B等属性。画笔在这里充当包装器,因此我们可以绑定到颜色。
将所有颜色定义为Brush
es
<SolidColorBrush x:Key="B">
<SolidColorBrush.Color>
#FF808080
</SolidColorBrush.Color>
</SolidColorBrush>
创建一个 MarkupExtension 以从 SolidColorBrush
:
检索 Color
[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}}
以从画笔中检索它。
遗憾的是,无法创建作为另一个别名的静态资源。至少在 XAML.
中没有
如果您可以从代码访问资源字典,那么您可以只使用它的 Add
方法。毕竟是字典。
对于某些类型,例如 Style
s,您可以使用继承伪造别名。例如:
<Style x:Key="Foo">...</Style>
<Style x:Key="Bar" BasedOn="{StaticResource Foo}"/>
<!-- now Bar is an "alias" for Foo -->
遗憾的是,没有对此的直接支持。但是通过使用自定义标记扩展,您可以获得一个灵活的解决方法。创建这样的标记扩展:
[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 扩展。
我试图遵循“不要重复自己”原则 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-,因此不必(记住)更改所有控件的资源,我宁愿使用一个名为 "placeholder" 颜色的替代方案B,所以我只需要更改一次:
<Color x:Key="controlBorderColor">B</Color><!-- Not working -->
我不知道该怎么做。在XAML中是否有通用的"pattern"或定义"constants"的方法?
解决方法
不可能按照我想要的方式,查看答案。
简而言之解决方法(感谢@dotsven 处理亮度的巧妙技巧):将所有颜色定义为画笔,并使用标记扩展来检索 Color
属性。
AFAIK Color
不支持它的内容分配,因此没有简单的方法从 XAML 定义或绑定它而不单独对 A、R、G、 B等属性。画笔在这里充当包装器,因此我们可以绑定到颜色。
将所有颜色定义为Brush
es
<SolidColorBrush x:Key="B">
<SolidColorBrush.Color>
#FF808080
</SolidColorBrush.Color>
</SolidColorBrush>
创建一个 MarkupExtension 以从 SolidColorBrush
:
Color
[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}}
以从画笔中检索它。
遗憾的是,无法创建作为另一个别名的静态资源。至少在 XAML.
中没有如果您可以从代码访问资源字典,那么您可以只使用它的 Add
方法。毕竟是字典。
对于某些类型,例如 Style
s,您可以使用继承伪造别名。例如:
<Style x:Key="Foo">...</Style>
<Style x:Key="Bar" BasedOn="{StaticResource Foo}"/>
<!-- now Bar is an "alias" for Foo -->
遗憾的是,没有对此的直接支持。但是通过使用自定义标记扩展,您可以获得一个灵活的解决方法。创建这样的标记扩展:
[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 扩展。