ControlTemplateBrowser.axaml代码
<Window 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"Height="544" Width="713" Loaded="Window_Loaded"x:Class="AvaloniaUI.ControlTemplateBrowser"Title="ControlTemplateBrowser"><Grid Margin="10" x:Name="grid" ColumnDefinitions="2*,5*"><ListBox x:Name="lstTypes" Background="WhiteSmoke"SelectionChanged="lstTypes_SelectionChanged"></ListBox><Grid Grid.Column="1" RowDefinitions="*,Auto" Margin="5"><ScrollViewer><TextBox x:Name="txtTemplate"TextWrapping="Wrap"AcceptsReturn="True"IsReadOnly="True"FontFamily="Consolas"FontSize="13" /></ScrollViewer><!-- 控件预览区 --><Border Grid.Row="1"BorderBrush="#DDD"BorderThickness="1"CornerRadius="6"Margin="0,10,0,0"Padding="10"Background="{DynamicResource ThemeBackgroundBrush}"><ContentPresenter x:Name="previewHost"HorizontalAlignment="Center"VerticalAlignment="Center" /></Border></Grid></Grid> </Window>
ControlTemplateBrowser.axaml.cs代码
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Chrome;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Styling;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;namespace AvaloniaUI;public partial class ControlTemplateBrowser : Window
{public ControlTemplateBrowser(){InitializeComponent();}private readonly Dictionary<string, Type> typeMap = new(StringComparer.Ordinal);private void Window_Loaded(object? sender, RoutedEventArgs e){try{var asmNames = new[]{"Avalonia.Controls","Avalonia.Controls.Primitives","Avalonia.Controls.Shapes","Avalonia.Controls.DataGrid","Avalonia.Controls.ItemsRepeater","Avalonia.Controls.Documents"};var controlType = typeof(Control);var topLevel = typeof(TopLevel);foreach (var name in asmNames){Assembly? asm = null;try { asm = Assembly.Load(name); } catch { continue; }foreach (var t in asm.GetTypes())if (t.IsPublic && !t.IsAbstract &&controlType.IsAssignableFrom(t) &&!topLevel.IsAssignableFrom(t) &&!typeMap.ContainsKey(t.Name))typeMap[t.Name] = t;}lstTypes.ItemsSource = typeMap.Keys.OrderBy(n => n).ToList();}catch (Exception ex){txtTemplate.Text = "加载失败:" + ex.Message;}}private void lstTypes_SelectionChanged(object? sender, SelectionChangedEventArgs e){if (lstTypes.SelectedItem is not string name || !typeMap.TryGetValue(name, out var type))return;previewHost.Content = null;try{if (type.GetConstructor(Type.EmptyTypes)?.Invoke(null) is not Control control){txtTemplate.Text = $"<< 无法实例化 {name} >>";return;}// 如果控件具有 Content 属性,设置默认文本“预览Abc”var contentProp = type.GetProperty("Content", BindingFlags.Public | BindingFlags.Instance);if (contentProp != null && contentProp.CanWrite && contentProp.PropertyType == typeof(object))contentProp.SetValue(control, "预览Abc");// 将控件显示在预览区previewHost.Content = control;control.Arrange(new Rect(control.DesiredSize));control.UpdateLayout();var sb = new StringBuilder();sb.AppendLine($"🔹 {type.FullName}, {type.Assembly.GetName().Name}");sb.AppendLine("──────── 模板(视觉树结构) ────────");if (control is TemplatedControl templated && templated.Template != null){var root = templated.Template.Build(templated)!.Result;// 内联递归打印结构void print(Control c, int d){sb.AppendLine(new string(' ', d * 2) + c.GetType().Name);if (c is Panel p) foreach (var child in p.Children) print(child, d + 1);else if (c is ContentControl cc && cc.Content is Control c1) print(c1, d + 1);else if (c is Decorator dc && dc.Child is Control c2) print(c2, d + 1);}print(root, 0);}else{sb.AppendLine("<< 控件不是 TemplatedControl 或模板为空 >>");}txtTemplate.Text = sb.ToString();}catch (Exception ex){txtTemplate.Text = "<< 出错: " + ex.Message + " >>";}}
}
运行效果
