WPF - 转换器作为 DependencyObject
Posted
技术标签:
【中文标题】WPF - 转换器作为 DependencyObject【英文标题】:WPF – Converter as DependencyObject 【发布时间】:2019-10-27 09:20:27 【问题描述】:无法将值绑定到Binding
的ConverterParametr
。 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
仍然返回默认值。通过提供的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 转换为字符串