2017-04-11 8 views
2

TabControlのItemsSourceプロパティがViewModelのコレクションにバインドされています。 コンテンツテンプレートです。ListView - UserControl。すべてのタブはListViewコントロールを1つだけ使用します(のコンストラクタListViewは1回だけ呼び出されます)。問題は、すべてのタブに共通の視覚的な状態があることです。たとえば、あるタブの項目のサイズを変更すると、この変更はすべてのタブに表示されます。どのように個別のリストビュー各タブを作成すると同時に、ItemsSourceプロパティを使用しますか?Wpf TabControlすべてのタブで1つのビューしか作成しない

+0

など、ハンドラを変更することにより、メモリリークに問題があるのか​​どうかわからない、私はそれが間違って重複したリンクであると思います。この質問は、単一のアイテムを作成し、それらの背後にあるDataContextを交換するデフォルトではなく、各タブアイテムを表示するための個別のContentTemplateを作成することです。私は、これを強制するためのテンプレートプロパティがあると思うが、わからない。個人的には、私はそのようなデザインに注意したいと思います...あなたが作成/コントロールの複数のコピーを格納するだろう、それが表示されていない場合でも。サイズがそれほど重要な場合は、DataContextにプロパティを作成してバインドして、各タブの変更ごとに変更することができます。 – Rachel

+0

私が考えていたプロパティは 'x:Shared =" False "'です(例[here](http://stackoverflow.com/a/3488396/302677))。これは本当に理想的ではありませんが、タブを選択するたびにUserControlの新しいコピーが作成されるので、サイズ変更のようなことは無関係に保たれません。テンプレートを使用してTabControlアイテムを作成する場合は、関心のあるすべてのプロパティを保存/バインドすることをお勧めします。ユーザーがタブを切り替えたときに使用したテンプレートと同じですが、DataContextが異なるため、すべてのバインディングが更新されます – Rachel

+0

'ItemsSource'を使うのではなく、各項目の' .TabItems'をビルドするカスタムTabControl DependencyPropertyに変換しますか? – Rachel

答えて

0

これを行う簡単な方法はありません。

問題はWPFテンプレートがあることです。これは、どのデータを後ろに置いても同じです。テンプレートの1つのコピーが作成され、UIツリー内でWPFがListViewModelに出会うたびに、そのテンプレートを使用して描画されます。 DataContextにバインドされていないコントロールのプロパティは、変化するデータソース間で状態を保持します。

x:Shared="False"(例:here)を使用できますが、タブを切り替えるとWPFが要求するたびにテンプレートの新しいコピーが作成されます。

falseに設定し、[x:Sharedがある]、リソースに対する要求ではなく、すべてのリクエストに対して同一のインスタンスを共有するよりも、リクエストごとに新しいインスタンスを作成することなどのWindows Presentation Foundationの(WPF)リソース検索の動作を変更します。各TabControl.Itemsは、各項目について、あなたのコントロールの新しいコピーを生成していますが、(これは仕様です)ItemsSourceプロパティを使用するときには発生しませんのためにあなたが本当に必要なもの

です。

あなたのアイテムのコレクションにバインドするカスタムDependencyPropertyを作成し、コレクション内の各アイテムに対してTabItemUserControlのオブジェクトを生成することもできます。このカスタムDPでは、コレクション変更イベントを処理して、TabItemがコレクションと同期していることを確認する必要があります。

ここで私は一緒に遊んでいました。 ObservableCollectionへのバインディングやアイテムの追加/削除などの単純なケースでは機能していました。このようなXAMLから使用

public class TabControlHelpers 
{ 
    // Custom DependencyProperty for a CachedItemsSource 
    public static readonly DependencyProperty CachedItemsSourceProperty = 
     DependencyProperty.RegisterAttached("CachedItemsSource", typeof(IList), typeof(TabControlHelpers), new PropertyMetadata(null, CachedItemsSource_Changed)); 

    // Get 
    public static IList GetCachedItemsSource(DependencyObject obj) 
    { 
     if (obj == null) 
      return null; 

     return obj.GetValue(CachedItemsSourceProperty) as IList; 
    } 

    // Set 
    public static void SetCachedItemsSource(DependencyObject obj, IEnumerable value) 
    { 
     if (obj != null) 
      obj.SetValue(CachedItemsSourceProperty, value); 
    } 

    // Change Event 
    public static void CachedItemsSource_Changed(
     DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     if (!(obj is TabControl)) 
      return; 

     var changeAction = new NotifyCollectionChangedEventHandler(
      (o, args) => 
      { 
       var tabControl = obj as TabControl; 

       if (tabControl != null) 
        UpdateTabItems(tabControl); 
      }); 


     // if the bound property is an ObservableCollection, attach change events 
     INotifyCollectionChanged newValue = e.NewValue as INotifyCollectionChanged; 
     INotifyCollectionChanged oldValue = e.OldValue as INotifyCollectionChanged; 

     if (oldValue != null) 
      newValue.CollectionChanged -= changeAction; 

     if (newValue != null) 
      newValue.CollectionChanged += changeAction; 

     UpdateTabItems(obj as TabControl); 
    } 

    static void UpdateTabItems(TabControl tc) 
    { 
     if (tc == null) 
      return; 

     IList itemsSource = GetCachedItemsSource(tc); 

     if (itemsSource == null || itemsSource.Count == null) 
     { 
      if (tc.Items.Count > 0) 
       tc.Items.Clear(); 

      return; 
     } 

     // loop through items source and make sure datacontext is correct for each one 
     for(int i = 0; i < itemsSource.Count; i++) 
     { 
      if (tc.Items.Count <= i) 
      { 
       TabItem t = new TabItem(); 
       t.DataContext = itemsSource[i]; 
       t.Content = new UserControl1(); // Should be Dynamic... 
       tc.Items.Add(t); 
       continue; 
      } 

      TabItem current = tc.Items[i] as TabItem; 
      if (current == null) 
       continue; 

      if (current.DataContext == itemsSource[i]) 
       continue; 

      current.DataContext = itemsSource[i]; 
     } 

     // loop backwards and cleanup extra tabs 
     for (int i = tc.Items.Count; i > itemsSource.Count; i--) 
     { 
      tc.Items.RemoveAt(i - 1); 
     } 
    } 
} 

その:

<TabControl local:TabControlHelpers.CachedItemsSource="{Binding Values}"> 
    <TabControl.Resources> 
     <Style TargetType="{x:Type TabItem}"> 
      <Setter Property="Header" Value="{Binding SomeString}" /> 
     </Style> 
    </TabControl.Resources> 
</TabControl> 

は、注意すべきいくつかのこと:

  • TabItem.Headerが設定されていないので、あなたはそれのためにバインディングをセットアップする必要がありますin TabControl.Resources
  • DependencyProperty実装は、現在、新しいUserControlの作成をハードコードしています。テンプレートプロパティやおそらく別のDPを使用してUserControlを作成するように指示するなど、他の方法でやりたいことがあります
  • もっとテストする必要があるでしょう...MM8 @
関連する問題