2017-01-06 4 views
1

コントロールテンプレート内でListViewを内部的に使用するカスタムコントロールを実装しました。このListViewには、FindPartsがアクセスできます。 ListViewsのViewプロパティを、カスタムコントロール内でプログラムでインスタンス化するインスタンスに設定する必要があります。カスタムコントロールのプロパティにバインドできるDataTemplateからこのインスタンスを作成できます。DataTemplateからインスタンスを作成する方法

問題は、DataTemplateからインスタンスを作成する方法がわかりません。

XAMLデザイナで問題が発生するため、GridViewを直接Viewプロパティ(DataTemplates x:Shared属性がfalseに設定されているResourceDictionaryなど)に直接バインドしたくないことに注意してください。複数のListViewで共有することができます)。

編集:私はgrek40を使って議論しましたが、DataTemplate内でGridViewを提供することは不可能であることが明らかになりました。したがって、解決策としてマークされた答えは、質問のタイトルによって暗示されるように、DataTemplateからインスタンスを作成する方法の問題を処理しません。

+0

私はあなたがある時点で少し外れていると感じます。 ['ListView.View'](https://msdn.microsoft.com/en-us/library/system.windows.controls.listview.view(v = vs.110).aspx)の型は' ViewBase'なので外部からこの部分をCustomControlに渡す場合は、この型のプロパティが必要です。たぶん、いくつかのサンプルコードは、この全部で 'DataTemplate'をどこにしたいのかを理解するのに役立ちます。 – grek40

+0

はい、そうです。現時点では、私はViewBase型のDependencyPropertyを持っています。 ResourceDictionaryには、そのプロパティのリソースとそのリソースを割り当てるセッターのスタイルがあります。上で述べたように、RunTimeでこれらのリソースを使用できるようにするには、x:Shared = falseを設定する必要がありましたが、設計時に問題が発生します。 GridViewの定義を含むDataTemplateを受け入れるようにコントロールを変更する必要があります。コントロールは、DataTemplateのインスタンスを作成する必要があります。私の質問は、DataTemplateからインスタンスを作成する方法です。 – E812

+0

リストビューのitemsourceとItemtemplateをバインドするだけの理由はありませんか? – MikeT

答えて

2

あなたは多くのコードを共有していなかったので、 。アイデア:MyCustomControlはアイテムをホストしており、そのためにListViewControlTemplateで使用されています。デフォルトGridViewControlTemplateに直接含まれているが、それはMyCustomControl.MyView

カスタムコントロールを経由して、それを変更することが可能です:

コントロールテンプレート
public class MyCustomControl : ItemsControl 
{ 
    static MyCustomControl() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl))); 
    } 


    public ViewBase MyView 
    { 
     get { return (ViewBase)GetValue(MyViewProperty); } 
     set { SetValue(MyViewProperty, value); } 
    } 

    public static readonly DependencyProperty MyViewProperty = 
     DependencyProperty.Register("MyView", typeof(ViewBase), typeof(MyCustomControl), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnMyViewChanged))); 

    private static void OnMyViewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     ((MyCustomControl)d).HasCustomView = e.NewValue != null; 
    } 



    // readonly property to support the Trigger in the ControlTemplate in order to exchange the ListView.View 
    public bool HasCustomView 
    { 
     get { return (bool)GetValue(HasCustomViewProperty); } 
     private set { SetValue(HasCustomViewPropertyKey, value); } 
    } 

    private static readonly DependencyPropertyKey HasCustomViewPropertyKey = 
     DependencyProperty.RegisterReadOnly("HasCustomView", typeof(bool), typeof(MyCustomControl), new PropertyMetadata(false)); 
    public static readonly DependencyProperty HasCustomViewProperty = HasCustomViewPropertyKey.DependencyProperty; 
} 

(デフォルトのGridViewコントロールおよび交換のためのトリガーを注意してください)

<Style TargetType="{x:Type local:MyCustomControl}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type local:MyCustomControl}"> 
       <Border Background="{TemplateBinding Background}" 
         BorderBrush="{TemplateBinding BorderBrush}" 
         BorderThickness="{TemplateBinding BorderThickness}"> 
        <ListView x:Name="PART_ListView" 
           ItemsSource="{Binding Items,RelativeSource={RelativeSource TemplatedParent}}"> 
         <ListView.View> 
          <GridView> 
           <GridView.Columns> 
            <GridViewColumn Header="DEF"/> 
           </GridView.Columns> 
          </GridView> 
         </ListView.View> 
        </ListView> 
       </Border> 
       <ControlTemplate.Triggers> 
        <Trigger Property="HasCustomView" Value="True"> 
         <Setter TargetName="PART_ListView" Property="View" Value="{Binding MyView,RelativeSource={RelativeSource TemplatedParent}}"/> 
        </Trigger> 
       </ControlTemplate.Triggers> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

使用法:

<local:MyCustomControl> 
    <!--uses default view--> 
    <TextBlock Text="Item 1"/> 
    <TextBlock Text="Item 2"/> 
</local:MyCustomControl> 

<local:MyCustomControl> 
    <!--uses custom view--> 
    <local:MyCustomControl.MyView> 
     <GridView> 
      <GridView.Columns> 
       <GridViewColumn Header="ABC"/> 
      </GridView.Columns> 
     </GridView> 
    </local:MyCustomControl.MyView> 
    <TextBlock Text="Item 1"/> 
    <TextBlock Text="Item 2"/> 
</local:MyCustomControl> 

不明な点が残っているかどうか自由にお尋ねください。コメントしたように、私はあなたのDataTemplateアイデアをこのすべてのものに適用する方法を知らない。

編集:

は、以下のいくつかのデータとDataTemplate Sならびにそれらの可能な使用法を定義するリソースセクションを有する例です。私はすでに私の最初の編集で説明したように、私はまさにこれを解決するだろう

:コメントMCVEをターゲット

<StackPanel> 
    <StackPanel.Resources> 
     <x:Array x:Key="Items1" Type="{x:Type sys:Int32}"> 
      <sys:Int32>1</sys:Int32> 
      <sys:Int32>2</sys:Int32> 
      <sys:Int32>3</sys:Int32> 
      <sys:Int32>4</sys:Int32> 
     </x:Array> 

     <x:Array x:Key="Items2" Type="{x:Type sys:Int32}"> 
      <sys:Int32>5</sys:Int32> 
      <sys:Int32>4</sys:Int32> 
      <sys:Int32>6</sys:Int32> 
      <sys:Int32>7</sys:Int32> 
     </x:Array> 

     <CollectionViewSource x:Key="ItemsSource1" Source="{StaticResource Items1}"/> 
     <CollectionViewSource x:Key="ItemsSource2" Source="{StaticResource Items2}"/> 

     <DataTemplate x:Key="IntegerListTemplate1"> 
      <local:MyCustomControl ItemsSource="{Binding}"> 
       <!--uses default view--> 
      </local:MyCustomControl> 
     </DataTemplate> 

     <DataTemplate x:Key="IntegerListTemplate2"> 
      <local:MyCustomControl ItemsSource="{Binding}"> 
       <!--uses custom view--> 
       <local:MyCustomControl.MyView> 
        <GridView> 
         <GridView.Columns> 
          <GridViewColumn Header="ABC"/> 
         </GridView.Columns> 
        </GridView> 
       </local:MyCustomControl.MyView> 
      </local:MyCustomControl> 
     </DataTemplate> 
    </StackPanel.Resources> 
    <!--the default view--> 
    <ContentControl ContentTemplate="{StaticResource IntegerListTemplate1}" Content="{Binding Source={StaticResource ItemsSource1}}"/> 
    <Separator Margin="3"/> 
    <!--same items other view--> 
    <ContentControl ContentTemplate="{StaticResource IntegerListTemplate2}" Content="{Binding Source={StaticResource ItemsSource1}}"/> 
    <Separator Margin="3"/> 
    <!--different items same view as second one, no complaints about reusing--> 
    <ContentControl ContentTemplate="{StaticResource IntegerListTemplate2}" Content="{Binding Source={StaticResource ItemsSource2}}"/> 
</StackPanel> 

編集2、。コントロールをスタイルに変換するのではなく、DataTemplateにします。

MainWindow.xamlに置き換えます。他の出現箇所と

<!-- old --> 
<myctrls:MyControl Grid.Row="0" Grid.Column="0" Style="{StaticResource AddressStyle}" ItemsSource="{Binding Addresses}"/> 
<!-- new --> 
<ContentControl Grid.Row="0" Grid.Column="0" ContentTemplate="{StaticResource AddressTemplate}" Content="{Binding Addresses}"/> 

同じ。

In MyControlStyles。xaml(またはDataTemplateの使用を示す名前の変更されたファイル)を使用して、GridViewリソースとStylemyctrls:MyControlにマージしてDataTemplateにします。

旧:

<GridView x:Key="AddressGridView" x:Shared="False"> 
    <GridViewColumn Header="City" Width="Auto" > 
     <GridViewColumn.CellTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding City}" HorizontalAlignment="Left"/> 
      </DataTemplate> 
     </GridViewColumn.CellTemplate> 
    </GridViewColumn> 
    <GridViewColumn Header="Country" Width="Auto" > 
     <GridViewColumn.CellTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding Country}" HorizontalAlignment="Left"/> 
      </DataTemplate> 
     </GridViewColumn.CellTemplate> 
    </GridViewColumn> 
</GridView> 

<Style x:Key="AddressStyle" TargetType="{x:Type myctrls:MyControl}"> 
    <Setter Property="SuggestionsView" Value="{DynamicResource AddressGridView}"/> 
</Style> 

新:ProductsStyleため

<DataTemplate x:Key="AddressTemplate"> 
    <!-- the base control --> 
    <myctrls:MyControl ItemsSource="{Binding}"> 
     <!-- this was previously assigned by AddressStyle --> 
     <myctrls:MyControl.SuggestionsView> 
      <!-- this was previously the AddressGridView --> 
      <!-- Same as before, only removed the x:Key and x:Shared --> 
      <GridView> 
       <GridViewColumn Header="City" Width="Auto" > 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock Text="{Binding City}" HorizontalAlignment="Left"/> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
       <GridViewColumn Header="Country" Width="Auto" > 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock Text="{Binding Country}" HorizontalAlignment="Left"/> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
      </GridView> 
     </myctrls:MyControl.SuggestionsView> 
    </myctrls:MyControl> 
</DataTemplate> 

同じ手順。

ContentControlワイヤアップアプローチが嫌いなら、AddressListViewModelのようなコレクションをホストする追加のビューモデルを作成することを検討してください。これにより、リソースキーではなくDataTypeDataTemplateを処理し、明示的に使用する場合はContentControlになります。

+0

あなたのコードは私の問題にかなり近いです。私は似たようなものを思いついたわけではありません。さまざまな種類の項目にコントロールが使用されたので、私はResourceDictionaryでいくつかのスタイルを定義しました: ' ' – E812

+0

と ' ' – E812

+0

これは実行時に動作しますが、設計時に特定の条件下でXAMLデザイナに「複数のListViewでビューを共有できません」というエラーが表示されます'問題を取り除くために、私はDataTemplate型の依存関係プロパティを導入したいと思います。 GridViewリソースをDataTemplatesにラップし、GridViewインスタンスをMyViewプロパティに割り当てる代わりに、それらのDataTemplatesを新しいプロパティに割り当てます。私のユーザーコントロールのOnApplyTemplateメソッド内で、データテンプレートと一致するインスタンスを作成し、それをMyViewプロパティに割り当てる必要があります。 – E812

0

その後、動的におおよそそのように、あなたの1回使用するDataTemplateを作成し、独自のDataTemplateSelectorを、実現することができます。、私は薄い空気のうちに何かを作っ

public DataTemplate GenerateTemplate() { 
    var template = new DataTemplate(); 
    var p = new FrameworkElementFactory(typeof(Grid)); 
    p.SetValue(FrameworkElement.HorizontalAlignmentProperty, HorizontalAlignment.Left); 
    p.SetValue(FrameworkElement.VerticalAlignmentProperty, VerticalAlignment.Center); 
    ... 
    template.VisualTree = p; 
    return template; 
} 
+0

私はそれを逆にする必要があります。私はすでに私の税関コントロールのプロパティに割り当てられているDataTemplateからインスタンスを作成する必要があります。 – E812

関連する問題