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 + " >>";
        }
    }
}

运行效果

image

 

posted on 2025-10-24 14:59  dalgleish  阅读(0)  评论(0)    收藏  举报