WPF保留Tab控件状态

我已经阅读了post@ 如何阻止Wpf Tabcontrol在Tab更改时卸载Visual Tree ,但我无法让它工作,我一定错过了什么。 请帮忙。 谢谢

我正在使用来自示例项目的类TabControlEx @ http://www.pluralsight-training.net/community/blogs/eburke/archive/2009/04/30/keeping-the-wpf-tab-control-from-destroying-its -children.aspx

                Datasource for the maintab is Tabs.TabItems public ObservableCollection TabItems { get { return _items; } } 

每个TabItem都是用

    

我一直使用该链接中的代码而没有任何问题,虽然我注意到自从我第一次获得代码以来网站已经发生了变化。 您可能想要检查我拥有的内容与网站内容之间的任何代码差异。

这是我们在更改网站之前获得的代码:

 // Extended TabControl which saves the displayed item so you don't get the performance hit of // unloading and reloading the VisualTree when switching tabs // Obtained from http://www.pluralsight-training.net/community/blogs/eburke/archive/2009/04/30/keeping-the-wpf-tab-control-from-destroying-its-children.aspx // and made a some modifications so it reuses a TabItem's ContentPresenter when doing drag/drop operations [TemplatePart(Name = "PART_ItemsHolder", Type = typeof(Panel))] public class TabControlEx : System.Windows.Controls.TabControl { // Holds all items, but only marks the current tab's item as visible private Panel _itemsHolder = null; // Temporaily holds deleted item in case this was a drag/drop operation private object _deletedObject = null; public TabControlEx() : base() { // this is necessary so that we get the initial databound selected item this.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged; } ///  /// if containers are done, generate the selected item ///  ///  ///  void ItemContainerGenerator_StatusChanged(object sender, EventArgs e) { if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) { this.ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged; UpdateSelectedItem(); } } ///  /// get the ItemsHolder and generate any children ///  public override void OnApplyTemplate() { base.OnApplyTemplate(); _itemsHolder = GetTemplateChild("PART_ItemsHolder") as Panel; UpdateSelectedItem(); } ///  /// when the items change we remove any generated panel children and add any new ones as necessary ///  ///  protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) { base.OnItemsChanged(e); if (_itemsHolder == null) { return; } switch (e.Action) { case NotifyCollectionChangedAction.Reset: _itemsHolder.Children.Clear(); if (base.Items.Count > 0) { base.SelectedItem = base.Items[0]; UpdateSelectedItem(); } break; case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Remove: // Search for recently deleted items caused by a Drag/Drop operation if (e.NewItems != null && _deletedObject != null) { foreach (var item in e.NewItems) { if (_deletedObject == item) { // If the new item is the same as the recently deleted one (ie a drag/drop event) // then cancel the deletion and reuse the ContentPresenter so it doesn't have to be // redrawn. We do need to link the presenter to the new item though (using the Tag) ContentPresenter cp = FindChildContentPresenter(_deletedObject); if (cp != null) { int index = _itemsHolder.Children.IndexOf(cp); (_itemsHolder.Children[index] as ContentPresenter).Tag = (item is TabItem) ? item : (this.ItemContainerGenerator.ContainerFromItem(item)); } _deletedObject = null; } } } if (e.OldItems != null) { foreach (var item in e.OldItems) { _deletedObject = item; // We want to run this at a slightly later priority in case this // is a drag/drop operation so that we can reuse the template this.Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new Action(delegate() { if (_deletedObject != null) { ContentPresenter cp = FindChildContentPresenter(_deletedObject); if (cp != null) { this._itemsHolder.Children.Remove(cp); } } } )); } } UpdateSelectedItem(); break; case NotifyCollectionChangedAction.Replace: throw new NotImplementedException("Replace not implemented yet"); } } ///  /// update the visible child in the ItemsHolder ///  ///  protected override void OnSelectionChanged(SelectionChangedEventArgs e) { base.OnSelectionChanged(e); UpdateSelectedItem(); } ///  /// generate a ContentPresenter for the selected item ///  void UpdateSelectedItem() { if (_itemsHolder == null) { return; } // generate a ContentPresenter if necessary TabItem item = GetSelectedTabItem(); if (item != null) { CreateChildContentPresenter(item); } // show the right child foreach (ContentPresenter child in _itemsHolder.Children) { child.Visibility = ((child.Tag as TabItem).IsSelected) ? Visibility.Visible : Visibility.Collapsed; } } ///  /// create the child ContentPresenter for the given item (could be data or a TabItem) ///  ///  ///  ContentPresenter CreateChildContentPresenter(object item) { if (item == null) { return null; } ContentPresenter cp = FindChildContentPresenter(item); if (cp != null) { return cp; } // the actual child to be added. cp.Tag is a reference to the TabItem cp = new ContentPresenter(); cp.Content = (item is TabItem) ? (item as TabItem).Content : item; cp.ContentTemplate = this.SelectedContentTemplate; cp.ContentTemplateSelector = this.SelectedContentTemplateSelector; cp.ContentStringFormat = this.SelectedContentStringFormat; cp.Visibility = Visibility.Collapsed; cp.Tag = (item is TabItem) ? item : (this.ItemContainerGenerator.ContainerFromItem(item)); _itemsHolder.Children.Add(cp); return cp; } ///  /// Find the CP for the given object. data could be a TabItem or a piece of data ///  ///  ///  ContentPresenter FindChildContentPresenter(object data) { if (data is TabItem) { data = (data as TabItem).Content; } if (data == null) { return null; } if (_itemsHolder == null) { return null; } foreach (ContentPresenter cp in _itemsHolder.Children) { if (cp.Content == data) { return cp; } } return null; } ///  /// copied from TabControl; wish it were protected in that class instead of private ///  ///  protected TabItem GetSelectedTabItem() { object selectedItem = base.SelectedItem; if (selectedItem == null) { return null; } if (_deletedObject == selectedItem) { } TabItem item = selectedItem as TabItem; if (item == null) { item = base.ItemContainerGenerator.ContainerFromIndex(base.SelectedIndex) as TabItem; } return item; } } 

我确实对原始代码进行了一些更改,因为我拖放了标签,并且在删除项目并重新添加标签时不想重新创建标签,但老实说,我已经忘了这么长时间以至于忘记了我的什么不是。

我做了一个快速测试来仔细检查,是的,它确实保留了您的非约束值,例如选定值或扩展值。

编辑

为了回应您的评论,请将DataTemplates放在您的Resources ,定义哪个UserControl用于每个Tab。 当TabControl尝试绘制每个Tab的内容时,它将使用您为该数据类型定义的任何DataTemplate

              

视图模型…

 public MyViewModelConstructor() { TabItems.Add(New TabAViewModel { Header = "Tab A" }); TabItems.Add(New TabBViewModel { Header = "Tab B" }); } 

编辑#2

根据您的要求,文本XAML

                 

我放弃了解决方法,它只是在我的情况下不起作用。 我购买了第三方WPF库(DevExpress WPF)来解决这个问题。 谢谢