A:集成数据库功能
This commit is contained in:
1 parent
974d16833c
commit
99c2c59552
6 files changed
+793
-69
No files matched your search
@@ -127,8 +127,8 @@ namespace Sharp.Demo
|
|||||||
services.AddTransient<Sharp.Demo.Views.Windows.HttpServerWindow>();
|
services.AddTransient<Sharp.Demo.Views.Windows.HttpServerWindow>();
|
||||||
services.AddTransient<Sharp.Demo.Views.Windows.HttpClientWindow>();
|
services.AddTransient<Sharp.Demo.Views.Windows.HttpClientWindow>();
|
||||||
services.AddTransient<Sharp.Demo.Views.Windows.PlcDebugWindow>();
|
services.AddTransient<Sharp.Demo.Views.Windows.PlcDebugWindow>();
|
||||||
|
services.AddTransient<Sharp.Demo.Views.Windows.DatabaseWindow>();
|
||||||
// TODO: 添加其他窗口注册
|
// TODO: 添加其他窗口注册
|
||||||
// services.AddTransient<Sharp.Demo.Views.Windows.DatabaseWindow>();
|
|
||||||
// services.AddTransient<Sharp.Demo.Views.Windows.SerialPortWindow>();
|
// services.AddTransient<Sharp.Demo.Views.Windows.SerialPortWindow>();
|
||||||
// etc...
|
// etc...
|
||||||
|
|
||||||
|
|||||||
@@ -237,8 +237,12 @@ namespace Sharp.Demo.ViewModels
|
|||||||
_windowManager.ShowWindow<Sharp.Demo.Views.Windows.PlcDebugWindow>(moduleKey);
|
_windowManager.ShowWindow<Sharp.Demo.Views.Windows.PlcDebugWindow>(moduleKey);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 其他窗口待实现
|
|
||||||
case "Database":
|
case "Database":
|
||||||
|
_logger.LogInformation("正在打开数据库管理窗口...");
|
||||||
|
_windowManager.ShowWindow<Sharp.Demo.Views.Windows.DatabaseWindow>(moduleKey);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 其他窗口待实现
|
||||||
case "SerialPort":
|
case "SerialPort":
|
||||||
case "ProcessTest":
|
case "ProcessTest":
|
||||||
case "LogDemo":
|
case "LogDemo":
|
||||||
|
|||||||
@@ -14,11 +14,20 @@ using Sharp.Wpf.Services;
|
|||||||
using Sharp.Wpf.Navigation;
|
using Sharp.Wpf.Navigation;
|
||||||
using Sharp.Demo.Data;
|
using Sharp.Demo.Data;
|
||||||
using Sharp.Demo.Views.Dialogs;
|
using Sharp.Demo.Views.Dialogs;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Common.ExpandFun;
|
||||||
|
|
||||||
namespace Sharp.Demo.ViewModels.Pages
|
namespace Sharp.Demo.ViewModels.Pages
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数据库管理页面 ViewModel - EF Core + Repository 演示
|
/// 数据库管理页面 ViewModel - EF Core + Repository 演示
|
||||||
|
/// 展示 Sharp.Data 模块的完整功能:
|
||||||
|
/// - 基本 CRUD 操作
|
||||||
|
/// - 分页查询
|
||||||
|
/// - 批量操作
|
||||||
|
/// - 软删除和审计追踪
|
||||||
|
/// - 统计和查询
|
||||||
|
/// - 事务处理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DatabaseViewModel : ViewModelBase, INavigationAware
|
public class DatabaseViewModel : ViewModelBase, INavigationAware
|
||||||
{
|
{
|
||||||
@@ -31,6 +40,21 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
private string _statusText = string.Empty;
|
private string _statusText = string.Empty;
|
||||||
private string _recordCount = "记录数: 0";
|
private string _recordCount = "记录数: 0";
|
||||||
|
|
||||||
|
// 分页相关
|
||||||
|
private int _currentPage = 1;
|
||||||
|
private int _pageSize = 10;
|
||||||
|
private int _totalPages = 1;
|
||||||
|
private int _totalCount = 0;
|
||||||
|
private string _pageInfo = "第 1/1 页";
|
||||||
|
|
||||||
|
// 统计信息
|
||||||
|
private int _totalUsers = 0;
|
||||||
|
private int _activeUsers = 0;
|
||||||
|
private int _inactiveUsers = 0;
|
||||||
|
|
||||||
|
// 当前窗口引用(用于设置对话框父窗口)
|
||||||
|
public Window? CurrentWindow { get; set; }
|
||||||
|
|
||||||
public DatabaseViewModel(
|
public DatabaseViewModel(
|
||||||
IDataContext dataContext,
|
IDataContext dataContext,
|
||||||
ILogger<DatabaseViewModel> logger,
|
ILogger<DatabaseViewModel> logger,
|
||||||
@@ -43,17 +67,31 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
Users = new ObservableCollection<User>();
|
Users = new ObservableCollection<User>();
|
||||||
|
|
||||||
// 初始化命令
|
// 初始化命令
|
||||||
LoadDataCommand = new AsyncCommand(async () => await LoadDataAsync());
|
LoadDataCommand = new AsyncCommand(async () => await LoadPagedDataAsync());
|
||||||
SearchCommand = new AsyncCommand(async () => await LoadDataAsync(SearchText.Trim()));
|
SearchCommand = new AsyncCommand(async () => await LoadPagedDataAsync());
|
||||||
ClearSearchCommand = new AsyncCommand(async () =>
|
ClearSearchCommand = new AsyncCommand(async () =>
|
||||||
{
|
{
|
||||||
SearchText = string.Empty;
|
SearchText = string.Empty;
|
||||||
await LoadDataAsync();
|
CurrentPage = 1;
|
||||||
|
await LoadPagedDataAsync();
|
||||||
});
|
});
|
||||||
AddCommand = new RelayCommand(_ => Add());
|
AddCommand = new RelayCommand(_ => Add());
|
||||||
EditCommand = new RelayCommand(_ => Edit(), _ => SelectedUser != null);
|
EditCommand = new RelayCommand(_ => Edit(), _ => SelectedUser != null);
|
||||||
DeleteCommand = new AsyncCommand(DeleteAsync, () => SelectedUser != null);
|
DeleteCommand = new AsyncCommand(DeleteAsync, () => SelectedUser != null);
|
||||||
RefreshCommand = new AsyncCommand(async () => await LoadDataAsync(SearchText.Trim()));
|
RefreshCommand = new AsyncCommand(async () => await LoadPagedDataAsync());
|
||||||
|
|
||||||
|
// 分页命令
|
||||||
|
FirstPageCommand = new AsyncCommand(async () => { CurrentPage = 1; await LoadPagedDataAsync(); }, () => CurrentPage > 1);
|
||||||
|
PreviousPageCommand = new AsyncCommand(async () => { CurrentPage--; await LoadPagedDataAsync(); }, () => CurrentPage > 1);
|
||||||
|
NextPageCommand = new AsyncCommand(async () => { CurrentPage++; await LoadPagedDataAsync(); }, () => CurrentPage < TotalPages);
|
||||||
|
LastPageCommand = new AsyncCommand(async () => { CurrentPage = TotalPages; await LoadPagedDataAsync(); }, () => CurrentPage < TotalPages);
|
||||||
|
|
||||||
|
// 批量操作命令
|
||||||
|
BatchAddCommand = new AsyncCommand(BatchAddAsync);
|
||||||
|
BatchDeleteCommand = new AsyncCommand(BatchDeleteAsync, () => Users.Any());
|
||||||
|
|
||||||
|
// 统计命令
|
||||||
|
RefreshStatsCommand = new AsyncCommand(RefreshStatsAsync);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 属性
|
#region 属性
|
||||||
@@ -74,8 +112,8 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
if (SetProperty(ref _selectedUser, value))
|
if (SetProperty(ref _selectedUser, value))
|
||||||
{
|
{
|
||||||
// 触发命令的 CanExecute 更新
|
// 触发命令的 CanExecute 更新
|
||||||
OnPropertyChanged(nameof(EditCommand));
|
(EditCommand as RelayCommand)?.RaiseCanExecuteChanged();
|
||||||
OnPropertyChanged(nameof(DeleteCommand));
|
(DeleteCommand as AsyncCommand)?.RaiseCanExecuteChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,6 +145,86 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
set => SetProperty(ref _recordCount, value);
|
set => SetProperty(ref _recordCount, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前页码
|
||||||
|
/// </summary>
|
||||||
|
public int CurrentPage
|
||||||
|
{
|
||||||
|
get => _currentPage;
|
||||||
|
set => SetProperty(ref _currentPage, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 每页大小
|
||||||
|
/// </summary>
|
||||||
|
public int PageSize
|
||||||
|
{
|
||||||
|
get => _pageSize;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _pageSize, value))
|
||||||
|
{
|
||||||
|
// 每页大小改变时,重置到第一页并重新加载
|
||||||
|
CurrentPage = 1;
|
||||||
|
_ = LoadPagedDataAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 总页数
|
||||||
|
/// </summary>
|
||||||
|
public int TotalPages
|
||||||
|
{
|
||||||
|
get => _totalPages;
|
||||||
|
set => SetProperty(ref _totalPages, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 总记录数
|
||||||
|
/// </summary>
|
||||||
|
public int TotalCount
|
||||||
|
{
|
||||||
|
get => _totalCount;
|
||||||
|
set => SetProperty(ref _totalCount, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 页码信息
|
||||||
|
/// </summary>
|
||||||
|
public string PageInfo
|
||||||
|
{
|
||||||
|
get => _pageInfo;
|
||||||
|
set => SetProperty(ref _pageInfo, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 总用户数
|
||||||
|
/// </summary>
|
||||||
|
public int TotalUsers
|
||||||
|
{
|
||||||
|
get => _totalUsers;
|
||||||
|
set => SetProperty(ref _totalUsers, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 活跃用户数
|
||||||
|
/// </summary>
|
||||||
|
public int ActiveUsers
|
||||||
|
{
|
||||||
|
get => _activeUsers;
|
||||||
|
set => SetProperty(ref _activeUsers, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 非活跃用户数
|
||||||
|
/// </summary>
|
||||||
|
public int InactiveUsers
|
||||||
|
{
|
||||||
|
get => _inactiveUsers;
|
||||||
|
set => SetProperty(ref _inactiveUsers, value);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 命令
|
#region 命令
|
||||||
@@ -119,14 +237,30 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
public ICommand DeleteCommand { get; }
|
public ICommand DeleteCommand { get; }
|
||||||
public ICommand RefreshCommand { get; }
|
public ICommand RefreshCommand { get; }
|
||||||
|
|
||||||
|
// 分页命令
|
||||||
|
public ICommand FirstPageCommand { get; }
|
||||||
|
public ICommand PreviousPageCommand { get; }
|
||||||
|
public ICommand NextPageCommand { get; }
|
||||||
|
public ICommand LastPageCommand { get; }
|
||||||
|
|
||||||
|
// 批量操作命令
|
||||||
|
public ICommand BatchAddCommand { get; }
|
||||||
|
public ICommand BatchDeleteCommand { get; }
|
||||||
|
|
||||||
|
// 统计命令
|
||||||
|
public ICommand RefreshStatsCommand { get; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region INavigationAware 实现
|
#region INavigationAware 实现
|
||||||
|
|
||||||
public async Task OnNavigatedToAsync(object? parameter)
|
public async Task OnNavigatedToAsync(object? parameter)
|
||||||
{
|
{
|
||||||
// 进入页面时加载数据
|
// 进入页面时加载数据和统计信息
|
||||||
await LoadDataAsync();
|
await Task.WhenAll(
|
||||||
|
LoadPagedDataAsync(),
|
||||||
|
RefreshStatsAsync()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task OnNavigatedFromAsync()
|
public Task OnNavigatedFromAsync()
|
||||||
@@ -139,40 +273,71 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
|
|
||||||
#region 私有方法
|
#region 私有方法
|
||||||
|
|
||||||
private async Task LoadDataAsync(string? searchText = null)
|
/// <summary>
|
||||||
|
/// 加载分页数据 - 演示 PagedResult 功能
|
||||||
|
/// </summary>
|
||||||
|
private async Task LoadPagedDataAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
StatusText = "正在加载数据...";
|
StatusText = "正在加载数据...";
|
||||||
_logger.LogInformation("开始加载用户数据,搜索条件: {SearchText}", searchText ?? "无");
|
_logger.LogInformation("开始加载用户数据,页码: {Page}, 每页: {PageSize}, 搜索: {SearchText}",
|
||||||
|
CurrentPage, PageSize, SearchText ?? "无");
|
||||||
|
|
||||||
var repo = _dataContext.Repository<User>();
|
var repo = _dataContext.Repository<User>();
|
||||||
|
|
||||||
List<User> users;
|
// 使用分页查询 - Data 模块的重要功能
|
||||||
if (string.IsNullOrWhiteSpace(searchText))
|
// 注意:软删除后需要手动过滤 IsDeleted=false 的记录
|
||||||
|
PagedResult<User> pagedResult;
|
||||||
|
if (string.IsNullOrWhiteSpace(SearchText))
|
||||||
{
|
{
|
||||||
users = await repo.GetAllAsync();
|
pagedResult = await repo.GetPagedAsync(
|
||||||
|
page: CurrentPage,
|
||||||
|
pageSize: PageSize,
|
||||||
|
predicate: u => !u.IsDeleted, // 过滤已删除的数据
|
||||||
|
orderBy: q => q.OrderByDescending(u => u.CreatedAt));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
users = await repo.FindAsync(u =>
|
var searchTerm = SearchText.Trim();
|
||||||
u.UserName.Contains(searchText) ||
|
pagedResult = await repo.GetPagedAsync(
|
||||||
u.Email.Contains(searchText) ||
|
page: CurrentPage,
|
||||||
(u.Remarks != null && u.Remarks.Contains(searchText)));
|
pageSize: PageSize,
|
||||||
|
predicate: u =>
|
||||||
|
!u.IsDeleted && // 过滤已删除的数据
|
||||||
|
(u.UserName.Contains(searchTerm) ||
|
||||||
|
u.Email.Contains(searchTerm) ||
|
||||||
|
(u.Remarks != null && u.Remarks.Contains(searchTerm))),
|
||||||
|
orderBy: q => q.OrderByDescending(u => u.CreatedAt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新UI数据
|
||||||
Users.Clear();
|
Users.Clear();
|
||||||
foreach (var user in users.OrderByDescending(u => u.CreatedAt))
|
foreach (var user in pagedResult.Items)
|
||||||
{
|
{
|
||||||
Users.Add(user);
|
Users.Add(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordCount = $"记录数: {users.Count}";
|
// 更新分页信息
|
||||||
StatusText = string.IsNullOrWhiteSpace(searchText)
|
TotalCount = pagedResult.TotalCount;
|
||||||
? $"加载完成,共 {users.Count} 条记录"
|
TotalPages = pagedResult.TotalPages;
|
||||||
: $"搜索完成,找到 {users.Count} 条记录";
|
CurrentPage = pagedResult.PageIndex;
|
||||||
|
PageSize = pagedResult.PageSize;
|
||||||
|
PageInfo = $"第 {CurrentPage}/{TotalPages} 页";
|
||||||
|
RecordCount = $"共 {TotalCount} 条记录,当前页 {Users.Count} 条";
|
||||||
|
|
||||||
_logger.LogInformation("加载完成,共 {Count} 条记录", users.Count);
|
StatusText = string.IsNullOrWhiteSpace(SearchText)
|
||||||
|
? $"加载完成 (第 {CurrentPage}/{TotalPages} 页)"
|
||||||
|
: $"搜索完成,找到 {TotalCount} 条记录 (第 {CurrentPage}/{TotalPages} 页)";
|
||||||
|
|
||||||
|
_logger.LogInformation("分页加载完成,总数: {Total}, 当前页: {Page}/{TotalPages}",
|
||||||
|
TotalCount, CurrentPage, TotalPages);
|
||||||
|
|
||||||
|
// 触发分页按钮的 CanExecute 更新
|
||||||
|
(FirstPageCommand as AsyncCommand)?.RaiseCanExecuteChanged();
|
||||||
|
(PreviousPageCommand as AsyncCommand)?.RaiseCanExecuteChanged();
|
||||||
|
(NextPageCommand as AsyncCommand)?.RaiseCanExecuteChanged();
|
||||||
|
(LastPageCommand as AsyncCommand)?.RaiseCanExecuteChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -182,11 +347,34 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 刷新统计信息 - 演示 Count 和 Any 功能
|
||||||
|
/// </summary>
|
||||||
|
private async Task RefreshStatsAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var repo = _dataContext.Repository<User>();
|
||||||
|
|
||||||
|
// 使用 Count 和条件查询(过滤已删除的数据)
|
||||||
|
TotalUsers = await repo.CountAsync(u => !u.IsDeleted);
|
||||||
|
ActiveUsers = await repo.CountAsync(u => !u.IsDeleted && u.IsActive);
|
||||||
|
InactiveUsers = await repo.CountAsync(u => !u.IsDeleted && !u.IsActive);
|
||||||
|
|
||||||
|
_logger.LogInformation("统计信息已刷新 - 总数: {Total}, 活跃: {Active}, 非活跃: {Inactive}",
|
||||||
|
TotalUsers, ActiveUsers, InactiveUsers);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "刷新统计信息失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Add()
|
private void Add()
|
||||||
{
|
{
|
||||||
var dialog = new UserEditDialog
|
var dialog = new UserEditDialog
|
||||||
{
|
{
|
||||||
Owner = Application.Current.MainWindow
|
Owner = CurrentWindow ?? Application.Current.MainWindow
|
||||||
};
|
};
|
||||||
|
|
||||||
if (dialog.ShowDialog() == true)
|
if (dialog.ShowDialog() == true)
|
||||||
@@ -205,7 +393,7 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
|
|
||||||
var dialog = new UserEditDialog(SelectedUser)
|
var dialog = new UserEditDialog(SelectedUser)
|
||||||
{
|
{
|
||||||
Owner = Application.Current.MainWindow
|
Owner = CurrentWindow ?? Application.Current.MainWindow
|
||||||
};
|
};
|
||||||
|
|
||||||
if (dialog.ShowDialog() == true)
|
if (dialog.ShowDialog() == true)
|
||||||
@@ -246,7 +434,7 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
_logger.LogInformation("用户新增成功: {UserId}", user.Id);
|
_logger.LogInformation("用户新增成功: {UserId}", user.Id);
|
||||||
await _dialogService.ShowInfoAsync("用户新增成功!", "成功");
|
await _dialogService.ShowInfoAsync("用户新增成功!", "成功");
|
||||||
|
|
||||||
await LoadDataAsync();
|
await Task.WhenAll(LoadPagedDataAsync(), RefreshStatsAsync());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -270,7 +458,7 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
_logger.LogInformation("用户更新成功: {UserId}", user.Id);
|
_logger.LogInformation("用户更新成功: {UserId}", user.Id);
|
||||||
await _dialogService.ShowInfoAsync("用户更新成功!", "成功");
|
await _dialogService.ShowInfoAsync("用户更新成功!", "成功");
|
||||||
|
|
||||||
await LoadDataAsync();
|
await Task.WhenAll(LoadPagedDataAsync(), RefreshStatsAsync());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -294,7 +482,7 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
_logger.LogInformation("用户软删除成功: {UserId}", userId);
|
_logger.LogInformation("用户软删除成功: {UserId}", userId);
|
||||||
await _dialogService.ShowInfoAsync("用户已标记为删除(软删除)!", "成功");
|
await _dialogService.ShowInfoAsync("用户已标记为删除(软删除)!", "成功");
|
||||||
|
|
||||||
await LoadDataAsync();
|
await Task.WhenAll(LoadPagedDataAsync(), RefreshStatsAsync());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -304,6 +492,111 @@ namespace Sharp.Demo.ViewModels.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 批量添加用户 - 演示 AddRangeAsync 功能
|
||||||
|
/// </summary>
|
||||||
|
private async Task BatchAddAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var confirmed = await _dialogService.ShowConfirmAsync(
|
||||||
|
"将批量添加 10 个测试用户,确定要继续吗?\n\n这将演示 Sharp.Data 的 AddRangeAsync 批量操作功能。",
|
||||||
|
"批量添加");
|
||||||
|
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
|
StatusText = "正在批量添加...";
|
||||||
|
_logger.LogInformation("开始批量添加测试用户");
|
||||||
|
|
||||||
|
// 生成测试数据
|
||||||
|
var testUsers = new List<User>();
|
||||||
|
for (int i = 1; i <= 10; i++)
|
||||||
|
{
|
||||||
|
testUsers.Add(new User
|
||||||
|
{
|
||||||
|
UserName = $"testuser{DateTime.Now:yyyyMMddHHmmss}_{i}",
|
||||||
|
Email = $"test{DateTime.Now:yyyyMMddHHmmss}_{i}@example.com",
|
||||||
|
Age = 20 + (i % 30),
|
||||||
|
IsActive = i % 2 == 0,
|
||||||
|
Remarks = $"批量导入的测试用户 {i}"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用批量添加 - Data 模块的批量操作功能
|
||||||
|
var repo = _dataContext.Repository<User>();
|
||||||
|
await repo.AddRangeAsync(testUsers);
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
_logger.LogInformation("批量添加成功,共添加 {Count} 个用户", testUsers.Count);
|
||||||
|
await _dialogService.ShowInfoAsync($"批量添加成功!共添加 {testUsers.Count} 个用户。", "成功");
|
||||||
|
|
||||||
|
await Task.WhenAll(LoadPagedDataAsync(), RefreshStatsAsync());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "批量添加失败");
|
||||||
|
StatusText = "批量添加失败";
|
||||||
|
await _dialogService.ShowErrorAsync($"批量添加失败: {ex.Message}", "错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 批量删除用户 - 演示事务处理和批量删除
|
||||||
|
/// </summary>
|
||||||
|
private async Task BatchDeleteAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!Users.Any())
|
||||||
|
{
|
||||||
|
await _dialogService.ShowInfoAsync("当前页没有可删除的数据", "提示");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var confirmed = await _dialogService.ShowConfirmAsync(
|
||||||
|
$"将删除当前页所有 {Users.Count} 个用户(软删除),确定要继续吗?\n\n这将演示 Sharp.Data 的事务处理功能。",
|
||||||
|
"批量删除");
|
||||||
|
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
|
StatusText = "正在批量删除...";
|
||||||
|
_logger.LogInformation("开始批量删除,数量: {Count}", Users.Count);
|
||||||
|
|
||||||
|
var repo = _dataContext.Repository<User>();
|
||||||
|
|
||||||
|
// 使用事务确保原子性
|
||||||
|
using var transaction = await _dataContext.Context.Database.BeginTransactionAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 批量软删除
|
||||||
|
var userIds = Users.Select(u => u.Id).ToList();
|
||||||
|
foreach (var userId in userIds)
|
||||||
|
{
|
||||||
|
await repo.RemoveAsync(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
await transaction.CommitAsync();
|
||||||
|
|
||||||
|
_logger.LogInformation("批量删除成功,共删除 {Count} 个用户", userIds.Count);
|
||||||
|
await _dialogService.ShowInfoAsync($"批量删除成功!共删除 {userIds.Count} 个用户。", "成功");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await transaction.RollbackAsync();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.WhenAll(LoadPagedDataAsync(), RefreshStatsAsync());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "批量删除失败");
|
||||||
|
StatusText = "批量删除失败";
|
||||||
|
await _dialogService.ShowErrorAsync($"批量删除失败: {ex.Message}", "错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,6 +31,37 @@
|
|||||||
Text="Sharp.Data - EF Core + Repository + 审计追踪 + 软删除"
|
Text="Sharp.Data - EF Core + Repository + 审计追踪 + 软删除"
|
||||||
Margin="0,0,0,20" />
|
Margin="0,0,0,20" />
|
||||||
|
|
||||||
|
<!-- 统计信息栏 -->
|
||||||
|
<Border
|
||||||
|
Grid.Row="2"
|
||||||
|
Background="{DynamicResource InfoBrush}"
|
||||||
|
BorderBrush="{DynamicResource BorderBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="15"
|
||||||
|
Margin="0,0,0,10">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock FontWeight="Bold" FontSize="14" Margin="0,0,20,0">
|
||||||
|
<Run Text="📊 数据统计"/>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock FontSize="13" Margin="0,0,15,0">
|
||||||
|
<Run Text="总用户数: "/>
|
||||||
|
<Run Text="{Binding TotalUsers}" FontWeight="Bold" Foreground="{DynamicResource PrimaryBrush}"/>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock FontSize="13" Margin="0,0,15,0">
|
||||||
|
<Run Text="活跃: "/>
|
||||||
|
<Run Text="{Binding ActiveUsers}" FontWeight="Bold" Foreground="#27AE60"/>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock FontSize="13" Margin="0,0,15,0">
|
||||||
|
<Run Text="非活跃: "/>
|
||||||
|
<Run Text="{Binding InactiveUsers}" FontWeight="Bold" Foreground="#95A5A6"/>
|
||||||
|
</TextBlock>
|
||||||
|
<Button Content="刷新统计" Width="90" Height="28" Margin="10,0,0,0"
|
||||||
|
Command="{Binding RefreshStatsCommand}"
|
||||||
|
Style="{StaticResource ButtonInfo}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<!-- 搜索和操作栏 -->
|
<!-- 搜索和操作栏 -->
|
||||||
<Border
|
<Border
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
@@ -39,46 +70,67 @@
|
|||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CornerRadius="8"
|
CornerRadius="8"
|
||||||
Padding="15"
|
Padding="15"
|
||||||
Margin="0,0,0,15">
|
Margin="0,45,0,15">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
</Grid.RowDefinitions>
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<!-- 搜索框 -->
|
<!-- 第一行:搜索和单条操作 -->
|
||||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0,0,15,0">
|
<Grid Grid.Row="0">
|
||||||
<TextBlock Text="搜索:" VerticalAlignment="Center" Margin="0,0,10,0"/>
|
<Grid.ColumnDefinitions>
|
||||||
<TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"
|
<ColumnDefinition Width="Auto"/>
|
||||||
Width="250" Height="32" VerticalContentAlignment="Center"
|
<ColumnDefinition Width="*"/>
|
||||||
Padding="8,0" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<Button Content="搜索" Width="80" Height="32" Margin="10,0,0,0"
|
</Grid.ColumnDefinitions>
|
||||||
Command="{Binding SearchCommand}"
|
|
||||||
Style="{StaticResource ButtonPrimary}"/>
|
|
||||||
<Button Content="清空" Width="80" Height="32" Margin="5,0,0,0"
|
|
||||||
Command="{Binding ClearSearchCommand}"
|
|
||||||
Style="{StaticResource ButtonDefault}"/>
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<!-- 状态信息 -->
|
<!-- 搜索框 -->
|
||||||
<TextBlock Grid.Column="1" Text="{Binding StatusText}" VerticalAlignment="Center"
|
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0,0,15,0">
|
||||||
Foreground="{DynamicResource SecondaryTextBrush}" Margin="15,0"/>
|
<TextBlock Text="搜索:" VerticalAlignment="Center" Margin="0,0,10,0"/>
|
||||||
|
<TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
Width="250" Height="32" VerticalContentAlignment="Center"
|
||||||
|
Padding="8,0" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1"/>
|
||||||
|
<Button Content="搜索" Width="80" Height="32" Margin="10,0,0,0"
|
||||||
|
Command="{Binding SearchCommand}"
|
||||||
|
Style="{StaticResource ButtonPrimary}"/>
|
||||||
|
<Button Content="清空" Width="80" Height="32" Margin="5,0,0,0"
|
||||||
|
Command="{Binding ClearSearchCommand}"
|
||||||
|
Style="{StaticResource ButtonDefault}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<!-- 操作按钮 -->
|
<!-- 状态信息 -->
|
||||||
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
<TextBlock Grid.Column="1" Text="{Binding StatusText}" VerticalAlignment="Center"
|
||||||
<Button Content="新增" Width="90" Height="32" Margin="0,0,5,0"
|
Foreground="{DynamicResource SecondaryTextBrush}" Margin="15,0"/>
|
||||||
Command="{Binding AddCommand}"
|
|
||||||
|
<!-- 单条操作按钮 -->
|
||||||
|
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
||||||
|
<Button Content="新增" Width="90" Height="32" Margin="0,0,5,0"
|
||||||
|
Command="{Binding AddCommand}"
|
||||||
|
Style="{StaticResource ButtonSuccess}"/>
|
||||||
|
<Button Content="编辑" Width="90" Height="32" Margin="0,0,5,0"
|
||||||
|
Command="{Binding EditCommand}"
|
||||||
|
Style="{StaticResource ButtonWarning}"/>
|
||||||
|
<Button Content="删除" Width="90" Height="32"
|
||||||
|
Command="{Binding DeleteCommand}"
|
||||||
|
Style="{StaticResource ButtonDanger}"/>
|
||||||
|
<Button Content="刷新" Width="90" Height="32" Margin="5,0,0,0"
|
||||||
|
Command="{Binding RefreshCommand}"
|
||||||
|
Style="{StaticResource ButtonInfo}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- 第二行:批量操作 -->
|
||||||
|
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,10,0,0">
|
||||||
|
<TextBlock Text="批量操作:" VerticalAlignment="Center" FontWeight="Bold" Margin="0,0,10,0"/>
|
||||||
|
<Button Content="批量添加测试数据" Width="140" Height="32" Margin="0,0,5,0"
|
||||||
|
Command="{Binding BatchAddCommand}"
|
||||||
Style="{StaticResource ButtonSuccess}"/>
|
Style="{StaticResource ButtonSuccess}"/>
|
||||||
<Button Content="编辑" Width="90" Height="32" Margin="0,0,5,0"
|
<Button Content="批量删除当前页" Width="140" Height="32" Margin="0,0,5,0"
|
||||||
Command="{Binding EditCommand}"
|
Command="{Binding BatchDeleteCommand}"
|
||||||
Style="{StaticResource ButtonWarning}"/>
|
|
||||||
<Button Content="删除" Width="90" Height="32"
|
|
||||||
Command="{Binding DeleteCommand}"
|
|
||||||
Style="{StaticResource ButtonDanger}"/>
|
Style="{StaticResource ButtonDanger}"/>
|
||||||
<Button Content="刷新" Width="90" Height="32" Margin="5,0,0,0"
|
<TextBlock Text="(演示 AddRangeAsync 和事务处理)" VerticalAlignment="Center"
|
||||||
Command="{Binding RefreshCommand}"
|
FontSize="11" Foreground="{DynamicResource SecondaryTextBrush}" Margin="10,0,0,0"/>
|
||||||
Style="{StaticResource ButtonInfo}"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
@@ -126,6 +178,67 @@
|
|||||||
</DataGrid>
|
</DataGrid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<!-- 分页控件 -->
|
||||||
|
<Border
|
||||||
|
Grid.Row="4"
|
||||||
|
Background="{DynamicResource RegionBrush}"
|
||||||
|
BorderBrush="{DynamicResource BorderBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="15"
|
||||||
|
Margin="0,0,0,10">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- 左侧:记录信息 -->
|
||||||
|
<TextBlock Grid.Column="0" VerticalAlignment="Center" FontSize="13">
|
||||||
|
<Run Text="{Binding RecordCount}"/>
|
||||||
|
<Run Text=" | "/>
|
||||||
|
<Run Text="{Binding PageInfo}"/>
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<!-- 中间:页码信息 -->
|
||||||
|
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
|
<TextBlock Text="每页显示: " VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||||
|
<ComboBox SelectedItem="{Binding PageSize}" Width="80" Height="28">
|
||||||
|
<sys:Int32 xmlns:sys="clr-namespace:System;assembly=mscorlib">5</sys:Int32>
|
||||||
|
<sys:Int32 xmlns:sys="clr-namespace:System;assembly=mscorlib">10</sys:Int32>
|
||||||
|
<sys:Int32 xmlns:sys="clr-namespace:System;assembly=mscorlib">20</sys:Int32>
|
||||||
|
<sys:Int32 xmlns:sys="clr-namespace:System;assembly=mscorlib">50</sys:Int32>
|
||||||
|
<sys:Int32 xmlns:sys="clr-namespace:System;assembly=mscorlib">100</sys:Int32>
|
||||||
|
</ComboBox>
|
||||||
|
<TextBlock Text=" 条" VerticalAlignment="Center" Margin="5,0,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- 右侧:分页按钮 -->
|
||||||
|
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
||||||
|
<Button Content="首页" Width="60" Height="28" Margin="0,0,5,0"
|
||||||
|
Command="{Binding FirstPageCommand}"
|
||||||
|
Style="{StaticResource ButtonDefault}"/>
|
||||||
|
<Button Content="上一页" Width="70" Height="28" Margin="0,0,5,0"
|
||||||
|
Command="{Binding PreviousPageCommand}"
|
||||||
|
Style="{StaticResource ButtonDefault}"/>
|
||||||
|
<TextBlock VerticalAlignment="Center" Margin="10,0">
|
||||||
|
<Run Text="第 "/>
|
||||||
|
<Run Text="{Binding CurrentPage}" FontWeight="Bold" Foreground="{DynamicResource PrimaryBrush}"/>
|
||||||
|
<Run Text=" / "/>
|
||||||
|
<Run Text="{Binding TotalPages}" FontWeight="Bold"/>
|
||||||
|
<Run Text=" 页"/>
|
||||||
|
</TextBlock>
|
||||||
|
<Button Content="下一页" Width="70" Height="28" Margin="5,0,5,0"
|
||||||
|
Command="{Binding NextPageCommand}"
|
||||||
|
Style="{StaticResource ButtonDefault}"/>
|
||||||
|
<Button Content="末页" Width="60" Height="28"
|
||||||
|
Command="{Binding LastPageCommand}"
|
||||||
|
Style="{StaticResource ButtonDefault}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<!-- 底部信息栏 -->
|
<!-- 底部信息栏 -->
|
||||||
<Border
|
<Border
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
@@ -133,7 +246,8 @@
|
|||||||
BorderBrush="{DynamicResource BorderBrush}"
|
BorderBrush="{DynamicResource BorderBrush}"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CornerRadius="8"
|
CornerRadius="8"
|
||||||
Padding="15">
|
Padding="15"
|
||||||
|
Margin="0,55,0,0">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
@@ -145,17 +259,24 @@
|
|||||||
<Run Text="💡 功能说明"/>
|
<Run Text="💡 功能说明"/>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<TextBlock FontSize="11" TextWrapping="Wrap">
|
<TextBlock FontSize="11" TextWrapping="Wrap">
|
||||||
<Run Text="• 本示例展示 Sharp.Data 模块的使用:SQLite 数据库、仓储模式、自动审计、软删除"/>
|
<Run Text="• 完整演示 Sharp.Data 模块功能:SQLite + Repository + 分页 + 批量操作 + 审计追踪 + 软删除 + 事务处理"/>
|
||||||
<LineBreak/>
|
<LineBreak/>
|
||||||
<Run Text="• 删除操作使用软删除(IsDeleted=true),数据不会真正删除"/>
|
<Run Text="• 分页查询:使用 GetPagedAsync 方法,返回 PagedResult<T> 分页结果"/>
|
||||||
<LineBreak/>
|
<LineBreak/>
|
||||||
<Run Text="• 创建/修改时间和操作人由 Data 模块自动记录"/>
|
<Run Text="• 批量操作:AddRangeAsync 批量添加,事务确保批量删除的原子性"/>
|
||||||
|
<LineBreak/>
|
||||||
|
<Run Text="• 审计追踪:CreatedAt/UpdatedAt/CreatedBy/UpdatedBy 由框架自动管理"/>
|
||||||
|
<LineBreak/>
|
||||||
|
<Run Text="• 软删除:RemoveAsync 标记 IsDeleted=true,数据不会物理删除"/>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||||
<TextBlock Text="数据库: SQLite (demo.db)" FontSize="11" FontWeight="Bold"/>
|
<TextBlock Text="数据库: SQLite (demo.db)" FontSize="11" FontWeight="Bold"/>
|
||||||
<TextBlock Text="{Binding RecordCount}" FontSize="11"/>
|
<TextBlock FontSize="11">
|
||||||
|
<Run Text="总用户数: "/>
|
||||||
|
<Run Text="{Binding TotalUsers}" FontWeight="Bold"/>
|
||||||
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
<Window x:Class="Sharp.Demo.Views.Windows.DatabaseWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
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"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="数据库管理 - Sharp.Data 演示"
|
||||||
|
Height="800"
|
||||||
|
Width="1200"
|
||||||
|
WindowStartupLocation="CenterScreen">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- 工具栏 -->
|
||||||
|
<Border Grid.Row="0" Background="{DynamicResource RegionBrush}"
|
||||||
|
BorderBrush="{DynamicResource BorderBrush}" BorderThickness="0,0,0,1" Padding="15,10">
|
||||||
|
<Grid>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Text="📊 数据库管理" FontSize="18" FontWeight="Bold" VerticalAlignment="Center" Margin="0,0,20,0"/>
|
||||||
|
<Separator Margin="0,0,10,0"/>
|
||||||
|
<Button Content="➕ 新增" Width="90" Height="32" Margin="0,0,5,0"
|
||||||
|
Command="{Binding AddCommand}"
|
||||||
|
Style="{StaticResource ButtonSuccess}"/>
|
||||||
|
<Button Content="✏️ 编辑" Width="90" Height="32" Margin="0,0,5,0"
|
||||||
|
Command="{Binding EditCommand}"
|
||||||
|
Style="{StaticResource ButtonWarning}"/>
|
||||||
|
<Button Content="🗑 删除" Width="90" Height="32" Margin="0,0,5,0"
|
||||||
|
Command="{Binding DeleteCommand}"
|
||||||
|
Style="{StaticResource ButtonDanger}"/>
|
||||||
|
<Button Content="🔄 刷新" Width="90" Height="32"
|
||||||
|
Command="{Binding RefreshCommand}"
|
||||||
|
Style="{StaticResource ButtonInfo}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
|
<TextBlock Text="{Binding StatusText}" VerticalAlignment="Center" Margin="0,0,15,0"
|
||||||
|
Foreground="{DynamicResource SecondaryTextBrush}"/>
|
||||||
|
<TextBlock Text="{Binding RecordCount}" FontWeight="Bold" VerticalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 主内容区 -->
|
||||||
|
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
|
||||||
|
<Grid Margin="20">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- 统计信息栏 -->
|
||||||
|
<Border Grid.Row="0"
|
||||||
|
Background="{DynamicResource InfoBrush}"
|
||||||
|
BorderBrush="{DynamicResource BorderBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="15"
|
||||||
|
Margin="0,0,0,10">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock FontWeight="Bold" FontSize="14" Margin="0,0,20,0">
|
||||||
|
<Run Text="📊 数据统计"/>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock FontSize="13" Margin="0,0,15,0">
|
||||||
|
<Run Text="总用户数: "/>
|
||||||
|
<Run Text="{Binding TotalUsers}" FontWeight="Bold" Foreground="{DynamicResource PrimaryBrush}"/>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock FontSize="13" Margin="0,0,15,0">
|
||||||
|
<Run Text="活跃: "/>
|
||||||
|
<Run Text="{Binding ActiveUsers}" FontWeight="Bold" Foreground="#27AE60"/>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock FontSize="13" Margin="0,0,15,0">
|
||||||
|
<Run Text="非活跃: "/>
|
||||||
|
<Run Text="{Binding InactiveUsers}" FontWeight="Bold" Foreground="#95A5A6"/>
|
||||||
|
</TextBlock>
|
||||||
|
<Button Content="刷新统计" Width="90" Height="28" Margin="10,0,0,0"
|
||||||
|
Command="{Binding RefreshStatsCommand}"
|
||||||
|
Style="{StaticResource ButtonInfo}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 搜索和操作栏 -->
|
||||||
|
<Border Grid.Row="1"
|
||||||
|
Background="{DynamicResource RegionBrush}"
|
||||||
|
BorderBrush="{DynamicResource BorderBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="15"
|
||||||
|
Margin="0,0,0,15">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<StackPanel Grid.Row="0" Orientation="Horizontal">
|
||||||
|
<TextBlock Text="搜索:" VerticalAlignment="Center" Margin="0,0,10,0"/>
|
||||||
|
<TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
Width="300" Height="32" VerticalContentAlignment="Center"
|
||||||
|
Padding="8,0" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1"/>
|
||||||
|
<Button Content="搜索" Width="80" Height="32" Margin="10,0,0,0"
|
||||||
|
Command="{Binding SearchCommand}"
|
||||||
|
Style="{StaticResource ButtonPrimary}"/>
|
||||||
|
<Button Content="清空" Width="80" Height="32" Margin="5,0,0,0"
|
||||||
|
Command="{Binding ClearSearchCommand}"
|
||||||
|
Style="{StaticResource ButtonDefault}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- 批量操作 -->
|
||||||
|
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,10,0,0">
|
||||||
|
<TextBlock Text="批量操作:" VerticalAlignment="Center" FontWeight="Bold" Margin="0,0,10,0"/>
|
||||||
|
<Button Content="批量添加测试数据" Width="140" Height="32" Margin="0,0,5,0"
|
||||||
|
Command="{Binding BatchAddCommand}"
|
||||||
|
Style="{StaticResource ButtonSuccess}"/>
|
||||||
|
<Button Content="批量删除当前页" Width="140" Height="32" Margin="0,0,5,0"
|
||||||
|
Command="{Binding BatchDeleteCommand}"
|
||||||
|
Style="{StaticResource ButtonDanger}"/>
|
||||||
|
<TextBlock Text="(演示 AddRangeAsync 和事务处理)" VerticalAlignment="Center"
|
||||||
|
FontSize="11" Foreground="{DynamicResource SecondaryTextBrush}" Margin="10,0,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 数据列表 -->
|
||||||
|
<Border Grid.Row="3"
|
||||||
|
Background="{DynamicResource RegionBrush}"
|
||||||
|
BorderBrush="{DynamicResource BorderBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="10"
|
||||||
|
Margin="0,0,0,15"
|
||||||
|
Height="450">
|
||||||
|
<DataGrid ItemsSource="{Binding Users}"
|
||||||
|
SelectedItem="{Binding SelectedUser}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
IsReadOnly="True"
|
||||||
|
SelectionMode="Single"
|
||||||
|
GridLinesVisibility="None"
|
||||||
|
HeadersVisibility="Column"
|
||||||
|
AlternationCount="2"
|
||||||
|
RowHeight="40"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
CanUserDeleteRows="False"
|
||||||
|
VerticalScrollBarVisibility="Disabled"
|
||||||
|
HorizontalScrollBarVisibility="Auto">
|
||||||
|
<DataGrid.Resources>
|
||||||
|
<Style TargetType="DataGridRow">
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SecondaryRegionBrush}" />
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</DataGrid.Resources>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="ID" Binding="{Binding Id}" Width="80" Visibility="Collapsed"/>
|
||||||
|
<DataGridTextColumn Header="用户名" Binding="{Binding UserName}" Width="150"/>
|
||||||
|
<DataGridTextColumn Header="邮箱" Binding="{Binding Email}" Width="220"/>
|
||||||
|
<DataGridTextColumn Header="年龄" Binding="{Binding Age}" Width="80"/>
|
||||||
|
<DataGridCheckBoxColumn Header="激活" Binding="{Binding IsActive}" Width="80"/>
|
||||||
|
<DataGridTextColumn Header="备注" Binding="{Binding Remarks}" Width="*"/>
|
||||||
|
<DataGridTextColumn Header="创建时间" Binding="{Binding CreatedAt, StringFormat={}{0:yyyy-MM-dd HH:mm}}" Width="150"/>
|
||||||
|
<DataGridTextColumn Header="创建人" Binding="{Binding CreatedBy}" Width="100"/>
|
||||||
|
<DataGridTextColumn Header="修改时间" Binding="{Binding UpdatedAt, StringFormat={}{0:yyyy-MM-dd HH:mm}}" Width="150"/>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 分页控件 -->
|
||||||
|
<Border Grid.Row="4"
|
||||||
|
Background="{DynamicResource RegionBrush}"
|
||||||
|
BorderBrush="{DynamicResource BorderBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="15"
|
||||||
|
Margin="0,0,0,10">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- 左侧:记录信息 -->
|
||||||
|
<TextBlock Grid.Column="0" VerticalAlignment="Center" FontSize="13">
|
||||||
|
<Run Text="{Binding RecordCount}"/>
|
||||||
|
<Run Text=" | "/>
|
||||||
|
<Run Text="{Binding PageInfo}"/>
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<!-- 中间:页码信息 -->
|
||||||
|
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
|
<TextBlock Text="每页显示: " VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||||
|
<ComboBox SelectedItem="{Binding PageSize}" Width="80" Height="28">
|
||||||
|
<sys:Int32 xmlns:sys="clr-namespace:System;assembly=mscorlib">5</sys:Int32>
|
||||||
|
<sys:Int32 xmlns:sys="clr-namespace:System;assembly=mscorlib">10</sys:Int32>
|
||||||
|
<sys:Int32 xmlns:sys="clr-namespace:System;assembly=mscorlib">20</sys:Int32>
|
||||||
|
<sys:Int32 xmlns:sys="clr-namespace:System;assembly=mscorlib">50</sys:Int32>
|
||||||
|
<sys:Int32 xmlns:sys="clr-namespace:System;assembly=mscorlib">100</sys:Int32>
|
||||||
|
</ComboBox>
|
||||||
|
<TextBlock Text=" 条" VerticalAlignment="Center" Margin="5,0,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- 右侧:分页按钮 -->
|
||||||
|
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
||||||
|
<Button Content="首页" Width="60" Height="28" Margin="0,0,5,0"
|
||||||
|
Command="{Binding FirstPageCommand}"
|
||||||
|
Style="{StaticResource ButtonDefault}"/>
|
||||||
|
<Button Content="上一页" Width="70" Height="28" Margin="0,0,5,0"
|
||||||
|
Command="{Binding PreviousPageCommand}"
|
||||||
|
Style="{StaticResource ButtonDefault}"/>
|
||||||
|
<TextBlock VerticalAlignment="Center" Margin="10,0">
|
||||||
|
<Run Text="第 "/>
|
||||||
|
<Run Text="{Binding CurrentPage}" FontWeight="Bold" Foreground="{DynamicResource PrimaryBrush}"/>
|
||||||
|
<Run Text=" / "/>
|
||||||
|
<Run Text="{Binding TotalPages}" FontWeight="Bold"/>
|
||||||
|
<Run Text=" 页"/>
|
||||||
|
</TextBlock>
|
||||||
|
<Button Content="下一页" Width="70" Height="28" Margin="5,0,5,0"
|
||||||
|
Command="{Binding NextPageCommand}"
|
||||||
|
Style="{StaticResource ButtonDefault}"/>
|
||||||
|
<Button Content="末页" Width="60" Height="28"
|
||||||
|
Command="{Binding LastPageCommand}"
|
||||||
|
Style="{StaticResource ButtonDefault}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 底部信息栏 -->
|
||||||
|
<Border Grid.Row="5"
|
||||||
|
Background="{DynamicResource SecondaryRegionBrush}"
|
||||||
|
BorderBrush="{DynamicResource BorderBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="15">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="0">
|
||||||
|
<TextBlock FontWeight="Bold" Margin="0,0,0,5">
|
||||||
|
<Run Text="💡 功能说明"/>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock FontSize="11" TextWrapping="Wrap">
|
||||||
|
<Run Text="• 完整演示 Sharp.Data 模块功能:SQLite + Repository + 分页 + 批量操作 + 审计追踪 + 软删除 + 事务处理"/>
|
||||||
|
<LineBreak/>
|
||||||
|
<Run Text="• 分页查询:使用 GetPagedAsync 方法,返回 PagedResult<T> 分页结果"/>
|
||||||
|
<LineBreak/>
|
||||||
|
<Run Text="• 批量操作:AddRangeAsync 批量添加,事务确保批量删除的原子性"/>
|
||||||
|
<LineBreak/>
|
||||||
|
<Run Text="• 审计追踪:CreatedAt/UpdatedAt/CreatedBy/UpdatedBy 由框架自动管理"/>
|
||||||
|
<LineBreak/>
|
||||||
|
<Run Text="• 软删除:RemoveAsync 标记 IsDeleted=true,数据不会物理删除"/>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||||
|
<TextBlock Text="数据库: SQLite (demo.db)" FontSize="11" FontWeight="Bold"/>
|
||||||
|
<TextBlock FontSize="11">
|
||||||
|
<Run Text="总用户数: "/>
|
||||||
|
<Run Text="{Binding TotalUsers}" FontWeight="Bold"/>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using Sharp.Demo.ViewModels.Pages;
|
||||||
|
|
||||||
|
namespace Sharp.Demo.Views.Windows
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DatabaseWindow.xaml 的交互逻辑
|
||||||
|
/// 数据库管理独立窗口 - 演示 Sharp.Data 模块的完整功能
|
||||||
|
/// </summary>
|
||||||
|
public partial class DatabaseWindow : Window
|
||||||
|
{
|
||||||
|
public DatabaseWindow(DatabaseViewModel viewModel)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = viewModel;
|
||||||
|
|
||||||
|
// 设置当前窗口引用(用于对话框父窗口)
|
||||||
|
viewModel.CurrentWindow = this;
|
||||||
|
|
||||||
|
// 窗口加载完成后加载数据
|
||||||
|
Loaded += async (s, e) =>
|
||||||
|
{
|
||||||
|
await viewModel.OnNavigatedToAsync(null);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user