@ -10,6 +10,7 @@ using Avalonia.LogicalTree;
using Avalonia.VisualTree ;
using Avalonia.Automation ;
using Avalonia.Controls.Metadata ;
using Avalonia.Reactive ;
namespace Avalonia.Controls
{
@ -19,6 +20,10 @@ namespace Avalonia.Controls
[TemplatePart("PART_ItemsPresenter", typeof(ItemsPresenter))]
public class TabControl : SelectingItemsControl , IContentPresenterHost
{
private object? _ selectedContent ;
private IDataTemplate ? _ selectedContentTemplate ;
private CompositeDisposable ? _ selectedItemSubscriptions ;
/// <summary>
/// Defines the <see cref="TabStripPlacement"/> property.
/// </summary>
@ -46,14 +51,14 @@ namespace Avalonia.Controls
/// <summary>
/// The selected content property
/// </summary>
public static readonly StyledProperty < object? > SelectedContentProperty =
AvaloniaProperty . Register < TabControl , object? > ( nameof ( SelectedContent ) ) ;
public static readonly DirectProperty < TabControl , object? > SelectedContentProperty =
AvaloniaProperty . RegisterDirect < TabControl , object? > ( nameof ( SelectedContent ) , o = > o . SelectedContent ) ;
/// <summary>
/// The selected content template property
/// </summary>
public static readonly StyledProperty < IDataTemplate ? > SelectedContentTemplateProperty =
AvaloniaProperty . Register < TabControl , IDataTemplate ? > ( nameof ( SelectedContentTemplate ) ) ;
public static readonly DirectProperty < TabControl , IDataTemplate ? > SelectedContentTemplateProperty =
AvaloniaProperty . RegisterDirect < TabControl , IDataTemplate ? > ( nameof ( SelectedContentTemplate ) , o = > o . SelectedContentTemplate ) ;
/// <summary>
/// The default value for the <see cref="ItemsControl.ItemsPanel"/> property.
@ -115,11 +120,10 @@ namespace Avalonia.Controls
/// <value>
/// The content of the selected tab.
/// </value>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1032", Justification = "This property is supposed to be a styled readonly property.")]
public object? SelectedContent
{
get { return GetValue ( SelectedContentProperty ) ; }
internal set { SetValu e( SelectedContentProperty , value ) ; }
get = > _ selectedContent ;
internal set = > SetAndRais e( SelectedContentProperty , ref _ selectedContent , value ) ;
}
/// <summary>
@ -128,11 +132,10 @@ namespace Avalonia.Controls
/// <value>
/// The content template of the selected tab.
/// </value>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1032", Justification = "This property is supposed to be a styled readonly property.")]
public IDataTemplate ? SelectedContentTemplate
{
get { return GetValue ( SelectedContentTemplateProperty ) ; }
internal set { SetValu e( SelectedContentTemplateProperty , value ) ; }
get = > _ selectedContentTemplate ;
internal set = > SetAndRais e( SelectedContentTemplateProperty , ref _ selectedContentTemplate , value ) ;
}
internal ItemsPresenter ? ItemsPresenterPart { get ; private set ; }
@ -161,18 +164,10 @@ namespace Avalonia.Controls
protected internal override void PrepareContainerForItemOverride ( Control element , object? item , int index )
{
base . PrepareContainerForItemOverride ( element , item , index ) ;
if ( element is TabItem tabItem )
{
if ( ContentTemplate is { } ct )
tabItem . ContentTemplate = ct ;
tabItem . SetValue ( TabStripPlacementProperty , TabStripPlacement ) ;
}
if ( index = = SelectedIndex & & element is ContentControl container )
if ( index = = SelectedIndex )
{
SelectedContentTemplate = container . ContentTemplate ;
SelectedContent = container . Content ;
UpdateSelectedContent ( element ) ;
}
}
@ -192,18 +187,25 @@ namespace Avalonia.Controls
UpdateSelectedContent ( ) ;
}
private void UpdateSelectedContent ( )
private void UpdateSelectedContent ( Control ? container = null )
{
_ selectedItemSubscriptions ? . Dispose ( ) ;
_ selectedItemSubscriptions = null ;
if ( SelectedIndex = = - 1 )
{
SelectedContent = SelectedContentTemplate = null ;
}
else
{
var container = SelectedItem as IContentControl ? ?
ContainerFromIndex ( SelectedIndex ) as IContentControl ;
SelectedContentTemplate = container ? . ContentTemplate ;
SelectedContent = container ? . Content ;
container ? ? = ContainerFromIndex ( SelectedIndex ) ;
if ( container ! = null )
{
_ selectedItemSubscriptions = new CompositeDisposable (
container . GetObservable ( ContentControl . ContentProperty ) . Subscribe ( v = > SelectedContent = v ) ,
// Note how we fall back to our own ContentTemplate if the container doesn't specify one
container . GetObservable ( ContentControl . ContentTemplateProperty ) . Subscribe ( v = > SelectedContentTemplate = v ? ? ContentTemplate ) ) ;
}
}
}
@ -285,6 +287,16 @@ namespace Avalonia.Controls
{
RefreshContainers ( ) ;
}
else if ( change . Property = = ContentTemplateProperty )
{
var newTemplate = change . GetNewValue < IDataTemplate ? > ( ) ;
if ( SelectedContentTemplate ! = newTemplate & &
ContainerFromIndex ( SelectedIndex ) is { } container & &
container . GetValue ( ContentControl . ContentTemplateProperty ) = = null )
{
SelectedContentTemplate = newTemplate ; // See also UpdateSelectedContent
}
}
else if ( change . Property = = KeyboardNavigation . TabOnceActiveElementProperty & &
ItemsPresenterPart ? . Panel is { } panel )
{