1

カスタム コントロールを作成していて、リスト ボックス項目用に部分的に指定されたテンプレートを作成しようとしています。テンプレートにはいくつかの事前定義された部分があり、コントロールを使用するときにテンプレート化できる別の部分があるはずです。

このために、次のように SuggestionItemTemplate という名前の依存関係プロパティを作成しました。

public static readonly DependencyProperty SuggestionItemTemplateProperty =
    DependencyProperty.Register("SuggestionItemTemplate", 
        typeof(DataTemplate), 
        typeof(AutoSuggestTextBox), 
        new PropertyMetadata(null));

私のカスタム コントロールの generic.xaml には、次のものがあります。

<Style TargetType="local:AutoSuggestTextBox">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:AutoSuggestTextBox">
                <Grid>
                    <ListBox x:Name="ItemsControl">
                        <ListBox.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel />
                            </ItemsPanelTemplate>
                        </ListBox.ItemsPanel>
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*" />
                                        <ColumnDefinition Width="Auto" />
                                    </Grid.ColumnDefinitions>
                                    <ContentPresenter Grid.Column="0" 
                                                      ContentTemplate="{TemplateBinding SuggestionItemTemplate}" 
                                                      Content="{Binding}" />
                                    <ToggleButton Grid.Column="1" 
                                                  x:Name="DetailsHover" 
                                                  ClickMode="Hover" 
                                                  Style="{StaticResource DetailsToggleButtonStyle}" />
                                </Grid>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

残念ながら、DataTemplate にネストされた ContentPresenter 内から TemplateBinding を使用できないため、これは機能しません。(メンバー「SuggestionItemTemplate」が認識されないか、アクセスできません。)

また、祖先バインディング (Silverlight 5 で利用可能) を次のように使用しようとしました。

<ContentPresenter Grid.Column="0" 
                  ContentTemplate="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=local:AutoSuggestTextBox}, Path=SuggestionItemTemplate}" 
                  Content="{Binding}" />

しかし、これはバインディングエラーになります:

Error: System.Exception: BindingExpression_CannotFindAncestor

これは、カスタム コントロールの ControlTemplate 内にいて、「local:AutoSuggestTextBox」がスタイルのどこにも定義されていないために発生すると思います。

私が試した 3 番目のオプションは、OnApplyTemplate オーバーライドで ContentTemplate を適用することでしたが、これも機能しません。

var cp = itemsControlElement.ItemTemplate.LoadContent() as ContentPresenter;
cp.ContentTemplate = SuggestionItemTemplate;

すべての場合で、2 つの列を持つグリッドを取得します。トグル ボタンは表示されますが、コンテンツ プレゼンターは単純にビュー モデルの型名を出力します。(ContentTemplate が null の場合、これがデフォルトの動作だと思います)。

これは可能ですか?部分的なテンプレートを指定し、必要に応じてカスタマイズされたテンプレート パーツのみを追加する他の方法はありますか?

今のところ回避策として、指定できます

ItemTemplate="{TemplateBinding SuggestionItemTemplate}"

リスト ボックスの場合は、このコントロールを使用するすべての場所に汎用テンプレートをコピーして貼り付けます。しかし、これは私が最初に避けたいと思っている行動です。

ありがとう!

編集:コードのすべてのブロックにコードタグを使用しましたが、何らかの理由で強調表示されていません。:/

4

2 に答える 2

0

OnApplyTemplate メソッドで Visual Ancestors をウォークスルーし、ContentPresenter(s) を見つけて、それに ItemTemplate を設定することができます。私の考えでは、これは単一のアイテムには問題ありませんが、ItemsControl シナリオではそれほどではありません。

独自のカスタム コントロールを使用した後、現在の状態を達成できます。Object 型の Content 依存関係プロパティと、DataTemplate 型の Template DP (必要に応じて 2 つの倍数) を指定するだけで、コントロールの既定のスタイルでルート ビジュアル スタイルとテンプレートを設定できます。

この特定のケースでは、ListBox.ItemContainerStyle をカスタマイズして、ToggleButton を ListBoxItem テンプレートに配置することをお勧めします。Expression Blend を使用して既定のコントロール テンプレートを変更するのは簡単で、ToggleButton の DataContext は変更されないため、独自のロジックへの変更は最小限に抑える必要があります。

編集:多数の異なるデータ テンプレートを使用する場合は、おそらくImplicit Data Templatesの方が適しています。

于 2013-02-11T19:05:14.833 に答える
0

私は別のアプローチを使用してこれを解決することができました。AutoSuggestTextBox祖先バインディングを使用しましたが、からルート コントロール ( my )に到達しようとする代わりに、 my (ここでは という名前)DataTemplateへの参照を要求します。ListBoxItemsControl

ただし、 にはプロパティListBoxがないため、そのプロパティを実装したSuggestionItemTemplate独自のクラスにサブクラス化しました。CustomListBoxそれはすべて、次のコード スニペットに帰着します。

<Style TargetType="local:AutoSuggestTextBox">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="local:AutoSuggestTextBox">
        <Grid>
          <local:CustomizableListBox x:Name="ItemsControl"
                                     SuggestionItemTemplate="{TemplateBinding SuggestionItemTemplate}">
            <local:CustomizableListBox.ItemTemplate>
              <DataTemplate>
                <Grid>
                  <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                  </Grid.ColumnDefinitions>
                  <ContentPresenter Grid.Column="0" 
                                    ContentTemplate="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=local:CustomizableListBox}, Path=SuggestionItemTemplate}"
                                    Content="{Binding}" />
                  <ToggleButton Grid.Column="1" 
                                x:Name="DetailsHover" 
                                ClickMode="Hover" 
                                Style="{StaticResource DetailsToggleButtonStyle}" />
                 </Grid>
              </DataTemplate>
            </local:CustomizableListBox.ItemTemplate>
          </local:CustomizableListBox>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>
于 2013-02-14T14:47:50.980 に答える