如何在.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
相关产品推荐
相关产品推荐

