AttachedPropertyを使用したWindowsコントロール機能の拡張





Windowsアプリケーション開発(WPF、SilverLight、WP、WinRT)の基礎はMVVMパターンです。 これは、プレゼンテーションモデルのデータとユーザーインターフェイスをリンクするという概念に基づいています。これにより、XAMLを使用したUIの宣言的な記述を使用して、コードビハインドを取り除き(ロシア語の翻訳を思いついたことがありませんでした)、ユーザーインターフェイスを操作するすべてのロジックをプレゼンテーションモデルに転送できます。



残念ながら、製造業者がすべての可能な機能をフレームワークに実装することは物理的に不可能であり、利用可能な手段で必要な問題を解決できない場合がしばしば起こります。 問題が単純で1回限りの場合、分離コード表現により、発生した場所で迅速に解決されます。 ただし、多くの場所で同じ機能が必要な場合は、ソリューションを再利用するための便利なメカニズムを実装する必要があります。



「ユニバーサルWindowsアプリケーションでの自動リンク割り当て」という記事によって、この記事を書くことに触発されました。 この記事では、特定の問題の解決策を見つけ、実用的な解決策を提案しました。 ただし、それを使用するには、各テキストブロックに対してコードビハインドのコードを呼び出す必要があります。 さらに、データが作業プロセスの変化を示唆している場合、それらの変化を監視する必要があります。 私の仕事の過程で、私はそのような決定に頻繁に会います。実装は異なりますが、それらはすべて、1つの不変の特性、コードのサポートと保守の複雑さによって区別されます。



このような問題を解決するには、アタッチ可能なプロパティ(AttachedProperty)を使用する必要があります。この技術は、問題の解決に必要な3つの機能を提供します。



1)値が設定されたコントロールのコンテキストに値を保存します

2)プロパティデータが変更されたときに通知する

3)XAMLの宣言的バインドに使用



添付プロパティを使用して上記の例の問題を解決しますこれを行うには、RtbExという新しい静的クラスを作成し、新しいAttachedPropertyの説明を追加します。



public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached("Text", typeof(string), typeof(RtbEx), new PropertyMetadata(default(string))); public static void SetText(DependencyObject element, string value) { element.SetValue(TextProperty, value); } public static string GetText(DependencyObject element) { return (string) element.GetValue(TextProperty); }
      
      





プロパティに名前Textと値型文字列を指定しました。 [Set | Get] Textメソッドには特に注意を払います。これらのメソッドは、推奨されるプロパティ宣言テンプレートに従うために追加され、プロパティ値へのアクセスを簡素化することを目的としています。 これで、このプロパティを使用して、コントロールに関連付けられたデータを保存できます。



 var someText = “Some Text”; RtbEx.SetText(richTextBlock, someText); someText = RtbEx.GetText(richTextBlock);
      
      





ただし、プロパティを変更するときに追加の動作を実装するには、テキストの解析とRTBコンテンツの生成の作業を行う必要があります。そのため、プロパティ値が変更されるたびに呼び出される各プロパティのハンドラーを定義できます。

イベントハンドラは、2番目のプロパティメタデータパラメータの添付プロパティの説明で指定する必要があります。



 public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached("Text", typeof(string), typeof(RtbEx), new PropertyMetadata(default(string), OnTextChanged));
      
      





プロパティ変更イベントハンドラは、PropertyChangedCallbackタイプである必要があります



 private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var richTextBlock = d as RichTextBlock; if (richTextBlock == null) { return; } richTextBlock.Blocks.Clear(); var text = e.NewValue as string; if (string.IsNullOrWhiteSpace(text)) { return; } richTextBlock.Blocks.Add(CreateParagraph(text)); }
      
      





ハンドラーは可能な限りシンプルです。RichTextBlockの呼び出しを決定し、コントロールのデータをクリアします。新しいプロパティ値が空の文字列でない場合は、コントロールに新しいデータを入力します。



 private static Paragraph CreateParagraph(string text) { var paragraph = new Paragraph(); var splitResult = Regex.Split(text, @"(https?://\S+)"); foreach (var part in splitResult) { if (part.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { var hyperLink = new Hyperlink {NavigateUri = new Uri(part)}; hyperLink.Inlines.Add(new Run {Text = part}); paragraph.Inlines.Add(hyperLink); continue; } paragraph.Inlines.Add(new Run {Text = part}); } return paragraph; }
      
      





RTBコンテンツ生成コードはタスクのコンテキストでは重要ではなく、理想からはほど遠いです。リンクとプレーンテキストを含むブロックに行を単純に分割し、その後RichTextBlockドキュメントプレゼンテーションの階層を構築します。



この方法でフォーマットされた拡張機能は、追加のコードを使用せずに、従来のデータバインディングを使用してXAMLから使用できます。



これを行うには、拡張機能を含む名前空間をXAMLドキュメントに追加します



 xmlns:ex="using:RtbEx.Extensions"
      
      





そして、通常の{binding}を使用してバインディングを設定します



 <RichTextBlock ex:RtbEx.Text="{Binding SomeText}" FontSize="20"/>
      
      







添付プロパティの使用は想像力によってのみ制限されます。それらを使用すると、コードの開発、再利用、サポートを大幅に簡素化する多くの便利な拡張機能を実装できます。



テストアプリケーションコードはGithubで入手できます: https : //github.com/Viacheslav01/RtbEx



All Articles