依赖属性-继承自另一个属性?

时间:2019-04-11 11:56:24

标签: c# wpf dependency-properties

我在WPF UserControl中有一个名为CustomForeground的自定义依赖项属性。

如果未在UserControl.ForeGround上指定任何值,我希望它回退到CustomForeground

我正在使用下面的代码,该代码可以正常工作,但是肯定有点黑。

任何人都可以确认确认是否存在实现此依赖项属性的“正确”方法吗?

public SolidColorBrush CustomForeground
{
      get { return (SolidColorBrush)(GetValue(CustomForegroundProperty) ?? GetValue(ForegroundProperty)); }
      set { SetValue(CustomForegroundProperty, value); }
}

注意-我省略了DependencyProperty的声明,因为它只是样板。

3 个答案:

答案 0 :(得分:3)

您可以使用Setter为CustomForeground属性向用户控件添加样式,该属性将Binding设置为其Foreground属性。

除非使用其他绑定或本地值或动画等替换CustomForeground属性值,否则将使用Binding。

<UserControl ...>
    <UserControl.Style>
        <Style>
            <Setter
                Property="local:MyUserControl.CustomForeground"
                Value="{Binding Foreground, RelativeSource={RelativeSource Self}}"/>
        </Style>
    </UserControl.Style>
    ...
</UserControl>

答案 1 :(得分:0)

这应该可以解决问题:

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到CustomForegroundProperty的MultiBinding。 MultiBinding设置为TwoWay(因此,对CustomForegroundProperty进行的任何更改都会触发绑定,对ForegroundProperty或CustomForegroundBackingProperty的任何更改也会触发绑定。)

我们将到CustomForegroundBackingProperty的绑定设置为TwoWay(因为我们要写入CustomForegroundProperty来影响CustomForegroundBackingProperty),但是我们不希望将到ForegroundProperty的绑定设置为OneWay。

然后我们在MultiBinding上放置一个转换器。当转换器写入CustomForegroundProperty时,它将同时查看CustomForegroundBackingProperty和ForegroundProperty,如果CustomForegroundBackingProperty为null,则选择ForegroundProperty。如果ForegroundProperty或CustomForegroundBackingProperty发生更改,则会触发此事件。

当转换器以另一种方式写(即用户写到CustomForegroundProperty)时,我们只返回他们设置的值。由于MultiBinding中绑定的模式,这意味着此值将设置为CustomForegroundBackingProperty。

答案 2 :(得分:0)

我不得不采用“自下而上”的解决方案,而不是像@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>