WPF - 转换器作为 DependencyObject

Posted

技术标签:

【中文标题】WPF - 转换器作为 DependencyObject【英文标题】:WPF – Converter as DependencyObject 【发布时间】:2019-10-27 09:20:27 【问题描述】:

无法将值绑定到BindingConverterParametrBinding 只能设置在 DependencyPropertyDependencyObject 上。

我很好奇将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 仍然返回默认值。通过提供的Binding 没有改变AddInteger 的依赖属性是什么原因?


脚注:MultiBinding 对我没有帮助,因为ConvertBack 方法仅包含控件提供的值。这东西也应该在 ViewModel 中解决,但我很好奇有转换器的解决方案。

【问题讨论】:

【参考方案1】:

问题是,首先,转换器无法继承它所在的 DataContext,因此绑定无法工作:如果您在 VS 输出中添加跟踪,您将看到“未找到框架导师”您拥有的绑定(参见附录 A)。这也是您不能仅从 FrameworkElement 派生并使用 RelativeSource=RelativeSource AncestorType=Whatever 的原因:您已经脱离了可视化树。没有祖先。此外,即使有框架指导者,DependencyObject 也无法为绑定提供源。来源必须是明确的。只有从 FrameworkElement 继承的类才能继承 DataContext。

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

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

XAML

<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>

附录 A

AddInteger="Binding MyAddIntegerProperty, Mode=OneWay, 
    PresentationTraceSources.TraceLevel=High"
System.Windows.Data Warning: 56 : Created BindingExpression (hash=14964341) for Binding (hash=21653700)
System.Windows.Data Warning: 58 :   Path: 'MyAddIntegerProperty'
System.Windows.Data Warning: 60 : BindingExpression (hash=14964341): Default mode resolved to OneWay
System.Windows.Data Warning: 61 : BindingExpression (hash=14964341): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=14964341): Attach to WpfApp2.AddConverter2.AddInteger (hash=57434139)
System.Windows.Data Warning: 64 : BindingExpression (hash=14964341): Use Framework mentor <null>
System.Windows.Data Warning: 67 : BindingExpression (hash=14964341): Resolving source 
System.Windows.Data Warning: 69 : BindingExpression (hash=14964341): Framework mentor not found
System.Windows.Data Warning: 65 : BindingExpression (hash=14964341): Resolve source deferred
System.Windows.Data Warning: 67 : BindingExpression (hash=14964341): Resolving source 
System.Windows.Data Warning: 69 : BindingExpression (hash=14964341): Framework mentor not found

【讨论】:

因为转换器不是FrameworkElement,同样通过RelativeSource FindAncestor, …找到DataContext也无济于事。我知道了。谢谢你的例子。 @David 正确。此外,即使您确实从 FrameworkElement 继承,FindAncestor 也不会工作,因为您已经脱离了可视化树 - 再也没有框架导师了。

以上是关于WPF - 转换器作为 DependencyObject的主要内容,如果未能解决你的问题,请参考以下文章

在 C# WPF 中将 ImageSource 转换为字符串

WPF DataGrid MultiBinding到DataGrid ItemSsource中的类

wpf学习20180606

在WPF中将图片转换成3D图像并可以旋转

将 uint8 字节数组转换为任何 WPF 呈现对象

在 VS 2010 中将控制台应用程序转换为 WPF 应用程序时遇到问题