XAML開発者チップ:条件付きコンバーター

スイッチコンバーターは特別な注意に値します。 シンプルで便利、驚くほどの汎用性があります。 それに基づいて、新しいクラスを宣言せずに、多くの一般的なタイプのコンバーターを簡単に構築できます。信じられません-ようこそ!

画像

中規模および大規模プロジェクトの分析プロセスでは、重要なパターンを特定できます。実際、コンバータークラスの重要な部分には、 if-elseコンストラクトswitch-case-defaultに相当するロジックが含まれています 。 すぐに、すべてを共通の分母に減らして、双子のクラスを作成したくないという要望がありますが、これはそれほど難しくありません。



ISwitchConverter
using System; using System.Collections.Generic; using System.Windows.Data; namespace Aero.Converters.Patterns { public class CaseSet : List<ICase> { public static readonly object UndefinedObject = new object(); } public interface ICase { object Key { get; set; } object Value { get; set; } Type KeyType { get; set; } } public interface ISwitchConverter : IValueConverter { CaseSet Cases { get; } object Default { get; set; } bool TypeMode { get; set; } } }
      
      







ICompositeConverter
 using System.Windows.Data; namespace Aero.Converters.Patterns { public interface ICompositeConverter : IValueConverter { IValueConverter PostConverter { get; set; } object PostConverterParameter { get; set; } } }
      
      







スイッチコンバーター
 using System; using System.Globalization; using System.Linq; using System.Windows; using System.Windows.Data; using System.Windows.Markup; using Aero.Converters.Patterns; namespace Aero.Converters { [ContentProperty("Cases")] public class SwitchConverter : DependencyObject, ISwitchConverter, ICompositeConverter { public static readonly DependencyProperty DefaultProperty = DependencyProperty.Register( "Default", typeof(object), typeof(SwitchConverter), new PropertyMetadata(CaseSet.UndefinedObject)); public SwitchConverter() { Cases = new CaseSet(); } public object Default { get { return GetValue(DefaultProperty); } set { SetValue(DefaultProperty, value); } } public CaseSet Cases { get; private set; } public bool TypeMode { get; set; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (TypeMode) value = value == null ? null : value.GetType(); var pair = Cases.FirstOrDefault(p => Equals(p.Key, value) || SafeCompareAsStrings(p.Key, value)); var result = pair == null ? Default : pair.Value; value = result == CaseSet.UndefinedObject ? value : result; return PostConverter == null ? value : PostConverter.Convert(value, targetType, PostConverterParameter, culture); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (TypeMode) value = value == null ? null : value.GetType(); var pair = Cases.FirstOrDefault(p => Equals(p.Value, value) || SafeCompareAsStrings(p.Value, value)); value = pair == null ? Default : pair.Key; return PostConverter == null ? value : PostConverter.ConvertBack(value, targetType, PostConverterParameter, culture); } private static bool SafeCompareAsStrings(object a, object b) { if (a == null && b == null) return true; if (a == null || b == null) return false; return string.Compare(a.ToString(), b.ToString(), StringComparison.OrdinalIgnoreCase) == 0; } public IValueConverter PostConverter { get; set; } public object PostConverterParameter { get; set; } } }
      
      







コンバーターは非常に単純に使用され、デフォルト値が設定されていない場合( default )、変換を使用します-以下の両方の例を比較してください。



 <Grid.Resources> <SwitchConverter x:Key="NumberSwitchConverter"> <Case Key="0" Value="Zero"/> <Case Key="1" Value="One"/> </SwitchConverter> </Grid.Resources> <TextBlock Text="{Binding Number, Converter={StaticResource NumberSwitchConverter}}"/> Number==0 => out: Zero Number==1 => out: One Number==2 => out: 2
      
      





 <Grid.Resources> <SwitchConverter x:Key="NumberSwitchConverter" Default="Hello"> <Case Key="0" Value="Zero"/> <Case Key="1" Value="One"/> </SwitchConverter> </Grid.Resources> <TextBlock Text="{Binding Number, Converter={StaticResource NumberSwitchConverter}}"/> Number==0 => out: Zero Number==1 => out: One Number==2 => out: Hello
      
      





数字、列挙、文字列、ブール値で簡単に動作し、 連鎖構成もサポートします。



さらに、別の重要なボーナスがあります。 WPFには、たとえばWindows Phone Silverlightではサポートされていないテンプレートセレクターの概念があります。 使用していた場合、確かに、それほど便利ではないことに注意してください-C#クラスを作成する必要があります。C#クラスでは、あまり美しくない方法でXAMLリソースにアクセスできます。 MSDNの例をご覧ください。



実際には、ほとんどの実際の場合のテンプレートセレクターのタスクは、従来のコンバーターの使用に簡単に減らすことができ、 テンプレートセレクターの唯一の利点は、テンプレートが適用されるデータコンテナーへのアクセスの追加提供です。



特にこのようなシナリオでは、 Switch Converterは特別なタイプモードをサポートします。値のキーはオブジェクトのタイプです。



 <SwitchConverter TypeMode="True" Default="{StaticResource DefaultDataTemplate}" x:Key="InfoConverter"> <Case KeyType="local:Person" Value="{StaticResource PersonDataTemplate}"/> <Case KeyType="local:PersonGroup" Value="{StaticResource PersonGroupDataTemplate}"/> </SwitchConverter>
      
      





 <ListBox ItemsSource="{Binding Items}"> <ListBox.ItemTemplate> <DataTemplate> <ContentControl Template="{Binding Converter={StaticResource TemplateSelectorConverter}}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
      
      





すべてのロジックがマークアップに含まれているため、 C#コードからXAMLリソースにアクセスする必要がなく、テンプレートセレクターを実装するために別のクラスを作成する必要がないことは注目に値します。



このようなものをお楽しみください。

さまざまなコンバーターの使用例は、 Aero Frameworkライブラリ[ バックアップリンク ]で利用できます。



ご清聴ありがとうございました!



PS 複合コンバーターに関する前の記事



All Articles