2017-04-11 118 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告诉它要创建的用户控件
  • 可能会需要更多的测试...不知道是否有任何问题,由于改变处理器的内存泄漏等
相关问题