アーカイブ

'PropertyValueEditor "タグの記事

Silverlightのコントロールのプロパティ値エディタ

はじめに

これは、デザイン時実装の ​​変更のシリーズの一部であるSilverlight Toolkitの 2009年3月リリース このポストはプロパティ値エディタと型コンバータを使用してSilverlightコントロールのプロパティの編集経験を強化する方法について説明します。 私はWPF / Silverlightのデザイナの機能拡張フレームワークで全体のプロパティを編集するアーキテクチャを記述すると開始され、その後で例を使用してSilverlight Toolkitの 2009年3月版リリース 、それがどのように行われるかを実証するため、およびSilverlightの設計時の開発に特有の問題/トリック。

プロパティ編集アーキテクチャ

視覚的にオブジェクトのプロパティを編集すると、デザイナーの重要な部分です。 設計者は通常、良い編集ユーザーインターフェイスを提供するために、はるかに少ないのカスタム型のプロパティ(構造体、クラスまたはインタフェース)をレンダリングする方法を知りません。 コントロールの開発者は通常、提供する必要がありますTypeConverterがPropertyValueEditorカスタム型のプロパティのUIとXAMLのシリアル化をレンダリング/編集を提供する、またはその両方を。

インラインエディタ、拡張エディタ、ダイアログエディタで、クラスによって実装されている各:デザイナの機能拡張フレームワークは、プロパティ値エディタの3つのタイプを定義しています。

PropertyValueEditor class diagram

これらのエディタのUIを編集することによって定義されているDataTemplateを 編集されているプロパティは、エディタにさらされたDataContextがPropertyValueのタイプ。 エディタUIは通常の3つのプロパティのいずれかを経由して編集されて基本的なプロパティにバインドがPropertyValueStringValue 、またはコレクション

PropertyValueEditor

PropertyValueEditorはによって定義される単一のインラインエディタを保持InlineEditorTemplateのプロパティを。 インラインエディタは、プロパティウィンドウ内に表示されます。 以下の簡単な例ですInlineEditorTemplateプロパティを表示および編集するテキストボックス(TextBox)コントロールを使用しています。

  x:Key ="TextBoxEditor" > <DataTemplate X:キー = "TextBoxEditor">
     Text ="{Binding Path=Value}" /> <TextBox テキスト = "{バインディングパス=値}" />
 > </ DataTemplateを > 

ExtendedPropertyValueEditor

ExtendedPropertyValueEditorはから継承されたインラインエディタ:2エディタがあるPropertyValueEditor 、と定義されている追加の拡張エディタExtendedEditorTemplateのプロパティを。 拡張エディタは、通常、インラインエディタによって開かれた 以下の簡単な例は、次のとおりです。インラインエディタは、ボタンです。クリックしたときに、それは、基礎となるプロパティを表示および編集するスライダーを使用する拡張エディタをポップアップ表示されます。
  x:Key ="inlineEditor" > <DataTemplate X:キー = "inlineEditor">
     Content ="..." Command ="{x:Static PropertyEditing:PropertyValueEditorCommands.ShowDialogEditor}" /> < ボタン 内容 = "..." コマンド = "{x:StaticのPropertyEditing:PropertyValueEditorCommands.ShowDialogEditor}" />
 > </ DataTemplateを >

     x:Name ="slider" Value ="{Binding Path=Value}" /> < スライダー X:名前 = "スライダー"  = "{バインディングパス=値}" />
 > </ DataTemplateを > 

DialogPropertyValueEditor

DialogPropertyValueEditorは、あまりにも2つのエディタをがあります。から継承されたインラインエディタPropertyValueEditor 、と定義されている追加のダイアログエディタDialogEditorTemplateのプロパティを。 ダイアログエディタは、通常は経由インラインエディタによって開かれたPropertyValueEditorCommandsShowDialogEditorのコマンドは。 以下の簡単な例は、次のとおりです。

 x:Key ="inlineEditor" > < Button Content ="..." Command ="{x:Static <DataTemplate X:キー = "inlineEditor"> < ボタン 内容 = "..." コマンド = "{x:Staticの  ="Center" HorizontalAlignment ="Right" Margin ="0,0,4,4" /> < TextBox Text ="{Binding 名前: " には、VerticalAlignment ="センターでは、右" マージン =" "=を HorizontalAlignmentを " 0,0,4,4 "/> <TextBox テキスト =" {バインディング 

カスタムプロパティエディタを実装します。

Silverlightコントロールのカスタムプロパティエディタを実装するには:

  • カスタムプロパティエディタクラスを実装する
  • AddCustomAttributes呼び出しを介してSilverlightコントロールのプロパティとカスタムプロパティエディタのようなものを関連付ける
      attributeTableBuilder.AddCustomAttributes(
         typeof演算 (MyControl)
         "MyPropertyに"
         (MyValueEditor))); 新しいPropertyValueEditor.CreateEditorAttribute(typeof演算 (MyValueEditor))); 

    正しく実装されたプロパティ値エディタは、次の要件を満たす必要があります。

  • プロパティ値エディタがインラインエディタと拡張エディタ部が独立して使用することができるように設計する必要があります。
  • プロパティ値エディタは状態を格納してはいけません。 プロパティ値エディタはステートレスであり、ホスト実装によってキャッシュされる可能性があり、複数のプロパティ値で再使用することができます。
  • プロパティ値エディタは1つだけ値エディタ部(ビュー/インライン/拡張)コントロールは、特定の時点でアクティブであることを仮定してはいけません。 たとえば、ダイアログボックスは、ビューの部分は、インライン部分と、同時にアクティブに拡張されたUIの部分を持つことができます。
  • プロパティ値エディタの一部として実装コントロールの状態を格納してはいけません。 値エディタの一部として実装されコントロールが1つだけのプロパティ値にバインドされることを仮定するべきではありません。 コントロールは、異なるプロパティ値を変更するには、リサイクルすることができる。 データモデルが更新された場合キャッシュされているすべての情報がフラッシュされるべきである。
  • プロパティ値エディタの一部として実装されコントロールは、ホストまたは親コントロールについて一切想定してはならない。 使用されるべき唯一の通信メカニズムであるがPropertyValueデータモデル、の方法でDataContextが 、コマンドの標準セット。

    WPFとSilverlightのアセンブリの両方を参照

    設計アセンブリは、Visual Studioまたはブレンドによってロードされる.NET / WPFアセンブリですが、それは通常、Silverlightのアセンブリを(それがデザイン時機能を提供する少なくともSilverlightコントロールのアセンブリ)を参照する必要があります。 これは設計アセンブリプロジェクトのための基準のあいまいさを作成することができます:それは時々、SilverlightのWPFとSystem.Windows.dllの両方PresentationFramework.dllでSystem.Windows.FrameworkElementを言う、WPFとSilverlightの両方に同じ完全修飾型名を参照する必要があります。 Visual Studioでの混乱を回避するには、使用することができますexternエイリアスを WPFとSilverlightの参照を区別する。

    例えば、でのSilverlight 3 ToolkitのControls.DataVisualization.Toolkit.Designプロジェクトのために下のスクリーンショットを参照してください2009年3月版リリース

    image

    • プロジェクト参照PresentationFrameworkとSystem.Windows名前の両方を、しかしSystem.Windows名前は、​​Silverlightのエイリアスの代わりに、デフォルトのグローバルエイリアスの下にあります。 。Silverlightのエイリアスの下System.Windows名前の参照は、以下のようにcsprojファイルに永続化されています。
        Include ="System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, processorArchitecture=MSIL" > < 参考 INCLUDE = "System.Windows名前、バージョン= 2.0.5.0、文化=中立的なPublicKeyToken = 7cec85d7bea7798e、processorArchitecture = MSIL">
         > False </ SpecificVersion > <SpecificVersion></ SpecificVersion>
         > ..\Binaries\System.Windows.dll </ HintPath > <HintPath> .. \バイナリ\ System.Windows.dll </ HintPath>
         > False </ Private > < プライベート ></ プライベート >
         > Silverlight </ Aliases > < エイリアス >シルバー</ エイリアス >
       > </ 参照 > 

    • ソースコードでは、我々は追加
        のexternエイリアスシルバー。
       SSW = Silverlightを使用して:: System.Windows名前。 

      SSWを経由して、リファレンスSilverlightのFrameworkElementの::のFrameworkElement。

    TextBoxEditor

    [|バー|バブル|コラム|ライン|パイ|エリア散布図]のオブジェクト型のTitleプロパティを表示および編集するためのControls.DataVisualization.Toolkit.Designプロジェクト内のインラインエディタのTextBoxEditorがあります以下に示すようにシリーズとグラフコントロールは、。

    TextBoxEditor

    右側の[プロパティ]ウィンドウの[タイトル]フィールドに入力テキストは、XAMLと真ん中にデザインビューに自動的に表示されます。

    TextBoxEditorの実装は、前に説明した手順に従った。

    TextBoxEditor.cs

    • TextBoxEditorはPropertyValueEditorのサブクラスです。 それが設定されInlineEditorTemplateをそのデフォルトコンストラクタで。 ここでは、構築する代わりにXAMLのコードを使用してDataTemplateを何らかの形で私は、XAMLを構築するために得ることができないので、XAMLのすべてが#とにかく、C言語で書き換えることができます。
    • それはChartMetadata.csでChart.Title(参照に関連付けられているSilverlightのツールキットの設計時の機能の実装 * Metadata.csファイルの詳細については、)

    TextBoxEditor.cs:

     / /(C)著作権Microsoft Corporationの。/ /このソースは、Microsoftパブリックライセンス(Ms-PL)の対象となります。/ /詳細については、http://go.microsoft.com/fwlink/?LinkID=131993を参照してください。/ /他のすべての権利  TextBoxEditor : PropertyValueEditor { /// <summary> /// Preserve the constructor prototype from PropertyValueEditor. /// </summary> /// <param name="inlineEditorTemplate">Inline editor template.</param> public TextBoxEditor(DataTemplate inlineEditorTemplate) : base (inlineEditorTemplate) { } /// <summary> /// Default constructor builds the default TextBox inline editor template. /// </summary> public TextBoxEditor() { FrameworkElementFactory textBox = new FrameworkElementFactory( typeof (TextBox)); Binding binding = new Binding(); binding.Path = new PropertyPath( "Value" ); binding.Mode = BindingMode.TwoWay; textBox.SetBinding(TextBox.TextProperty, binding); DataTemplate dt = new DataTemplate(); dt.VisualTree = textBox; InlineEditorTemplate = dt; } } } {/ / / <summary> / / /シンプルなテキストボックス(TextBox)コントロールのインラインエディタ/ / / </概要> 公共の部分クラス TextBoxEditor。PropertyValueEditor {/ / / <summary> / / / PropertyValueEditorからコンストラクタのプロトタイプを保持する/ / / </。 > / / / <param name="inlineEditorTemplate">インラインエディタのテンプレートの概要</ PARAM> 公共 TextBoxEditor(DataTemplateをinlineEditorTemplate): ベース (inlineEditorTemplate){} / / / <summary> / / /デフォルトのコンストラクタは、既定のテキストボックス(TextBox)コントロールのインラインを構築。エディタテンプレート/ / / </概要> 公共 TextBoxEditor(){FrameworkElementFactoryテキストボックス(TextBox)= 新しいFrameworkElementFactory(typeof演算 (テキストボックス(TextBox)));バインディングバインディング= 新しいBinding(); binding.Path = 新しい PropertyPathの( "値"); binding.Mode = BindingMode.TwoWay、(TextBox.TextProperty、結合)textBox.SetBinding、DataTemplateはdtが= 新しい DataTemplateを(); dt.VisualTree =テキストボックス(TextBox)。InlineEditorTemplate = DT;}}} 

    CultureInfoEditor

    同僚のRJは、 BlendでのCultureInfoの経験を編集するデフォルトでは無効なXAMLにつながるため、TimePicker.CultureプロパティのインラインエディタCultureInfoEditorを書きました。 スクリーンショットの下CultureInfoEditorは、すべてのCultureInfoを表示するには、コンボボックス(ComboBox)コントロールを使用して、右のXAMLを生成を示しています。

    CultureInfoEditor

    CultureInfoEditorはTextBoxEditorより複雑な例ですが、実際には基礎となるプロパティは、DataContextプロパティを経由してエディタに関連付けられている方法を示しています。

    CultureInfoEditor.cs:

     / /(C)著作権Microsoft Corporationの。/ /このソースは、Microsoftパブリックライセンス(Ms-PL)の対象となります。/ /詳細については、http://go.microsoft.com/fwlink/?LinkID=131993を参照してください。/ /他のすべての権利  CultureInfoEditor : PropertyValueEditor { /// <summary> /// The ComboBox being used to edit the value. /// </summary> private ComboBox _owner; /// <summary> /// Preserve the constructor prototype from PropertyValueEditor. /// </summary> /// <param name="inlineEditorTemplate">Inline editor template.</param> public CultureInfoEditor(DataTemplate inlineEditorTemplate) : base (inlineEditorTemplate) { } /// <summary> /// Default constructor builds a ComboBox inline editor template. /// </summary> public CultureInfoEditor() { // not using databinding here because Silverlight does not support // the WPF CultureConverter that is used by Blend. FrameworkElementFactory comboBox = new FrameworkElementFactory( typeof (ComboBox)); comboBox.AddHandler( ComboBox.LoadedEvent, new RoutedEventHandler( (sender, e) => { _owner = (ComboBox) sender; _owner.SelectionChanged += EditorSelectionChanged; INotifyPropertyChanged data = _owner.DataContext as INotifyPropertyChanged; if (data != null ) { data.PropertyChanged += DatacontextPropertyChanged; } _owner.DataContextChanged += CultureDatacontextChanged; })); comboBox.SetValue(ComboBox.IsEditableProperty, false ); comboBox.SetValue(ComboBox.DisplayMemberPathProperty, "DisplayName" ); comboBox.SetValue(ComboBox.ItemsSourceProperty, CultureInfo.GetCultures(CultureTypes.SpecificCultures)); DataTemplate dt = new DataTemplate(); dt.VisualTree = comboBox; InlineEditorTemplate = dt; } /// <summary> /// Handles the SelectionChanged event of the owner control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> /// instance containing the event data.</param> private void EditorSelectionChanged( object sender, SelectionChangedEventArgs e) { // serialize with name. object DataContext = _owner.DataContext; DataContext .GetType() .GetProperty( "Value" , BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) .SetValue(DataContext, ((CultureInfo)_owner.SelectedItem).Name, new object [] { }); } /// <summary> /// Handles the PropertyChanged event of the context object. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param> private void DatacontextPropertyChanged( object sender, PropertyChangedEventArgs e) { // deserialize from name. if (e.PropertyName == "Value" ) { object value = sender .GetType() .GetProperty( "Value" , BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty) .GetValue(sender, new object [] { }); if ( value != null ) { if ( value is string ) { CultureInfo setCulture = new CultureInfo( value .ToString()); _owner.SelectedItem = setCulture; } } } } /// <summary> /// Called when the context is changed. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param> private void CultureDatacontextChanged( object sender, DependencyPropertyChangedEventArgs e) { INotifyPropertyChanged old = e.OldValue as INotifyPropertyChanged; if (old != null ) { old.PropertyChanged -= DatacontextPropertyChanged; } INotifyPropertyChanged newDataContext = e.NewValue as INotifyPropertyChanged; if (newDataContext != null ) { newDataContext.PropertyChanged += DatacontextPropertyChanged; } } } } {/ / CultureInfoの/ <summary> / / /編集/ / / </概要> / / / <remarks>は、現在、XAMLからエディタへのバインドはサポートされていません</備考> パブリッククラス CultureInfoEditor:PropertyValueEditor {/ / /の値を編集するために使用されている<summary> / / /コンボボックス(ComboBox)/ / / </概要> プライベートコンボボックス(ComboBox)コントロールの_owner; / / / <summary> / / / PropertyValueEditorからコンストラクタのプロトタイプを保持する/ / / </概要> / / / <param name="inlineEditorTemplate">インラインエディタのテンプレート</ PARAM> 公共 CultureInfoEditor(DataTemplateをinlineEditorTemplate): ベース (inlineEditorTemplate){} / / / <summary> / / /デフォルトのコンストラクタは、ComboBoxのインラインエディタのテンプレートを作成します。 / / / </概要> 公共 CultureInfoEditor(){ シルバーサポートしていないため、/ /ここでデータバインディングを使用していない/ /ブレンドで使用されているWPFのCultureConverter FrameworkElementFactory comboBoxの= 新しいFrameworkElementFactory(typeof演算 (コンボボックス(ComboBox))); comboBox.AddHandler( ComboBox.LoadedEvent、 新しい RoutedEventHandler((送信者は、e)=> {_owner =(ComboBoxコントロール)送信。_owner.SelectionChanged + = EditorSelectionChanged。でINotifyPropertyChanged などでINotifyPropertyChangedデータ= _owner.DataContext。!data.PropertyChanged 場合 (データ= NULL){+ = DatacontextPropertyChanged;} _owner.DataContextChanged + = CultureDatacontextChanged;})); comboBox.SetValue(ComboBox.IsEditableProperty、FALSE); comboBox.SetValue(ComboBox.DisplayMemberPathProperty "DisplayNameは"); comboBox.SetValue(ComboBox.ItemsSourceProperty、CultureInfo.GetCultures (CultureTypes.SpecificCultures)); DataTemplateをDT = 新しい DataTemplateを(); dt.VisualTree = comboBoxの。InlineEditorTemplate = DT;} / / / <summary> / / /所有者のコントロールのSelectionChangedイベントを処理します/ / / </概要> / / / <param name="sender">イベントのソース。</ PARAM> / / / <param name="e"> <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> / / /インスタンスのイベントデータを含む</ PARAM> ます。private void EditorSelectionChanged( オブジェクト送信者、SelectionChangedEventArgs e){/ /何名でシリアライズ オブジェクトのDataContext = _owner.DataContext;。DataContextのGetTypeを()のGetProperty( "値"は、BindingFlags。公共| BindingFlags.Instance | BindingFlags.GetProperty)SetValueメソッド(DataContextは、((カルチャ)_owner.SelectedItem)名前は、 新しいオブジェクト [] {});} / / / <summary> / / /のPropertyChangedイベントを処理します/ / / <param name="sender">イベントのソースコンテキストオブジェクトを指定します。/ / / </概要> ... </ PARAM> / / / <param name="e"> <CREF = "システムを参照してください。 ComponentModel.PropertyChangedEventArgs "/イベントデータを含む>インスタンス。</ PARAM> ます。private void DatacontextPropertyChanged( オブジェクト送信者、PropertyChangedEventArgsのe){/ /名前から逆シリアル化ますif(e.PropertyName =="値"){ オブジェクト値 =送信。 。GetTypeを()のGetProperty( "値"、のBindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty)GetValueメソッド(送信者、 新しいオブジェクト [] {}); 場合 = nullを !){{( 値は文字列です )の場合 CultureInfoのsetCulture = 新しいCultureInfo(値のtoString()); _owner.SelectedItem = setCulture;}}}} / / / <summary> / / /というコンテキストが変更された/ / / </概要> / / / <パラメータ名= "送信者">送信</ PARAM> / / / <param name="e">イベントデータを含む<see cref="System.Windows.DependencyPropertyChangedEventArgs"/>インスタンスを作成します。</ PARAM> プライベート INotifyPropertyChangedを古い= e.OldValueでINotifyPropertyChanged など {( オブジェクト送信者、DependencyPropertyChangedEventArgs e)のCultureDatacontextChanged ボイド ; 場合 (古い= NULL!){old.PropertyChanged - = DatacontextPropertyChanged;}でINotifyPropertyChanged newDataContext = e.NewValueでINotifyPropertyChanged など、IF(newDataContext = NULL ){newDataContext.PropertyChanged + = DatacontextPropertyChanged;}}}} 

    ExpandableObjectConverter

    冒頭で述べたように、カスタムプロパティ値エディタのほかに、時にはあなたは良い編集の経験とXAMLのシリアル化を提供するために適切な型コンバータを使用することができます。 一例はColumnSeries.DependentRangeAxisです:それはIRangeAxis型である、ブレンドは、それを編集する方法を知りませんので、[プロパティ]パネルで読み取り専用としてDependentRangeAxisを示しています。 関連付けることで、 ExpandableObjectConverterを ColumnSeries.DependentRangeAxisへ:

      b.AddCustomAttributes(
         Extensions.GetMemberName <ColumnSeries>(X => x.DependentRangeAxis)
         (ExpandableObjectConverter))); 新しい TypeConverterAttributeを(typeof演算 (ExpandableObjectConverter)));
     b.AddCustomAttributes(
         Extensions.GetMemberName <ColumnSeries>(X => x.IndependentAxis)
         (ExpandableObjectConverter))); 新しい TypeConverterAttributeを(typeof演算 (ExpandableObjectConverter))); 

    ブレンドはプロパティパネルで、このプロパティの横にある[新規作成]ボタンが表示されます。クリックすると、プロパティの型IRangeAxisで濾過し[オブジェクトの選択]ダイアログがポップアップ表示されます:

    ExpandableObjectConverter

    結論

    Blendとシルバー一緒に、設計者が直接、実際のコントロールに対して素晴らしいUIを作成することができますので、コントロールの開発者は、全体的な制御の設計と実装の一環として、デザイナーの経験を取ることが非常に重要です。 素敵な編集UIを提供し、正しいXAMLを生成するカスタムプロパティエディタを持つことは、デザイナーの経験の重要な部分です。 うまくいけば、この記事では、カスタムプロパティエディタの作成方法を理解するのに役立ちます。 ありがとう!