feat: add VariablesDemo.

This commit is contained in:
Zhang Dian
2025-01-21 18:51:45 +08:00
parent bb928fb239
commit a99db733ed
9 changed files with 392 additions and 140 deletions

View File

@@ -0,0 +1,223 @@
using System;
using System.Collections.Generic;
namespace Semi.Avalonia.Demo.Constant;
public static class ColorTokens
{
public static IReadOnlyList<Tuple<string, string>> PrimaryTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorPrimary", "Primary"),
new("SemiColorPrimaryPointerover", "Primary Pointerover"),
new("SemiColorPrimaryActive", "Primary Active"),
new("SemiColorPrimaryDisabled", "Primary Disabled"),
new("SemiColorPrimaryLight", "Primary Light"),
new("SemiColorPrimaryLightPointerover", "Primary Light Pointerover"),
new("SemiColorPrimaryLightActive", "Primary Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> SecondaryTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorSecondary", "Secondary"),
new("SemiColorSecondaryPointerover", "Secondary Pointerover"),
new("SemiColorSecondaryActive", "Secondary Active"),
new("SemiColorSecondaryDisabled", "Secondary Disabled"),
new("SemiColorSecondaryLight", "Secondary Light"),
new("SemiColorSecondaryLightPointerover", "Secondary Light Pointerover"),
new("SemiColorSecondaryLightActive", "Secondary Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> TertiaryTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorTertiary", "Tertiary"),
new("SemiColorTertiaryPointerover", "Tertiary Pointerover"),
new("SemiColorTertiaryActive", "Tertiary Active"),
new("SemiColorTertiaryLight", "Tertiary Light"),
new("SemiColorTertiaryLightPointerover", "Tertiary Light Pointerover"),
new("SemiColorTertiaryLightActive", "Tertiary Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> InformationTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorInformation", "Information"),
new("SemiColorInformationPointerover", "Information Pointerover"),
new("SemiColorInformationActive", "Information Active"),
new("SemiColorInformationDisabled", "Information Disabled"),
new("SemiColorInformationLight", "Information Light"),
new("SemiColorInformationLightPointerover", "Information Light Pointerover"),
new("SemiColorInformationLightActive", "Information Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> SuccessTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorSuccess", "Success"),
new("SemiColorSuccessPointerover", "Success Pointerover"),
new("SemiColorSuccessActive", "Success Active"),
new("SemiColorSuccessDisabled", "Success Disabled"),
new("SemiColorSuccessLight", "Success Light"),
new("SemiColorSuccessLightPointerover", "Success Light Pointerover"),
new("SemiColorSuccessLightActive", "Success Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> WarningTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorWarning", "Warning"),
new("SemiColorWarningPointerover", "Warning Pointerover"),
new("SemiColorWarningActive", "Warning Active"),
new("SemiColorWarningLight", "Warning Light"),
new("SemiColorWarningLightPointerover", "Warning Light Pointerover"),
new("SemiColorWarningLightActive", "Warning Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> DangerTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorDanger", "Danger"),
new("SemiColorDangerPointerover", "Danger Pointerover"),
new("SemiColorDangerActive", "Danger Active"),
new("SemiColorDangerLight", "Danger Light"),
new("SemiColorDangerLightPointerover", "Danger Light Pointerover"),
new("SemiColorDangerLightActive", "Danger Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> TextTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorText0", "Text 0"),
new("SemiColorText1", "Text 1"),
new("SemiColorText2", "Text 2"),
new("SemiColorText3", "Text 3"),
};
public static IReadOnlyList<Tuple<string, string>> LinkTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorLink", "Link"),
new("SemiColorLinkPointerover", "Link Pointerover"),
new("SemiColorLinkActive", "Link Active"),
new("SemiColorLinkVisited", "Link Visited"),
};
public static IReadOnlyList<Tuple<string, string>> BackgroundTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorBackground0", "Background 0"),
new("SemiColorBackground1", "Background 1"),
new("SemiColorBackground2", "Background 2"),
new("SemiColorBackground3", "Background 3"),
new("SemiColorBackground4", "Background 4"),
};
public static IReadOnlyList<Tuple<string, string>> FillTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorFill0", "Fill 0"),
new("SemiColorFill1", "Fill 1"),
new("SemiColorFill2", "Fill 2"),
};
public static IReadOnlyList<Tuple<string, string>> BorderTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorBorder", "Border"),
};
public static IReadOnlyList<Tuple<string, string>> DisabledTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorDisabledText", "Disabled Text"),
new("SemiColorDisabledBorder", "Disabled Border"),
new("SemiColorDisabledBackground", "Disabled Background"),
new("SemiColorDisabledFill", "Disabled Fill"),
};
public static IReadOnlyList<Tuple<string, string>> ShadowTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorShadow", "Shadow"),
new("SemiShadowElevated", "Shadow Elevated"),
};
public static IReadOnlyList<Tuple<string, string>> HeightTokens { get; } = new List<Tuple<string, string>>
{
new("SemiHeightControlSmall", ""),
new("SemiHeightControlDefault", ""),
new("SemiHeightControlLarge", ""),
};
public static IReadOnlyList<Tuple<string, string>> IconSizeTokens { get; } = new List<Tuple<string, string>>
{
new("SemiWidthIconExtraSmall", ""),
new("SemiWidthIconSmall", ""),
new("SemiWidthIconMedium", ""),
new("SemiWidthIconLarge", ""),
new("SemiWidthIconExtraLarge", ""),
};
public static IReadOnlyList<Tuple<string, string>> CornerRadiusTokens { get; } = new List<Tuple<string, string>>
{
new("SemiBorderRadiusExtraSmall", ""),
new("SemiBorderRadiusSmall", ""),
new("SemiBorderRadiusMedium", ""),
new("SemiBorderRadiusLarge", ""),
new("SemiBorderRadiusFull", ""),
};
public static IReadOnlyList<Tuple<string, string>> BorderSpacingTokens { get; } = new List<Tuple<string, string>>
{
new("SemiBorderSpacing", ""),
new("SemiBorderSpacingControl", ""),
new("SemiBorderSpacingControlFocus", ""),
};
public static IReadOnlyList<Tuple<string, string>> BorderThicknessTokens { get; } = new List<Tuple<string, string>>
{
new("SemiBorderThickness", ""),
new("SemiBorderThicknessControl", ""),
new("SemiBorderThicknessControlFocus", ""),
};
public static IReadOnlyList<Tuple<string, string>> SpacingTokens { get; } = new List<Tuple<string, string>>
{
new("SemiSpacingNone", ""),
new("SemiSpacingSuperTight", ""),
new("SemiSpacingExtraTight", ""),
new("SemiSpacingTight", ""),
new("SemiSpacingBaseTight", ""),
new("SemiSpacingBase", ""),
new("SemiSpacingBaseLoose", ""),
new("SemiSpacingLoose", ""),
new("SemiSpacingExtraLoose", ""),
new("SemiSpacingSuperLoose", ""),
};
public static IReadOnlyList<Tuple<string, string>> ThicknessTokens { get; } = new List<Tuple<string, string>>
{
new("SemiThicknessNone", ""),
new("SemiThicknessSuperTight", ""),
new("SemiThicknessExtraTight", ""),
new("SemiThicknessTight", ""),
new("SemiThicknessBaseTight", ""),
new("SemiThicknessBase", ""),
new("SemiThicknessBaseLoose", ""),
new("SemiThicknessLoose", ""),
new("SemiThicknessExtraLoose", ""),
new("SemiThicknessSuperLoose", ""),
};
public static IReadOnlyList<Tuple<string, string>> FontSizeTokens { get; } = new List<Tuple<string, string>>
{
new("SemiFontSizeSmall", ""),
new("SemiFontSizeRegular", ""),
new("SemiFontSizeHeader6", ""),
new("SemiFontSizeHeader5", ""),
new("SemiFontSizeHeader4", ""),
new("SemiFontSizeHeader3", ""),
new("SemiFontSizeHeader2", ""),
new("SemiFontSizeHeader1", ""),
};
public static IReadOnlyList<Tuple<string, string>> FontWeightTokens { get; } = new List<Tuple<string, string>>
{
new("SemiFontWeightLight", ""),
new("SemiFontWeightRegular", ""),
new("SemiFontWeightBold", ""),
};
public static IReadOnlyList<Tuple<string, string>> FontFamilyTokens { get; } = new List<Tuple<string, string>>
{
new("SemiFontFamilyRegular", ""),
};
}

View File

@@ -1,8 +1,5 @@
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Markup.Xaml;
using Avalonia.Threading;
using Semi.Avalonia.Demo.ViewModels;
@@ -16,13 +13,10 @@ public partial class PaletteDemo : UserControl
this.DataContext = new PaletteDemoViewModel();
}
protected override async void OnApplyTemplate(TemplateAppliedEventArgs e)
protected override async void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
PaletteDemoViewModel? vm = this.DataContext as PaletteDemoViewModel;
await Dispatcher.UIThread.InvokeAsync(() =>
{
vm?.InitializeResources();
});
await Dispatcher.UIThread.InvokeAsync(() => { vm?.InitializeResources(); });
}
}

View File

@@ -0,0 +1,70 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:Semi.Avalonia.Demo.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Semi.Avalonia.Demo.Pages.VariablesDemo"
x:DataType="vm:VariablesDemoViewModel">
<Design.DataContext>
<vm:VariablesDemoViewModel />
</Design.DataContext>
<ScrollViewer>
<StackPanel>
<ItemsControl ItemsSource="{Binding VariableGrid}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<HeaderedContentControl
Header="{Binding Title}"
Content="{Binding VariableItems}">
<HeaderedContentControl.HeaderTemplate>
<DataTemplate DataType="x:String">
<SelectableTextBlock
Margin="0,16,0,0"
Classes="H3"
Text="{Binding}"
Theme="{DynamicResource TitleSelectableTextBlock}" />
</DataTemplate>
</HeaderedContentControl.HeaderTemplate>
<HeaderedContentControl.ContentTemplate>
<DataTemplate>
<DataGrid IsReadOnly="True" ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*" Header="ResourceKey">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="vm:VariableItemViewModel">
<SelectableTextBlock
Margin="12,0,12,0"
VerticalAlignment="Center"
Text="{Binding ResourceKey}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn
Width="*"
x:DataType="vm:VariableItemViewModel"
Binding="{Binding Description}"
IsVisible="False"
CanUserSort="False"
Header="Description" />
<DataGridTemplateColumn Width="300" Header="Value">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="vm:VariableItemViewModel">
<SelectableTextBlock
Margin="12,0,12,0"
VerticalAlignment="Center"
Text="{Binding Value}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</HeaderedContentControl.ContentTemplate>
</HeaderedContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@@ -0,0 +1,22 @@
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Threading;
using Semi.Avalonia.Demo.ViewModels;
namespace Semi.Avalonia.Demo.Pages;
public partial class VariablesDemo : UserControl
{
public VariablesDemo()
{
InitializeComponent();
this.DataContext = new VariablesDemoViewModel();
}
protected override async void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
var vm = this.DataContext as VariablesDemoViewModel;
await Dispatcher.UIThread.InvokeAsync(() => { vm?.InitializeResources(); });
}
}

View File

@@ -45,7 +45,7 @@
x:DataType="viewModels:ColorItemViewModel"
Binding="{Binding ColorDisplayName}"
CanUserSort="False"
Header="Name" />
Header="Description" />
<DataGridTemplateColumn Width="100" Header="Hex">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="viewModels:ColorItemViewModel">
@@ -99,7 +99,7 @@
x:DataType="viewModels:ColorItemViewModel"
Binding="{Binding ColorDisplayName}"
CanUserSort="False"
Header="Name" />
Header="Description" />
<DataGridTemplateColumn Width="100" Header="Hex">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="viewModels:ColorItemViewModel">

View File

@@ -34,7 +34,7 @@
x:DataType="viewModels:ShadowItemViewModel"
Binding="{Binding ShadowDisplayName}"
CanUserSort="False"
Header="Name" />
Header="Description" />
<DataGridTemplateColumn Width="300" Header="BoxShadows">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="viewModels:ShadowItemViewModel">
@@ -66,7 +66,7 @@
x:DataType="viewModels:ShadowItemViewModel"
Binding="{Binding ShadowDisplayName}"
CanUserSort="False"
Header="Name" />
Header="Description" />
<DataGridTemplateColumn Width="300" Header="BoxShadows">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="viewModels:ShadowItemViewModel">

View File

@@ -6,6 +6,7 @@ using Avalonia.Controls;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Semi.Avalonia.Demo.Constant;
using Semi.Avalonia.Tokens.Palette;
using Semi.Avalonia.Demo.Converters;
@@ -228,132 +229,4 @@ public partial class ShadowGroupViewModel : ObservableObject
}
}
}
}
public static class ColorTokens
{
public static IReadOnlyList<Tuple<string, string>> PrimaryTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorPrimary", "Primary"),
new("SemiColorPrimaryPointerover", "Primary Pointerover"),
new("SemiColorPrimaryActive", "Primary Active"),
new("SemiColorPrimaryDisabled", "Primary Disabled"),
new("SemiColorPrimaryLight", "Primary Light"),
new("SemiColorPrimaryLightPointerover", "Primary Light Pointerover"),
new("SemiColorPrimaryLightActive", "Primary Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> SecondaryTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorSecondary", "Secondary"),
new("SemiColorSecondaryPointerover", "Secondary Pointerover"),
new("SemiColorSecondaryActive", "Secondary Active"),
new("SemiColorSecondaryDisabled", "Secondary Disabled"),
new("SemiColorSecondaryLight", "Secondary Light"),
new("SemiColorSecondaryLightPointerover", "Secondary Light Pointerover"),
new("SemiColorSecondaryLightActive", "Secondary Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> TertiaryTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorTertiary", "Tertiary"),
new("SemiColorTertiaryPointerover", "Tertiary Pointerover"),
new("SemiColorTertiaryActive", "Tertiary Active"),
new("SemiColorTertiaryLight", "Tertiary Light"),
new("SemiColorTertiaryLightPointerover", "Tertiary Light Pointerover"),
new("SemiColorTertiaryLightActive", "Tertiary Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> InformationTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorInformation", "Information"),
new("SemiColorInformationPointerover", "Information Pointerover"),
new("SemiColorInformationActive", "Information Active"),
new("SemiColorInformationDisabled", "Information Disabled"),
new("SemiColorInformationLight", "Information Light"),
new("SemiColorInformationLightPointerover", "Information Light Pointerover"),
new("SemiColorInformationLightActive", "Information Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> SuccessTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorSuccess", "Success"),
new("SemiColorSuccessPointerover", "Success Pointerover"),
new("SemiColorSuccessActive", "Success Active"),
new("SemiColorSuccessDisabled", "Success Disabled"),
new("SemiColorSuccessLight", "Success Light"),
new("SemiColorSuccessLightPointerover", "Success Light Pointerover"),
new("SemiColorSuccessLightActive", "Success Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> WarningTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorWarning", "Warning"),
new("SemiColorWarningPointerover", "Warning Pointerover"),
new("SemiColorWarningActive", "Warning Active"),
new("SemiColorWarningLight", "Warning Light"),
new("SemiColorWarningLightPointerover", "Warning Light Pointerover"),
new("SemiColorWarningLightActive", "Warning Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> DangerTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorDanger", "Danger"),
new("SemiColorDangerPointerover", "Danger Pointerover"),
new("SemiColorDangerActive", "Danger Active"),
new("SemiColorDangerLight", "Danger Light"),
new("SemiColorDangerLightPointerover", "Danger Light Pointerover"),
new("SemiColorDangerLightActive", "Danger Light Active"),
};
public static IReadOnlyList<Tuple<string, string>> TextTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorText0", "Text 0"),
new("SemiColorText1", "Text 1"),
new("SemiColorText2", "Text 2"),
new("SemiColorText3", "Text 3"),
};
public static IReadOnlyList<Tuple<string, string>> LinkTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorLink", "Link"),
new("SemiColorLinkPointerover", "Link Pointerover"),
new("SemiColorLinkActive", "Link Active"),
new("SemiColorLinkVisited", "Link Visited"),
};
public static IReadOnlyList<Tuple<string, string>> BackgroundTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorBackground0", "Background 0"),
new("SemiColorBackground1", "Background 1"),
new("SemiColorBackground2", "Background 2"),
new("SemiColorBackground3", "Background 3"),
new("SemiColorBackground4", "Background 4"),
};
public static IReadOnlyList<Tuple<string, string>> FillTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorFill0", "Fill 0"),
new("SemiColorFill1", "Fill 1"),
new("SemiColorFill2", "Fill 2"),
};
public static IReadOnlyList<Tuple<string, string>> BorderTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorBorder", "Border"),
};
public static IReadOnlyList<Tuple<string, string>> DisabledTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorDisabledText", "Disabled Text"),
new("SemiColorDisabledBorder", "Disabled Border"),
new("SemiColorDisabledBackground", "Disabled Background"),
new("SemiColorDisabledFill", "Disabled Fill"),
};
public static IReadOnlyList<Tuple<string, string>> ShadowTokens { get; } = new List<Tuple<string, string>>
{
new("SemiColorShadow", "Shadow"),
new("SemiShadowElevated", "Shadow Elevated"),
};
}

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using Semi.Avalonia.Demo.Constant;
using Semi.Avalonia.Tokens;
namespace Semi.Avalonia.Demo.ViewModels;
public partial class VariablesDemoViewModel : ObservableObject
{
private readonly IResourceDictionary? _dictionary;
public ObservableCollection<VariableGridViewModel> VariableGrid { get; set; } = [];
public VariablesDemoViewModel()
{
_dictionary = new Variables();
}
public void InitializeResources()
{
VariableGrid.Add(new VariableGridViewModel("Height", _dictionary, ColorTokens.HeightTokens));
VariableGrid.Add(new VariableGridViewModel("Icon Size", _dictionary, ColorTokens.IconSizeTokens));
VariableGrid.Add(new VariableGridViewModel("Border CornerRadius", _dictionary, ColorTokens.CornerRadiusTokens));
VariableGrid.Add(new VariableGridViewModel("Border Spacing", _dictionary, ColorTokens.BorderSpacingTokens));
VariableGrid.Add(new VariableGridViewModel("Border Thickness", _dictionary, ColorTokens.BorderThicknessTokens));
VariableGrid.Add(new VariableGridViewModel("Spacing", _dictionary, ColorTokens.SpacingTokens));
VariableGrid.Add(new VariableGridViewModel("Thickness", _dictionary, ColorTokens.ThicknessTokens));
VariableGrid.Add(new VariableGridViewModel("FontSize", _dictionary, ColorTokens.FontSizeTokens));
VariableGrid.Add(new VariableGridViewModel("FontWeight", _dictionary, ColorTokens.FontWeightTokens));
VariableGrid.Add(new VariableGridViewModel("FontFamily", _dictionary, ColorTokens.FontFamilyTokens));
}
}
public partial class VariableGridViewModel : ObservableObject
{
[ObservableProperty] private string? _title;
public ObservableCollection<VariableItemViewModel> VariableItems { get; set; } = [];
public VariableGridViewModel(string title, IResourceDictionary? dictionary,
IReadOnlyList<Tuple<string, string>> tokens)
{
Title = title;
foreach (var (key, name) in tokens)
{
if (dictionary?.TryGetValue(key, out var value) ?? false)
{
VariableItems.Add(new VariableItemViewModel(name, value ?? string.Empty, key));
}
}
}
}
public partial class VariableItemViewModel : ObservableObject
{
[ObservableProperty] private string? _resourceKey;
[ObservableProperty] private string? _description;
[ObservableProperty] private string? _value;
public VariableItemViewModel(string description, object value, string resourceKey)
{
ResourceKey = resourceKey;
Description = description;
Value = value.ToString();
}
}

View File

@@ -91,6 +91,9 @@
<TabItem Header="HighContrastTheme">
<pages:HighContrastDemo />
</TabItem>
<TabItem Header="Variables">
<pages:VariablesDemo />
</TabItem>
<TabItem Header="Icon">
<pages:IconDemo />
</TabItem>