WPFのBindableConverter

問題: WPFはクールなテクノロジーですが、一部の場所では未完成です。 たとえば、このようなコードは吐き出されます。ConverterParameterはDependencyObjectの継承者ではないため、どのような例外を正確に覚えていません。



<...Text={Binding SourceProperty, Converter={StaticResource SomethingToSomethingElseConverter} ConverterParameter={Binding AnotherSourceProperty}} />
      
      





実際、これは問題です。 以下は彼女の決定です。



1/18/16からの更新:

1)コンバーターの基本クラスがFreezableから継承される場合、プロキシは単に必要ありません。 この場合、コンバーターは通常のコンバーターとまったく同じように機能します。

 <-.Resources> <converters:-_ x:Key="-_" BindingParameter1="{Binding -_}" /> </-.Resources>
      
      





...読むときにこれを考慮してください!



原則として、問題を解決する方法は2つあります。1つ目はDependencyProperty.Register(..)、2つ目は.RegisterAttached(..)です。 違いは、2番目のオプションが概念的およびアーキテクチャ的に欠陥があることです。 したがって、このように:



 using System; using System.Globalization; using System.Windows; using System.Windows.Data; namespace BindableConverter { [ValueConversion(typeof(object), typeof(object))] public class BindableConverterBase : DependencyObject, IValueConverter, IMultiValueConverter { #region BindableParameters #region BindableParameter1 public object BindableParameter1 { get { return GetValue(BindableParameter1Property); } set { SetValue(BindableParameter1Property, value); } } public static readonly DependencyProperty BindableParameter1Property = DependencyProperty.Register( nameof(BindableParameter1), typeof(object), typeof(BindableConverterBase), new PropertyMetadata(String.Empty) ); #endregion #region BindableParameter2 public object BindableParameter2 { get { return GetValue(BindableParameter2Property); } set { SetValue(BindableParameter2Property, value); } } public static readonly DependencyProperty BindableParameter2Property = DependencyProperty.Register( nameof(BindableParameter2), typeof(object), typeof(BindableConverterBase), new PropertyMetadata(String.Empty) ); #endregion #region BindableParameter3 public object BindableParameter3 { get { return GetValue(BindableParameter3Property); } set { SetValue(BindableParameter3Property, value); } } public static readonly DependencyProperty BindableParameter3Property = DependencyProperty.Register( nameof(BindableParameter3), typeof(object), typeof(BindableConverterBase), new PropertyMetadata(String.Empty) ); #endregion #endregion #region IValueConverter public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } #endregion #region IMultiValueConverter public virtual object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } public virtual object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } #endregion } }
      
      







クラスは両方のインターフェイスを実装しているため、通常のBindingとMultiBindingの両方で機能します。 実際、BindableConverterから継承するだけで、必要な(または必要な希少性)メソッドをオーバーライドします。



XAMLで使用する場合、1つの基本的なポイントがあります。 タイプの素朴な試み:

 <Window.Resources> <local:NameAndAgeToVladimirPutinConverter x:Key="NameAndAgeToVladimirPutin" BindableParameter1="{Binding FirstName}" BindableParameter2="{Binding Age}" /> </Window.Resources>
      
      





...は、両方のパラメーターがデフォルト値に等しいという結果になります。 常に-コンバーターへのリンクをリソースのどこで宣言しても。



私はこれがなぜ起こるのか最終的に理解していないと告白します。 一般的に言えば、ポイントはコンバーターがLogical \ VisualTree UI要素の外側にあるということです。そのため、コンバーターにアタッチする人はいません。 いずれにしても、これはStackOverflowで掘り下げた説明です。 問題の解決策は次のようになります。



 <bc:BindingProxy x:Key="BindingProxy" Data="{Binding}" /> <local:NameAndAgeToVladimirPutinConverter x:Key="NameAndAgeToVladimirPutin" BindableParameter1="{Binding Source={StaticResource BindingProxy}, Path=Data.FirstName}" BindableParameter2="{Binding Source={StaticResource BindingProxy}, Path=Data.Age}"/> ... <TextBlock Grid.Row="0" Text="{Binding Name, Converter={StaticResource NameAndAgeToVladimirPutin}}" />
      
      







 using System.Windows; namespace BindableConverter { public class BindingProxy : Freezable { protected override Freezable CreateInstanceCore() { return new BindingProxy(); } /// <summary> /// Binding data. /// </summary> public object Data { get { return GetValue(DataProperty); } set { SetValue(DataProperty, value); } } public static readonly DependencyProperty DataProperty = DependencyProperty.Register( nameof(Data), typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null) ); } }
      
      







PS Converter = {bc:BindableConverter BindingProxy = {StaticResource Proxy}、Parameter1 = FirstName、Parameter2 = Age}のようなことを行えるように、MarkupExtensionをねじ込む計画があります。 誰かがそれをもっと美しく簡潔にする方法を考えているなら、どうぞ。



なぜBindingProxyなしでも同じことが機能しないのかという問題も非常に重要です。



All Articles