WPF – 作为 DependencyObject 的转换器
WPF – Converter as DependencyObject
无法将值绑定到 Binding
的 ConverterParametr
。 Binding
只能设置在 DependencyObject
的 DependencyProperty
上。
我很好奇如何将 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
仍然是 returns 默认值。通过提供的 Binding
AddInteger
依赖性 属性 没有变化的原因是什么?
脚注: MultiBinding
对我没有帮助,因为 ConvertBack
方法仅包含控件提供的值。这玩意在ViewModel中应该也能解决,不过我很好奇有转换器的解决方法
问题是,首先,转换器无法在其所在的位置继承 DataContext,因此绑定无法工作:如果放置跟踪,您将在 VS 输出中看到 "Framework mentor not found"在你的绑定上(见附录 A)。这也是您不能仅从 FrameworkElement 派生并使用 RelativeSource={RelativeSource AncestorType=Whatever}
的原因:您超出了可视化树。没有祖先。此外,即使有框架导师,DependencyObject 也无法为绑定提供源。来源必须是明确的。只有从 FrameworkElement 继承的 classes 才能继承 DataContext。
所以我偷了一个 BindingProxy class (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
无法将值绑定到 Binding
的 ConverterParametr
。 Binding
只能设置在 DependencyObject
的 DependencyProperty
上。
我很好奇如何将 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
仍然是 returns 默认值。通过提供的 Binding
AddInteger
依赖性 属性 没有变化的原因是什么?
脚注: MultiBinding
对我没有帮助,因为 ConvertBack
方法仅包含控件提供的值。这玩意在ViewModel中应该也能解决,不过我很好奇有转换器的解决方法
问题是,首先,转换器无法在其所在的位置继承 DataContext,因此绑定无法工作:如果放置跟踪,您将在 VS 输出中看到 "Framework mentor not found"在你的绑定上(见附录 A)。这也是您不能仅从 FrameworkElement 派生并使用 RelativeSource={RelativeSource AncestorType=Whatever}
的原因:您超出了可视化树。没有祖先。此外,即使有框架导师,DependencyObject 也无法为绑定提供源。来源必须是明确的。只有从 FrameworkElement 继承的 classes 才能继承 DataContext。
所以我偷了一个 BindingProxy class (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