WPF –转换器作为DependencyObject

时间:2019-06-12 19:41:57

标签: wpf binding wpf-controls converters

不可能将值绑定到ConverterParametr的{​​{1}}。只能在Binding中的Binding上设置DependencyProperty

我很好奇将DependencyObject转换器实现为IValueConverter

DependencyObject

让我们在示例视图中查看吧。

public class AddConverter : DependencyObject, IValueConverter
{
    public static readonly DependencyProperty AddIntegerProperty =
        DependencyProperty.Register(nameof(AddInteger),
            typeof(int),
            typeof(AddConverter),
            new PropertyMetadata(0));

    public int AddInteger
    {
        get => (int)GetValue(AddIntegerProperty);
        set => SetValue(AddIntegerProperty, value);
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is int intValue)) return 0;
        return intValue + AddInteger;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int intValue;
        try
        {
            intValue = System.Convert.ToInt32(value);
        }
        catch (Exception)
        {
            return 0;
        }

        return intValue - AddInteger;
    }
}

结果是<TextBox> <TextBox.Text> <Binding Path="MyIntegerProperty"> <Binding.Converter> <local:AddConverter AddInteger="{Binding MyAddIntegerProperty, Mode=OneWay}" /> </Binding.Converter> </Binding> </TextBox.Text> </TextBox> 仍返回默认值。通过提供的AddInteger AddInteger依赖属性没有变化的原因是什么?


脚注:由于Binding方法仅由控件提供的值组成,因此MultiBinding对我没有帮助。这些东西也应该在ViewModel中解决,但是我很好奇转换器的解决方案。

1 个答案:

答案 0 :(得分:1)

问题是,首先,转换器无法继承其所在的DataContext,因此绑定无法正常工作:如果在VS上进行跟踪,您将在VS输出中看到“找不到框架导师”您拥有的绑定(请参阅附录A)。这也是为什么不能仅从FrameworkElement派生并使用 export const getChannels = () => dispatch => { const token = "token"; axios .get(`https://slack.com/api/conversations.list?token=${token}`) .then(response => { dispatch({ type: actionTypes.GET_CHANNELS, payload: response.data }) }); }; }; 的原因:您不在可视化树中。没有祖先。同样,即使有框架指导者,DependencyObject也不能提供绑定的源。来源必须明确。仅继承自FrameworkElement的类可以继承DataContext。

因此,我偷了BindingProxy类(from this answer),并使用该类为绑定提供了源。这有点笨拙,但是我想到的另一种选择是从Freezable继承转换器,从本质上赋予它BindingProxy的属性,并在资源中创建转换器。它起作用了,但是我更喜欢这种组织方式。

RelativeSource={RelativeSource AncestorType=Whatever}

XAML

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    #region Data Property
    public Object Data
    {
        get { return (Object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register(nameof(Data), typeof(Object), typeof(BindingProxy),
            new PropertyMetadata(null));
    #endregion Data Property
}

附录A

<StackPanel.Resources>
    <local:BindingProxy
        x:Key="VMProxy"
        Data="{Binding}"
        />
</StackPanel.Resources>
<TextBlock>
    <TextBlock.Text>
        <Binding Path="MyIntegerProperty">
            <Binding.Converter>
                <local:AddConverter
                    AddInteger="{Binding Data.MyAddIntegerProperty, Source={StaticResource VMProxy}}" 
                    />
            </Binding.Converter>
        </Binding>
    </TextBlock.Text>
</TextBlock>
AddInteger="{Binding MyAddIntegerProperty, Mode=OneWay, 
    PresentationTraceSources.TraceLevel=High}"