默认情况下,
TabControl共享面板以呈现其内容。若要做您想做的事情(以及许多其他WPF开发人员),您需要
TabControl像这样进行扩展:
TabControlEx.cs
[TemplatePart(Name = "PART_ItemsHolder", Type = typeof(Panel))]public class TabControlEx : TabControl{ private Panel ItemsHolderPanel = null; public TabControlEx() : base() { // This is necessary so that we get the initial databound selected item ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged; } /// <summary> /// If containers are done, generate the selected item /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e) { if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) { this.ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged; UpdateSelectedItem(); } } /// <summary> /// Get the ItemsHolder and generate any children /// </summary> public override void onApplyTemplate() { base.onApplyTemplate(); ItemsHolderPanel = GetTemplateChild("PART_ItemsHolder") as Panel; UpdateSelectedItem(); } /// <summary> /// When the items change we remove any generated panel children and add any new ones as necessary /// </summary> /// <param name="e"></param> protected override void onItemsChanged(NotifyCollectionChangedEventArgs e) { base.onItemsChanged(e); if (ItemsHolderPanel == null) return; switch (e.Action) { case NotifyCollectionChangedAction.Reset: ItemsHolderPanel.Children.Clear(); break; case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Remove: if (e.OldItems != null) { foreach (var item in e.OldItems) { ContentPresenter cp = FindChildContentPresenter(item); if (cp != null) ItemsHolderPanel.Children.Remove(cp); } } // Don't do anything with new items because we don't want to // create visuals that aren't being shown UpdateSelectedItem(); break; case NotifyCollectionChangedAction.Replace: throw new NotImplementedException("Replace not implemented yet"); } } protected override void onSelectionChanged(SelectionChangedEventArgs e) { base.onSelectionChanged(e); UpdateSelectedItem(); } private void UpdateSelectedItem() { if (ItemsHolderPanel == null) return; // Generate a ContentPresenter if necessary TabItem item = GetSelectedTabItem(); if (item != null) CreateChildContentPresenter(item); // show the right child foreach (ContentPresenter child in ItemsHolderPanel.Children) child.Visibility = ((child.Tag as TabItem).IsSelected) ? Visibility.Visible : Visibility.Collapsed; } private 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)); ItemsHolderPanel.Children.Add(cp); return cp; } private ContentPresenter FindChildContentPresenter(object data) { if (data is TabItem) data = (data as TabItem).Content; if (data == null) return null; if (ItemsHolderPanel == null) return null; foreach (ContentPresenter cp in ItemsHolderPanel.Children) { if (cp.Content == data) return cp; } return null; } protected TabItem GetSelectedTabItem() { object selectedItem = base.SelectedItem; if (selectedItem == null) return null; TabItem item = selectedItem as TabItem; if (item == null) item = base.ItemContainerGenerator.ContainerFromIndex(base.SelectedIndex) as TabItem; return item; }}
XAML
<Style TargetType="{x:Type controls:TabControlEx}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TabControl}"> <Grid Background="{TemplateBinding Background}" ClipToBounds="True" KeyboardNavigation.TabNavigation="Local" SnapsToDevicePixels="True"> <Grid.ColumnDefinitions> <ColumnDefinition x:Name="ColumnDefinition0" /> <ColumnDefinition x:Name="ColumnDefinition1" Width="0" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition x:Name="RowDefinition0" Height="Auto" /> <RowDefinition x:Name="RowDefinition1" Height="*" /> </Grid.RowDefinitions> <DockPanel Margin="2,2,0,0" LastChildFill="False"> <TabPanel x:Name="HeaderPanel" Margin="0,0,0,-1" VerticalAlignment="Bottom" Panel.ZIndex="1" DockPanel.Dock="Right" IsItemsHost="True" KeyboardNavigation.TabIndex="1" /> </DockPanel> <Border x:Name="ContentPanel" Grid.Row="1" Grid.Column="0" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local"> <Grid x:Name="PART_ItemsHolder" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter></Style>
注意: 我没有提出这个解决方案。它已在编程论坛中共享了几年,并且相信它现在已成为WPF食谱书之一。我认为最古老或原始的来源是PluralSight
.NET博客文章,以及StackOverflow上的答案。
HTH,
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)