2017-04-11 29 views
2

的TabControl的的ItemsSource財產視圖模型綁定到集合只有一個視圖。 ContentTemplate is ListView - UserControl。所有選項卡只使用一個ListView控件(構造函數ListView僅被調用一次)。問題是所有選項卡都有一個共同的可視狀態 - 例如,如果更改一個選項卡中任何項目的大小,則此更改將顯示在所有選項卡上。如何創建爲每個標籤單獨的ListView,但在同一時間使用的ItemsSource財產?WPF TabControl的創建在所有選項卡

<TabControl Grid.Row="1" Grid.Column="2" TabStripPlacement="Bottom" >  

    <TabControl.ContentTemplate> 
     <DataTemplate DataType="viewModel:ListViewModel" > 
      <view:ListView /> 
     </DataTemplate> 
    </TabControl.ContentTemplate> 

    <TabControl.ItemsSource> 
     <Binding Path="Lists"/> 
    </TabControl.ItemsSource> 
</TabControl> 
+0

@ MM8我認爲這是一個不正確的重複鏈接。這個問題是關於顯示每個標籤的項目,而不是創建一個單一的項目,只是調換的DataContext他們身後的默認創建一個單獨的ContentTemplate。我認爲可能有一個模板屬性來執行此操作,但我不確定。就我個人而言,我會小心這樣的設計......即使它不可見,您也會創建/存儲控件的多個副本。如果大小很重要,你可以在你的DataContext上爲它創建一個屬性並綁定它,這樣它隨着每個製表符的變化而變化。 – Rachel

+0

我想的特性是'X:共享= 「假」'(例如[這裏](http://stackoverflow.com/a/3488396/302677))。但這並不是很理想,因爲每次選擇該選項卡時都會創建一個UserControl的新副本,因此不管大小更改如何都不會保留。如果您使用模板構建TabControl項目,我建議僅存儲/綁定您關心的所有屬性,以便在用戶切換選項卡時使用與其使用的模板相同的模板,但DataContext不同,因此所有綁定都會更新 – Rachel

+0

到一個自定義的TabControl DependencyProperty中,爲每個項目構建'.TabItems',而不是使用'ItemsSource'? – Rachel

回答

0

有沒有簡單的方法來做到這一點。

問題是你有一個WPF模板,這意思是一樣的,不管你把什麼數據背後的。因此,創建了該模板的一個副本,並且隨時WPF在您的UI樹中遇到ListViewModel時,它將使用該模板進行繪製。未綁定到DataContext的控件的屬性將保持其在更改DataSources之間的狀態。

你可以使用x:Shared="False"(例如here),但是這將創建模板隨時隨地的新副本WPF要求它,當你切換標籤頁,其中包括。

當[x:Shared時]設置爲false,修改的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沒有設置,所以你必須設置爲它綁定在TabControl.Resources
  • 的DependencyProperty目前執行的硬編碼用戶控件新的創造。可能需要做一些其他的方式,比如試圖用一個模板屬性或者一個不同的DP告訴它要創建的用戶控件
  • 可能會需要更多的測試...不知道是否有任何問題,由於改變處理器的內存泄漏等
相關問題