winform+api是一种对接数据模式,在本例中,为了方便,开发两个天生具有与后台api对接的用例控件,并且把他们封闭成单独控件,以供多次使用。
提示:此实例不是生产使用,仅作演示,有不完善地方,重点关注流程和自定义控件。
本例为API Server,用户控件项目,使用控件项目。
API Server端:
api端主要是根据提交上来的请求,组装成一个sql,查询一个内存sqlite数据库(请注意这里没有做sql注入处理)
using Dapper; using Microsoft.Data.Sqlite; using System.Data; using System.Data.Common; using System.Net; using System.Text; using System.Text.Encodings.Web; using System.Text.Unicode; using System.Web; var builder = WebApplication.CreateBuilder(args); var connection = new SqliteConnection("Data Source=InMemorySample;Mode=Memory;Cache=Shared"); await InitDataAsync(); async Task InitDataAsync() { await connection.OpenAsync(); await connection.ExecuteAsync("create table type(ID INTEGER primary key,Name text,Category INTEGER);"); await connection.ExecuteAsync("insert into main.type(ID,Name,Category) values(1,'AliPay',1),(2,'MiroPay',1),(3,'PayPay',2);"); await connection.ExecuteAsync("create table [order](ID INTEGER primary key,Name text,Price real,Quantity integer);"); await connection.ExecuteAsync("insert into [order](ID,Name,Price,Quantity) values(1,'产品A',21.15,12),(2,'产品B',32.45,23),(3,'产品C',43.45,23);"); } builder.Services.AddSingleton<IDbConnection>(connection); builder.Services.AddResponseCaching(); builder.Services.AddSingleton<IParameService, ParameService>(); var app = builder.Build(); app.UseResponseCaching(); app.Use(async (context, next) => { context.Response.GetTypedHeaders().CacheControl = new Microsoft.Net.Http.Headers.CacheControlHeaderValue() { Public = true, MaxAge = TimeSpan.FromHours(1) }; context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] = new string[] { "Accept-Encoding" }; await next(); }); app.MapGet("/parame/{dataSource}", async (IParameService parameService, string dataSource, string fields, string conditions) => { var list = await parameService.GetParamesAsync(dataSource, fields, conditions); return TypedResults.Json(list, new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = false }); }); app.Run(); public interface IParameService { Task<IEnumerable<dynamic>> GetParamesAsync(string dataSource, string fields, string conditions); } public class ParameService : IParameService { private readonly ILogger<ParameService> _logger; private readonly IDbConnection _db; public ParameService(ILogger<ParameService> logger, IDbConnection db) { _logger = logger; _db = db; } public async Task<IEnumerable<dynamic>> GetParamesAsync(string dataSource, string fields, string conditions) { var sql = $"select {fields} from [{dataSource}]"; if (conditions != null && conditions.Length > 0) { var whereBuilder = new StringBuilder(" where "); var conditionArr = conditions.Split(new string[] { "(", "),(", ")" }, StringSplitOptions.RemoveEmptyEntries); foreach (var condition in conditionArr) { var arr = condition.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries); whereBuilder.Append($" {arr[0]} {arr[1]} '{arr[2]}' and"); } sql += whereBuilder.ToString().Substring(0, whereBuilder.Length - 3); } _logger.LogInformation(sql); return await _db.QueryAsync<dynamic>(sql); } }
用户控件端:
用户控件有一个公共部分,分别处理两类控件ListControl和DataGridView控件,思路都是从控件上拿到相应的属性数据,然后组装http请求,取回数据,绑定到控件上。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing.Design; using System.Linq; using System.Net.Http; using System.Security.Policy; using System.Text; using System.Text.Json; using System.Threading.Tasks; using System.Web; namespace GSWControls { public static class ControlExpand { static HttpClient _httpClient = new HttpClient(); public static async Task DBControlInit(this ListControl control, string url, string dataSourceName, List<DBCondition>? conditions) { if (!control.IsAncestorSiteInDesignMode) { if (!string.IsNullOrWhiteSpace(url) && !string.IsNullOrWhiteSpace(dataSourceName) && !string.IsNullOrWhiteSpace(control.DisplayMember) && !string.IsNullOrWhiteSpace(control.ValueMember)) { url = $"{url.TrimEnd('/', '\\')}/{dataSourceName}?fields={Uri.EscapeDataString(control.ValueMember)},{Uri.EscapeDataString(control.DisplayMember)}"; if (conditions != null && conditions.Count > 0) { var arr = conditions.Select(s => $"({s.Name},{s.Symbol},{s.Value})").ToArray(); url += "&conditions=" + Uri.EscapeDataString(string.Join(',', arr)); } var content = await _httpClient.GetStringAsync(url); var table = JsonToDataTable(content); control.DataSource = table; } } } static DataTable JsonToDataTable(string json) { var table = new DataTable(); var list = JsonSerializer.Deserialize<IList<Dictionary<string, dynamic>>>(json); var columns = list?.First().Select(d => d.Key); if (list != null && columns != null) { foreach (var item in columns) { table.Columns.Add(item); } foreach (var item in list) { table.Rows.Add(item.Values.ToArray()); } } return table; } public static async Task DBGridInit(this DataGridView control, string url, string dataSourceName, List<DBCondition>? conditions) { if (!control.IsAncestorSiteInDesignMode) { if (!string.IsNullOrWhiteSpace(url) && !string.IsNullOrWhiteSpace(dataSourceName) && control.Columns.Count > 0) { var fieldList = new List<string>(); foreach (DataGridViewColumn column in control.Columns) { fieldList.Add(column.DataPropertyName); } url = $"{url.TrimEnd('/', '\\')}/{dataSourceName}?fields={Uri.EscapeDataString(string.Join(',', fieldList))}"; if (conditions != null && conditions.Count > 0) { var arr = conditions.Select(s => $"({s.Name},{s.Symbol},{s.Value})").ToArray(); url += "&conditions=" + Uri.EscapeDataString(string.Join(',', arr)); } var content = await _httpClient.GetStringAsync(url); var table = JsonToDataTable(content); control.DataSource = table; } } } } public class DBCondition { [Browsable(true)] [Description("查询条件名称"), Category("数据"), DefaultValue("")] [DisplayName] public string? Name { get; set; } [Browsable(true)] [Description("条件符号"), Category("数据"), DefaultValue("")] public string? Symbol { get; set; } [Browsable(true)] [Description("查询条件值"), Category("数据"), DefaultValue("")] public string? Value { get; set; } } }
DBComBox控件:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace GSWControls { [ToolboxItem(true)] [ToolboxBitmap(typeof(DBComBox), "gcom.png")] public class DBComBox : ComboBox { [Browsable(true)] [Description("后端Url"), Category("远程数据"), DefaultValue("")] public string? Url { get; set; } [Browsable(true)] [Description("访问Url后端数据源名称"), Category("远程数据"), DefaultValue("")] public string? DataSourceName { get; set; } [Browsable(true)] [Description("查询数据源条件参数"), Category("远程数据"), DefaultValue("")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public List<DBCondition>? Conditions { get; set; } = new List<DBCondition>(); protected async override void CreateHandle() { base.CreateHandle(); if (!string.IsNullOrWhiteSpace(Url) && !string.IsNullOrWhiteSpace(DataSourceName) && Conditions != null) { await this.DBControlInit(Url, DataSourceName, Conditions); } } } }
DBDataGridView控件:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace GSWControls { [ToolboxItem(true)] [ToolboxBitmap(typeof(DBDataGridView), "ggrid.png")] public class DBDataGridView : DataGridView { [Browsable(true)] [Description("后端Url"), Category("远程数据"), DefaultValue("")] public string? Url { get; set; } [Browsable(true)] [Description("访问Url后端数据源名称"), Category("远程数据"), DefaultValue("")] public string? DataSourceName { get; set; } [Browsable(true)] [Description("查询数据源条件参数"), Category("远程数据"), DefaultValue("")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public List<DBCondition>? Conditions { get; set; } = new List<DBCondition>(); protected async override void CreateHandle() { base.CreateHandle(); if (!string.IsNullOrWhiteSpace(Url) && !string.IsNullOrWhiteSpace(DataSourceName) && Conditions != null) { await this.DBGridInit(Url, DataSourceName, Conditions); } } } }
上面的属性都是为了在VS的工具箱或在属性管理器里,让自定义控件看起起来与官方控件一样。
![](/i/l/?n=23&i=blog/1101861/202302/1101861-20230207205357843-264410184.png)
使用控件项目:
使用项目很简单,就是完成布局,设置一下属性就可以了。
DBComBox的控件设置
查询条件设置(这里没有处理条件间的组合)
DBDataGridView的属性设置,DataGridView的列是设置在控件本身的更中的,这里就不切图了。
这个组合查询条件
最后运行结果:
标签:十一,string,控件,System,var,using,public,WinForm From: https://www.cnblogs.com/ljknlb/p/17099824.html