You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET MAUI/Xamarin中动态创建控件可视化未知数据库架构

在.NET MAUI/Xamarin中可视化任意数据库架构

核心需求回顾

  • 展示任意数据库的表结构,暂不处理表间关联
  • 每个表单行缩进显示,包含表名及所有列的名称、数据类型(主键标记)
  • 基于已定义的Column、Table、DBSchema实体类实现

第一步:补全实体类构造函数

原代码中Column和Table缺少构造函数,先补上避免编译错误:

public class Column
{
    public string ColumnName { get; set; }
    public string DataType { get; set; }
    public bool IsPrimaryKey { get; set; }

    // 补全构造函数
    public Column(string columnName, string dataType, bool isPrimaryKey = false)
    {
        ColumnName = columnName;
        DataType = dataType;
        IsPrimaryKey = isPrimaryKey;
    }
}

public class Table
{
    public string TableName { get; set; }
    public List<Column> Columns { get; set; }

    // 补全构造函数
    public Table(string tableName, List<Column> columns)
    {
        TableName = tableName;
        Columns = columns ?? new List<Column>();
    }
}

public class DBSchema
{
    public List<Table> Tables { get; set; } = new List<Table>(); // 初始化集合

    public void AddTable(Table table)
    {
        if (table != null) Tables.Add(table);
    }
}

第二步:实现单行缩进的可视化方案

推荐使用CollectionView(.NET MAUI原生控件)动态渲染所有表,每个表项用横向布局实现单行展示,配合数据绑定完成动态内容填充。

1. 编写ViewModel

创建ViewModel管理数据库架构数据,处理后台数据加载:

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

public class SchemaViewModel : INotifyPropertyChanged
{
    private DBSchema _dbSchema;
    public DBSchema DBSchema
    {
        get => _dbSchema;
        set
        {
            _dbSchema = value;
            OnPropertyChanged();
        }
    }

    public async Task LoadSchemaAsync(string connectionString)
    {
        // 后台线程执行数据库操作,避免阻塞UI
        await Task.Run(() =>
        {
            DBSchema = GetDBSchema(connectionString);
        });
    }

    // 完善原GetDBSchema方法,补充主键判断逻辑
    public static DBSchema GetDBSchema(string connectionString)
    {
        DBSchema schema = new DBSchema();

        using var connection = new SqlConnection(connectionString);
        connection.Open();

        DataTable tablesScheme = connection.GetSchema("Tables");
        foreach (DataRow table in tablesScheme.Rows)
        {
            string tableName = table["TABLE_NAME"].ToString();
            DataTable columnsScheme = connection.GetSchema("Columns", new string[] { null, null, tableName });
            // 获取当前表的主键列
            DataTable pkScheme = connection.GetSchema("PrimaryKeys", new string[] { null, null, tableName });
            var primaryKeys = pkScheme.AsEnumerable()
                                      .Select(r => r["COLUMN_NAME"].ToString())
                                      .ToHashSet();

            List<Column> columns = new List<Column>();
            foreach (DataRow column in columnsScheme.Rows)
            {
                string colName = column["COLUMN_NAME"].ToString();
                bool isPk = primaryKeys.Contains(colName);
                columns.Add(new Column(colName, column["DATA_TYPE"].ToString(), isPk));
            }

            schema.AddTable(new Table(tableName, columns));
        }

        return schema;
    }

    // INotifyPropertyChanged实现
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 编写XAML布局

在页面中使用CollectionView绑定Tables集合,通过嵌套横向布局实现单行缩进效果:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourNamespace"
             x:Class="YourNamespace.SchemaPage">
    <ContentPage.BindingContext>
        <local:SchemaViewModel />
    </ContentPage.BindingContext>

    <CollectionView ItemsSource="{Binding DBSchema.Tables}"
                    Margin="10"
                    VerticalOptions="Fill">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <HorizontalStackLayout Margin="0,5,0,5"
                                      Spacing="10">
                    <!-- 表名区域:固定宽度加粗显示 -->
                    <Label Text="{Binding TableName}"
                           FontAttributes="Bold"
                           WidthRequest="160" />
                    <!-- 列信息区域:横向排列,实现缩进效果 -->
                    <HorizontalStackLayout Spacing="8">
                        <BindableLayout ItemsSource="{Binding Columns}">
                            <BindableLayout.ItemTemplate>
                                <DataTemplate>
                                    <Label>
                                        <Label.FormattedText>
                                            <FormattedString>
                                                <Span Text="{Binding ColumnName}" />
                                                <Span Text="({Binding DataType})"
                                                      TextColor="Gray" />
                                                <Span Text="*"
                                                      TextColor="DarkRed"
                                                      IsVisible="{Binding IsPrimaryKey}" />
                                            </FormattedString>
                                        </Label.FormattedText>
                                    </Label>
                                </DataTemplate>
                            </BindableLayout.ItemTemplate>
                        </BindableLayout>
                    </HorizontalStackLayout>
                </HorizontalStackLayout>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

3. 触发数据加载

在页面的OnAppearing方法中调用加载逻辑:

protected override async void OnAppearing()
{
    base.OnAppearing();
    var vm = BindingContext as SchemaViewModel;
    if (vm != null)
    {
        // 替换为你的数据库连接字符串
        await vm.LoadSchemaAsync("Server=.;Database=YourDB;Trusted_Connection=True;");
    }
}

UraniumUI DataGrid替代方案(非单行布局)

如果坚持使用UraniumUI DataGrid,可通过CollectionView为每个表生成独立表格,但此方案不符合单行缩进要求,仅作参考:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourNamespace"
             xmlns:uranium="clr-namespace:UraniumUI.Controls;assembly=UraniumUI"
             x:Class="YourNamespace.SchemaPage">
    <ContentPage.BindingContext>
        <local:SchemaViewModel />
    </ContentPage.BindingContext>

    <CollectionView ItemsSource="{Binding DBSchema.Tables}"
                    Margin="10">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <VerticalStackLayout Margin="0,0,0,15">
                    <Label Text="{Binding TableName}" 
                           FontAttributes="Bold" 
                           FontSize="Large"
                           Margin="0,0,0,5"/>
                    <uranium:DataGrid ItemsSource="{Binding Columns}" 
                                      AutoGenerateColumns="False">
                        <uranium:DataGrid.Columns>
                            <uranium:DataGridTextColumn PropertyName="ColumnName" Header="列名"/>
                            <uranium:DataGridTextColumn PropertyName="DataType" Header="数据类型"/>
                            <uranium:DataGridCheckBoxColumn PropertyName="IsPrimaryKey" Header="主键"/>
                        </uranium:DataGrid.Columns>
                    </uranium:DataGrid>
                </VerticalStackLayout>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

内容的提问来源于stack exchange,提问作者pr0skilled

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:11:07