WIP query tool, executes query for real and shows result
This commit is contained in:
parent
fd4cb8692d
commit
bee0e0915f
9 changed files with 204 additions and 61 deletions
|
|
@ -1,7 +1,8 @@
|
||||||
# pgLabII AI Assistant Guidelines
|
# pgLabII AI Assistant Guidelines
|
||||||
|
|
||||||
## Project Context
|
## Project Context
|
||||||
This is a .NET 8/C# 13 Avalonia cross-platform application for document management.
|
This is a .NET 9/C# 14 Avalonia cross-platform application for querying and inspecting
|
||||||
|
postgresql databases. It should also be a good editor for SQL files.
|
||||||
|
|
||||||
### Architecture Overview
|
### Architecture Overview
|
||||||
- **Main Project**: pgLabII (Avalonia UI)
|
- **Main Project**: pgLabII (Avalonia UI)
|
||||||
|
|
@ -12,16 +13,18 @@ This is a .NET 8/C# 13 Avalonia cross-platform application for document manageme
|
||||||
## Coding Standards
|
## Coding Standards
|
||||||
|
|
||||||
### C# Guidelines
|
### C# Guidelines
|
||||||
- Use C# 13 features and modern .NET patterns
|
- Use C# 14 features and modern .NET patterns
|
||||||
- Prefer primary constructors for dependency injection
|
- Prefer primary constructors for dependency injection
|
||||||
- Use `var` for obvious types, explicit types for clarity
|
- Use `var` for obvious types, explicit types for clarity
|
||||||
- Implement proper async/await patterns for I/O operations
|
- Implement proper async/await patterns for I/O operations
|
||||||
- Use nullable reference types consistently
|
- Use nullable reference types consistently
|
||||||
- Prefer "target-typed new"
|
- Prefer "target-typed new"
|
||||||
- Prefer "list initializer" over new
|
- Prefer "list initializer" over new
|
||||||
|
- Package versions are managed centrally in Directory.Packages.props
|
||||||
|
|
||||||
### Avalonia-Specific
|
### Avalonia-Specific
|
||||||
- Follow MVVM pattern strictly
|
- Follow MVVM pattern strictly
|
||||||
|
- x:Name does work for making components accessible in code-behind
|
||||||
- ViewModels should inherit from appropriate base classes
|
- ViewModels should inherit from appropriate base classes
|
||||||
- Use ReactiveUI patterns where applicable
|
- Use ReactiveUI patterns where applicable
|
||||||
- Make use of annotations to generate bindable properties
|
- Make use of annotations to generate bindable properties
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,9 @@ public class EditHistoryManager : IEditHistoryManager
|
||||||
|
|
||||||
public void SaveToDatabase()
|
public void SaveToDatabase()
|
||||||
{
|
{
|
||||||
_db.EditHistory.AddRange(_pendingEdits);
|
// _db.EditHistory.AddRange(_pendingEdits);
|
||||||
_db.SaveChanges();
|
// _db.SaveChanges();
|
||||||
_pendingEdits.Clear();
|
// _pendingEdits.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<EditHistoryEntry> GetHistory() => _pendingEdits.AsReadOnly();
|
public IReadOnlyList<EditHistoryEntry> GetHistory() => _pendingEdits.AsReadOnly();
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Npgsql;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ReactiveUI.SourceGenerators;
|
using ReactiveUI.SourceGenerators;
|
||||||
|
using pgLabII.Model;
|
||||||
|
|
||||||
namespace pgLabII.ViewModels;
|
namespace pgLabII.ViewModels;
|
||||||
|
|
||||||
|
|
@ -18,56 +22,50 @@ public class ColumnInfo
|
||||||
|
|
||||||
public partial class QueryToolViewModel : ViewModelBase, IViewItem
|
public partial class QueryToolViewModel : ViewModelBase, IViewItem
|
||||||
{
|
{
|
||||||
|
private readonly ServerConfigurationEntity? _serverConfig;
|
||||||
|
|
||||||
// Tab caption
|
// Tab caption
|
||||||
[Reactive] private string _caption = "Query";
|
[Reactive] private string _caption = "Query";
|
||||||
|
|
||||||
// SQL text bound to the editor
|
// SQL text bound to the editor
|
||||||
[Reactive] private string _userSql = "SELECT 1 AS one, 'hello' AS text;";
|
[Reactive] private string _userSql = "SELECT n, 1, 'hello', '2025-4-5'::date FROM generate_series(1, 2000) AS d(n)";
|
||||||
|
|
||||||
// Summary and status labels
|
// Summary and status labels
|
||||||
[Reactive] private string _resultSummary = "Showing 0 rows";
|
[Reactive] private string _resultSummary = "Showing 0 rows";
|
||||||
[Reactive] private string _status = "Ready";
|
[Reactive] private string _status = "Ready";
|
||||||
|
|
||||||
// Paging flags
|
// Paging flags
|
||||||
[Reactive] private bool _canLoadMore = false;
|
[Reactive] private bool _canLoadMore;
|
||||||
[Reactive] private bool _autoLoadMore = false;
|
[Reactive] private bool _autoLoadMore;
|
||||||
|
|
||||||
// Rows shown in the DataGrid. For now, simple object rows for AutoGenerateColumns.
|
// Rows shown in the DataGrid. For now, simple object rows for AutoGenerateColumns.
|
||||||
public ObservableCollection<object> Rows { get; } = new();
|
public ObservableCollection<object> Rows { get; } = new();
|
||||||
public ObservableCollection<ColumnInfo> Columns { get; } = new();
|
|
||||||
|
[Reactive] private IReadOnlyList<ColumnInfo> _columns = new List<ColumnInfo>();
|
||||||
|
|
||||||
// Commands (stubs)
|
// Commands
|
||||||
public ReactiveCommand<Unit, Unit> RunQuery { get; }
|
public ReactiveCommand<Unit, Unit> RunQuery { get; }
|
||||||
public ReactiveCommand<Unit, Unit> LoadMore { get; }
|
public ReactiveCommand<Unit, Unit> LoadMore { get; }
|
||||||
public ReactiveCommand<Unit, Unit> ExportResults { get; }
|
public ReactiveCommand<Unit, Unit> ExportResults { get; }
|
||||||
public ReactiveCommand<Unit, Unit> OpenSqlFile { get; }
|
public ReactiveCommand<Unit, Unit> OpenSqlFile { get; }
|
||||||
public ReactiveCommand<Unit, Unit> SaveSqlFile { get; }
|
public ReactiveCommand<Unit, Unit> SaveSqlFile { get; }
|
||||||
|
|
||||||
public QueryToolViewModel()
|
public QueryToolViewModel(ServerConfigurationEntity? serverConfig)
|
||||||
{
|
{
|
||||||
// Create stub commands that only update labels/rows so UI is interactive without real DB work.
|
_serverConfig = serverConfig;
|
||||||
RunQuery = ReactiveCommand.Create(() =>
|
|
||||||
|
// Create command that executes actual SQL queries
|
||||||
|
RunQuery = ReactiveCommand.CreateFromTask(async () =>
|
||||||
{
|
{
|
||||||
Rows.Clear();
|
await ExecuteQuery();
|
||||||
Columns.Clear();
|
|
||||||
Columns.Add(new ColumnInfo { Name = "id", DataType = typeof(int), DisplayName = "ID" });
|
|
||||||
Columns.Add(new ColumnInfo { Name = "name", DataType = typeof(string), DisplayName = "Name" });
|
|
||||||
Columns.Add(new ColumnInfo { Name = "active", DataType = typeof(bool), DisplayName = "Active" });
|
|
||||||
Rows.Add(new { id = 1, name = "Alice", active = true });
|
|
||||||
Rows.Add(new { id = 2, name = "Bob", active = false });
|
|
||||||
this.RaisePropertyChanged(nameof(Rows)); // Force DataGrid refresh
|
|
||||||
ResultSummary = $"Showing {Rows.Count} rows";
|
|
||||||
Status = "Query executed (stub)";
|
|
||||||
CanLoadMore = true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
LoadMore = ReactiveCommand.Create(() =>
|
LoadMore = ReactiveCommand.Create(() =>
|
||||||
{
|
{
|
||||||
// Add more demo rows to see paging UX
|
// Add more demo rows to see paging UX
|
||||||
var baseId = Rows.Count;
|
|
||||||
for (int i = 1; i <= 3; i++)
|
for (int i = 1; i <= 3; i++)
|
||||||
{
|
{
|
||||||
Rows.Add(new { id = baseId + i, name = $"User {baseId + i}", active = (baseId + i) % 2 == 0 });
|
Rows.Add(new RowData(10));
|
||||||
}
|
}
|
||||||
this.RaisePropertyChanged(nameof(Rows)); // Force DataGrid refresh
|
this.RaisePropertyChanged(nameof(Rows)); // Force DataGrid refresh
|
||||||
ResultSummary = $"Showing {Rows.Count} rows";
|
ResultSummary = $"Showing {Rows.Count} rows";
|
||||||
|
|
@ -91,4 +89,117 @@ public partial class QueryToolViewModel : ViewModelBase, IViewItem
|
||||||
Status = "Save SQL file (stub)";
|
Status = "Save SQL file (stub)";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteQuery()
|
||||||
|
{
|
||||||
|
if (_serverConfig == null)
|
||||||
|
{
|
||||||
|
Status = "Error: No server configuration selected";
|
||||||
|
ResultSummary = "Showing 0 rows";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(UserSql))
|
||||||
|
{
|
||||||
|
Status = "Error: SQL query is empty";
|
||||||
|
ResultSummary = "Showing 0 rows";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Status = "Executing query...";
|
||||||
|
Rows.Clear();
|
||||||
|
|
||||||
|
var connStringBuilder = new NpgsqlConnectionStringBuilder
|
||||||
|
{
|
||||||
|
Host = _serverConfig.Host,
|
||||||
|
Port = _serverConfig.Port,
|
||||||
|
Database = _serverConfig.InitialDatabase,
|
||||||
|
Username = _serverConfig.UserName,
|
||||||
|
Password = _serverConfig.Password,
|
||||||
|
SslMode = _serverConfig.SslMode,
|
||||||
|
};
|
||||||
|
|
||||||
|
using var connection = new NpgsqlConnection(connStringBuilder.ConnectionString);
|
||||||
|
await connection.OpenAsync();
|
||||||
|
|
||||||
|
using var command = new NpgsqlCommand(UserSql, connection);
|
||||||
|
using var reader = await command.ExecuteReaderAsync();
|
||||||
|
|
||||||
|
// Get column information - build in a temporary list to avoid multiple CollectionChanged events
|
||||||
|
var schema = reader.GetColumnSchema();
|
||||||
|
var columnList = new List<ColumnInfo>();
|
||||||
|
foreach (var column in schema)
|
||||||
|
{
|
||||||
|
columnList.Add(new ColumnInfo
|
||||||
|
{
|
||||||
|
Name = column.ColumnName ?? "Unknown",
|
||||||
|
DisplayName = column.ColumnName,
|
||||||
|
DataType = column.DataType ?? typeof(string),
|
||||||
|
IsSortable = true,
|
||||||
|
IsFilterable = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read rows - also build in a temporary list first
|
||||||
|
var rowList = new List<object>();
|
||||||
|
int rowCount = 0;
|
||||||
|
while (await reader.ReadAsync())
|
||||||
|
{
|
||||||
|
var values = new object[reader.FieldCount];
|
||||||
|
reader.GetValues(values);
|
||||||
|
|
||||||
|
// Convert to a dynamic object for the DataGrid
|
||||||
|
var row = new RowData(reader.FieldCount);
|
||||||
|
for (int i = 0; i < reader.FieldCount; i++)
|
||||||
|
{
|
||||||
|
row.Values[i] = values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
rowList.Add(row);
|
||||||
|
rowCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap the entire Columns list at once (single property change notification)
|
||||||
|
Columns = columnList;
|
||||||
|
|
||||||
|
// Add all rows at once
|
||||||
|
Rows.Clear();
|
||||||
|
foreach (var row in rowList)
|
||||||
|
{
|
||||||
|
Rows.Add(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultSummary = $"Showing {rowCount} rows";
|
||||||
|
Status = "Query executed successfully";
|
||||||
|
CanLoadMore = false; // TODO: Implement pagination if needed
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Status = $"Error: {ex.Message}";
|
||||||
|
ResultSummary = "Showing 0 rows";
|
||||||
|
Rows.Clear();
|
||||||
|
Columns = new List<ColumnInfo>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dynamic row container for displaying results in the DataGrid
|
||||||
|
/// </summary>
|
||||||
|
public class RowData
|
||||||
|
{
|
||||||
|
public RowData(int columnCount)
|
||||||
|
{
|
||||||
|
Values = new object[columnCount];
|
||||||
|
}
|
||||||
|
//public Dictionary<string, object?> Values { get; } = new();
|
||||||
|
public object[] Values { get; }
|
||||||
|
|
||||||
|
public object? this[int idx]
|
||||||
|
{
|
||||||
|
get => Values[idx]; //.TryGetValue(key, out var value) ? value : null;
|
||||||
|
set => Values[idx] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,9 @@ public class ServerConfigurationViewModel : ReactiveObject
|
||||||
var window = new Views.EditServerConfigurationWindow(new(this)) { New = false };
|
var window = new Views.EditServerConfigurationWindow(new(this)) { New = false };
|
||||||
window.Show();
|
window.Show();
|
||||||
});
|
});
|
||||||
ExploreCommand = ReactiveCommand.Create(() => {
|
ExploreCommand = ReactiveCommand.Create(() =>
|
||||||
var window = new Views.SingleDatabaseWindow();
|
{
|
||||||
|
var window = new Views.SingleDatabaseWindow(entity);
|
||||||
window.Show();
|
window.Show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,11 @@ public class ServerListViewModel : ViewModelBase
|
||||||
[
|
[
|
||||||
new (new()
|
new (new()
|
||||||
{
|
{
|
||||||
Name = "Local pg15",
|
Name = "pg18",
|
||||||
ColorEnabled = true,
|
ColorEnabled = true,
|
||||||
Host = "localhost",
|
Host = "localhost",
|
||||||
Port = 5434,
|
Port = 5418,
|
||||||
InitialDatabase = "dbname",
|
InitialDatabase = "postgres",
|
||||||
UserName = "postgres",
|
UserName = "postgres",
|
||||||
Password = "admin",
|
Password = "admin",
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using pgLabII.Model;
|
||||||
|
|
||||||
namespace pgLabII.ViewModels;
|
namespace pgLabII.ViewModels;
|
||||||
|
|
||||||
|
|
@ -7,9 +8,17 @@ namespace pgLabII.ViewModels;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ViewListViewModel : ViewModelBase
|
public class ViewListViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
public ObservableCollection<IViewItem> Views { get; } = [
|
private readonly ServerConfigurationEntity serverConfig;
|
||||||
new QueryToolViewModel() { Caption = "Abc" },
|
|
||||||
new QueryToolViewModel() { Caption = "Test" } ,
|
public ViewListViewModel(ServerConfigurationEntity serverConfig)
|
||||||
];
|
{
|
||||||
|
this.serverConfig = serverConfig;
|
||||||
|
|
||||||
|
Views = [
|
||||||
|
new QueryToolViewModel(serverConfig) { Caption = "Abc" },
|
||||||
|
new QueryToolViewModel(serverConfig) { Caption = "Test" },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
public ObservableCollection<IViewItem> Views { get; private set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,17 @@
|
||||||
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="600"
|
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="600"
|
||||||
x:Class="pgLabII.Views.QueryToolView"
|
x:Class="pgLabII.Views.QueryToolView"
|
||||||
x:DataType="viewModels:QueryToolViewModel">
|
x:DataType="viewModels:QueryToolViewModel">
|
||||||
<Grid RowDefinitions="Auto,Auto,*">
|
<Grid RowDefinitions="Auto,Auto,Auto,*">
|
||||||
<!-- Step 2: Open/Save toolbar -->
|
<!-- Step 2: Open/Save toolbar -->
|
||||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="4">
|
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="4">
|
||||||
<Button Content="Open" Command="{Binding OpenSqlFile}" ToolTip.Tip="Open .sql file (Ctrl+O)" />
|
<Button Content="Open" Command="{Binding OpenSqlFile}" ToolTip.Tip="Open .sql file (Ctrl+O)" />
|
||||||
<Button Content="Save" Command="{Binding SaveSqlFile}" ToolTip.Tip="Save .sql file (Ctrl+S)" Margin="4,0,0,0"/>
|
<Button Content="Save" Command="{Binding SaveSqlFile}" ToolTip.Tip="Save .sql file (Ctrl+S)" Margin="4,0,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<!-- Step 2: SQL Editor -->
|
||||||
|
<controls:CodeEditorView Grid.Row="1"
|
||||||
|
Text="{Binding UserSql, Mode=TwoWay}" />
|
||||||
<!-- Step 3: Results toolbar -->
|
<!-- Step 3: Results toolbar -->
|
||||||
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="4">
|
<StackPanel Grid.Row="2" Orientation="Horizontal" Margin="4">
|
||||||
<Button Content="Run" Command="{Binding RunQuery}" />
|
<Button Content="Run" Command="{Binding RunQuery}" />
|
||||||
<Button Content="Load more" Command="{Binding LoadMore}" IsEnabled="{Binding CanLoadMore}" Margin="4,0,0,0"/>
|
<Button Content="Load more" Command="{Binding LoadMore}" IsEnabled="{Binding CanLoadMore}" Margin="4,0,0,0"/>
|
||||||
<Button Content="Export..." Command="{Binding ExportResults}" Margin="4,0,0,0"/>
|
<Button Content="Export..." Command="{Binding ExportResults}" Margin="4,0,0,0"/>
|
||||||
|
|
@ -22,18 +25,16 @@
|
||||||
<TextBlock Text="{Binding ResultSummary}" Margin="16,0,0,0" VerticalAlignment="Center"/>
|
<TextBlock Text="{Binding ResultSummary}" Margin="16,0,0,0" VerticalAlignment="Center"/>
|
||||||
<TextBlock Text="{Binding Status}" Margin="8,0,0,0" VerticalAlignment="Center" Foreground="Gray"/>
|
<TextBlock Text="{Binding Status}" Margin="8,0,0,0" VerticalAlignment="Center" Foreground="Gray"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<!-- Editor and Results grid with splitter -->
|
<!-- Step 4: Results grid -->
|
||||||
<Grid Grid.Row="2" ColumnDefinitions="*,Auto,*">
|
<DataGrid Grid.Row="3"
|
||||||
<controls:CodeEditorView Grid.Column="0" Text="{Binding UserSql, Mode=TwoWay}" />
|
x:Name="ResultsDataGrid"
|
||||||
<GridSplitter Grid.Column="1" Width="6" Background="Gray" ShowsPreview="True" HorizontalAlignment="Stretch" />
|
ItemsSource="{Binding Rows}"
|
||||||
<DataGrid x:Name="ResultsGrid"
|
IsReadOnly="True"
|
||||||
Grid.Column="2"
|
SelectionMode="Extended"
|
||||||
ItemsSource="{Binding Rows}"
|
CanUserSortColumns="True"
|
||||||
IsReadOnly="True"
|
AutoGenerateColumns="False"
|
||||||
SelectionMode="Extended"
|
Margin="4">
|
||||||
CanUserSortColumns="True"
|
<DataGrid.Columns />
|
||||||
AutoGenerateColumns="False"
|
</DataGrid>
|
||||||
Margin="4" />
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
@ -1,26 +1,41 @@
|
||||||
using Avalonia;
|
using System.ComponentModel;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using pgLabII.ViewModels;
|
using pgLabII.ViewModels;
|
||||||
|
|
||||||
namespace pgLabII.Views;
|
namespace pgLabII.Views;
|
||||||
|
|
||||||
public partial class QueryToolView : UserControl
|
public partial class QueryToolView : UserControl
|
||||||
{
|
{
|
||||||
|
private QueryToolViewModel? _currentVm;
|
||||||
|
|
||||||
public QueryToolView()
|
public QueryToolView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.DataContextChanged += (_, __) => WireColumns();
|
this.DataContextChanged += (_, _) => WireColumns();
|
||||||
WireColumns();
|
WireColumns();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WireColumns()
|
private void WireColumns()
|
||||||
{
|
{
|
||||||
|
// Unsubscribe from previous ViewModel if it exists
|
||||||
|
if (_currentVm != null)
|
||||||
|
{
|
||||||
|
_currentVm.PropertyChanged -= OnViewModelPropertyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
if (DataContext is QueryToolViewModel vm)
|
if (DataContext is QueryToolViewModel vm)
|
||||||
{
|
{
|
||||||
var grid = this.FindControl<DataGrid>("ResultsGrid");
|
_currentVm = vm;
|
||||||
vm.Columns.CollectionChanged += (s, e) => RegenerateColumns(grid, vm);
|
vm.PropertyChanged += OnViewModelPropertyChanged;
|
||||||
|
RegenerateColumns(this.ResultsDataGrid, vm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(QueryToolViewModel.Columns) && DataContext is QueryToolViewModel vm)
|
||||||
|
{
|
||||||
|
var grid = this.ResultsDataGrid;
|
||||||
RegenerateColumns(grid, vm);
|
RegenerateColumns(grid, vm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -28,15 +43,17 @@ public partial class QueryToolView : UserControl
|
||||||
private void RegenerateColumns(DataGrid grid, QueryToolViewModel vm)
|
private void RegenerateColumns(DataGrid grid, QueryToolViewModel vm)
|
||||||
{
|
{
|
||||||
grid.Columns.Clear();
|
grid.Columns.Clear();
|
||||||
foreach (var col in vm.Columns)
|
//foreach (var col in vm.Columns)
|
||||||
|
for (int i = 0; i < vm.Columns.Count; i++)
|
||||||
{
|
{
|
||||||
|
var col = vm.Columns[i];
|
||||||
DataGridColumn gridCol;
|
DataGridColumn gridCol;
|
||||||
if (col.DataType == typeof(bool))
|
if (col.DataType == typeof(bool))
|
||||||
{
|
{
|
||||||
gridCol = new DataGridCheckBoxColumn
|
gridCol = new DataGridCheckBoxColumn
|
||||||
{
|
{
|
||||||
Header = col.DisplayName ?? col.Name,
|
Header = col.DisplayName ?? col.Name,
|
||||||
Binding = new Avalonia.Data.Binding(col.Name)
|
Binding = new Avalonia.Data.Binding($"Values[{i}]")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -44,7 +61,7 @@ public partial class QueryToolView : UserControl
|
||||||
gridCol = new DataGridTextColumn
|
gridCol = new DataGridTextColumn
|
||||||
{
|
{
|
||||||
Header = col.DisplayName ?? col.Name,
|
Header = col.DisplayName ?? col.Name,
|
||||||
Binding = new Avalonia.Data.Binding(col.Name)
|
Binding = new Avalonia.Data.Binding($"Values[{i}]")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
grid.Columns.Add(gridCol);
|
grid.Columns.Add(gridCol);
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
using pgLabII.Model;
|
||||||
using pgLabII.ViewModels;
|
using pgLabII.ViewModels;
|
||||||
|
|
||||||
namespace pgLabII.Views;
|
namespace pgLabII.Views;
|
||||||
|
|
||||||
public partial class SingleDatabaseWindow : Window
|
public partial class SingleDatabaseWindow : Window
|
||||||
{
|
{
|
||||||
public SingleDatabaseWindow()
|
public SingleDatabaseWindow(ServerConfigurationEntity serverConfig)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
DataContext = new ViewListViewModel();
|
DataContext = new ViewListViewModel(serverConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue