阻止TabControl重新创建其子级

阻止TabControl重新创建其子级,第1张

阻止TabControl重新创建其子级

默认情况下,

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,



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5602289.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存