我在我的WPF UserControl
中有一个名为CustomForeground
的自定义依赖项属性。
如果没有在UserControl.ForeGround
上指定值,我希望它回退到CustomForeground
。
我正在使用以下代码,它可以工作,但它确实感觉有点hacky。
任何人都可以确认是否有一种“正确”的方式来实现这种依赖属性?
public SolidColorBrush CustomForeground
{
get { return (SolidColorBrush)(GetValue(CustomForegroundProperty) ?? GetValue(ForegroundProperty)); }
set { SetValue(CustomForegroundProperty, value); }
}
注意 - 我遗漏了DependencyProperty
的声明,因为它只是样板。
您可以使用自定义前景属性的Setter向用户控件添加样式,该属性将Binding设置为其Foreground属性。
除非CustomForeground属性值被另一个Binding或本地值或动画等替换,否则将使用Binding。
<UserControl ...>
<UserControl.Style>
<Style>
<Setter
Property="local:MyUserControl.CustomForeground"
Value="{Binding Foreground, RelativeSource={RelativeSource Self}}"/>
</Style>
</UserControl.Style>
...
</UserControl>
这应该做的伎俩:
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
var multiBinding = new MultiBinding()
{
Converter = FallbackColorConverter.Instance,
Mode = BindingMode.TwoWay,
Bindings =
{
new Binding()
{
Source = this,
Path = new PropertyPath(CustomForegroundBackingProperty),
Mode = BindingMode.TwoWay
},
new Binding()
{
Source = this,
Path = new PropertyPath(ForegroundProperty),
Mode = BindingMode.OneWay
},
},
};
SetBinding(CustomForegroundProperty, multiBinding);
}
public Brush CustomForeground
{
get => (Brush)GetValue(CustomForegroundProperty);
set => SetValue(CustomForegroundProperty, value);
}
public static readonly DependencyProperty CustomForegroundProperty =
DependencyProperty.Register(nameof(CustomForeground), typeof(Brush), typeof(MyControl), new PropertyMetadata(null));
private static readonly DependencyProperty CustomForegroundBackingProperty =
DependencyProperty.Register("CustomForegroundBacking", typeof(Brush), typeof(MyControl), new PropertyMetadata(null));
private class FallbackColorConverter : IMultiValueConverter
{
public static readonly FallbackColorConverter Instance = new FallbackColorConverter();
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values[0] ?? values[1];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { value };
}
}
}
我们设置了两个DependencyProperties。 CustomForegroundBackingProperty充当用户设置的任何CustomForeground值的实际存储。 CustomForegroundProperty只是一种代理。
然后将ForegroundProperty和CustomForegroundBackingProperty中的MultiBinding设置为CustomForegroundProperty。 MultiBinding设置为TwoWay(因此更改对CustomForegroundProperty的任何更改都会触发绑定,对ForegroundProperty或CustomForegroundBackingProperty的任何更改也是如此)。
我们将对CustomForegroundBackingProperty的绑定设置为TwoWay(因为我们希望写入CustomForegroundProperty以影响CustomForegroundBackingProperty),但我们将ForegroundProperty的绑定设置为OneWay,因为我们不希望这种情况发生。
然后我们在MultiBinding上放置一个转换器。当转换器写入CustomForegroundProperty时,它会查看CustomForegroundBackingProperty和ForegroundProperty,如果CustomForegroundBackingProperty是null
,则选择ForegroundProperty。如果ForegroundProperty或CustomForegroundBackingProperty更改,则会触发此操作。
当转换器以另一种方式写入时 - 即用户写入CustomForegroundProperty - 然后我们只返回它们设置的值。由于MultiBinding中绑定的模式,这意味着此值设置为CustomForegroundBackingProperty。
我不得不采用“自下而上”的解决方案,而不是像@Clemens这样的'自上而下'(因为我已经在UserControl
上定义了一种风格。它看起来像这样:
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="{Binding ValueBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ValueBrush}" Value="{x:Null}">
<Setter Property="Foreground" Value="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
</DataTrigger>
</Style.Triggers>
</Style>