1、前言

在做winform开发的过程中,经常需要做数据展示的功能,之前一直使用的是gridcontrol控件,今天想通过一个示例,跟大家介绍一下如何在winform blazor hybrid中使用ant design blazor中的table组件做数据展示。

2、效果

先来看看实现的效果:

3、具体实现

怎么在winform blazor hybrid项目中使用Ant Design Blazor可以看我上篇文章。

引入Ant Design Blazor的Table组件:

  1. <Table TItem="IData" DataSource="@datas"
        OnRowClick="OnRowClick" @ref="antTableRef" >
        <PropertyColumn Property="c=>c.StationName">            
        </PropertyColumn>
        <PropertyColumn Property="c=>c.Weather">
        </PropertyColumn>
        <PropertyColumn Property="c=>c.Tem_Low">            
        </PropertyColumn>
        <PropertyColumn Property="c=>c.Tem_High">          
        </PropertyColumn>
        <PropertyColumn Property="c=>c.Wind">
        </PropertyColumn>
        <PropertyColumn Property="c=>c.Visibility_Low">
        </PropertyColumn>
        <PropertyColumn Property="c=>c.Visibility_High">
        </PropertyColumn>
        <PropertyColumn Property="c=>c.Fog">
        </PropertyColumn>
        <PropertyColumn Property="c=>c.Haze">
        </PropertyColumn>
        <PropertyColumn Property="c=>c.Date">
        </PropertyColumn>
    </Table>

其中:

TItem表示DataSource中单个项的类型,从 0.16.0 开始,Table 已支持普通类、record、接口和抽象类作为 DataSource 的类型。

这里我的TItem设置为一个叫做IData的接口,它的定义如下:

  1. public interface IData
    {
      [DisplayName("站名")]
       public string? StationName { get; set; }
      [DisplayName("天气")]
       public string? Weather { get; set; }
      [DisplayName("最低温度/℃")]
       public string? Tem_Low { get; set; }
      [DisplayName("最高温度/℃")]
       public string? Tem_High { get; set; }
      [DisplayName("风力风向")]
       public string? Wind { get; set; }
      [DisplayName("最低可见度/km")]
       public string? Visibility_Low { get; set; }
      [DisplayName("最高可见度/km")]
       public string? Visibility_High { get; set; }
      [DisplayName("雾")]
       public string? Fog { get; set; }
      [DisplayName("霾")]
       public string? Haze { get; set; }
      [DisplayName("日期")]
       public DateTime? Date { get; set; }
    }

其中的[DisplayName("站名")]是一个属性或成员的元数据注解,用于提供一个更友好的显示名称。Ant Design Blazor会自动使用这个来显示名称。

DataSource表示表格的数据源,类型为IEnumerable

这里DataSource="@datas"表示我将一个名为 datas 的数据源分配给Table组件的 DataSource 属性。

datas的定义如下:

  1. WeatherData[] datas = Array.Empty<WeatherData>();

WeatherData是自定义类,实现了IData接口:

  1.    public class WeatherData : IData
      {
          [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
           public int Id { get; set; }    
           public string? StationName { get; set; }
           public string? Weather { get; set; }
           public string? Tem_Low { get; set; }
           public string? Tem_High { get; set; }
           public string? Wind { get; set; }
           public string? Visibility_Low { get; set; }
           public string? Visibility_High { get; set; }
           public string? Fog { get; set; }
           public string? Haze { get; set; }
           public DateTime? Date { get; set; }
      }
    }

看到这里大家可能会有个疑问,那就是刚刚的TItem表示DataSource中单个项的类型,但是现在这里DataSourceWeatherData[],那么单个项的类型是WeatherData而不是刚刚设置的IData,这样可以吗?

通过以下这个简单的例子,可能你就会解开疑惑:

  1. public interface IFlyable
    {
       void Fly();
    }
    public class Bird : IFlyable
    {
       public void Fly()
      {
           Console.WriteLine("The bird is flying.");
      }

    }
    class Program
    {
       // 主方法
       static void Main()
      {
          Bird myBird = new Bird();
          IFlyable flyableObject = myBird; // 类型转换

           // 调用接口方法
           flyableObject.Fly();
      }
    }

定义了一个IFlyable接口、一个Bird类,该类实现了IFlyable接口,在Main函数中,实例化了一个Bird类,然后该对象隐式转换为接口类型,再通过接口调用实现类的方法,输出结果为:

  1. The bird is flying.

这说明C# 中当一个类实现了一个接口时,该类的实例可以被隐式转换为该接口类型。这里就是WeatherData会被隐式转化为了IData

DataSource也是一样,虽然官方文档上写的类型是IEnumerable,但是我们这里确是WeatherData[]这样也可以,也是因为Array实现了IEnumerable接口,如下所示:

OnRowClick表示行点击事件,类型为EventCallback<RowData>,本例中实际上没有用到。

在Blazor中,@ref 是一个用于在Blazor组件中引用HTML元素或组件实例的指令。通过使用 @ref,你可以在Blazor组件中获取对DOM元素或子组件的引用,然后在代码中进行操作或访问其属性和方法。

这里我在Table组件上添加了@ref="antTableRef",在代码区域添加了:

  1. Table<IData>? antTableRef;

就成功引用了Table组件实例。

<PropertyColumn>表示属性列,也就是要展示的列。它的Property属性指定要绑定的属性,类型为Expression<Func<TItem, TProp>>

这里大家可能会有疑问,Expression<Func<TItem, TProp>>到底是啥呀?

Expression<Func<TItem, TProp>> 是C#中的一个表达式树,用于表示一个参数为 TItem 类型且返回值为 TProp 类型的lambda表达式。

拆开来看,Expression<T> 是一个表示lambda表达式的树状结构的类,其中 T 是委托类型。详细学习,可以查看官方文档:

Func<TItem, TProp> 是一个泛型委托类型,表示一个带有一个输入参数和一个输出参数的方法,详细学习,也可以查看官方文档:

这里也通过一个简单的例子进行说明:

  1. Expression<Func<Person, string>> getNameExpression = person => person.Name;

getNameExpression表示一个Lambda表达式,一个什么样的Lambda表达式呢?一个输入参数类型为Person对应这里的person、输出类型为string对应这里的person.Name的一个Lambda表达式。

所以代码:

  1. <PropertyColumn Property="c=>c.StationName">            
    </PropertyColumn>

就可以理解了,Property的类型是一个输入参数类型为TItem这里TItem的类型就是IData、输出类型为TProp这里TProp类型就是string的一个Lamda表达式c=>c.StationName

理解了以上之后,我们看看这部分的代码:

代码如下:

  1. <GridRow>
         <Space>
               <SpaceItem>
                   <Text Strong>开始日期:</Text>
               </SpaceItem>
               <SpaceItem>
                   <DatePicker TValue="DateTime?" Format="yyyy/MM/dd"
                   Mask="yyyy/dd/MM" Placeholder="@("yyyy/dd/MM")"
                   @bind-Value = "Date1"/>
               </SpaceItem>
               <SpaceItem>
                   <Text Strong>结束日期:</Text>
               </SpaceItem>
               <SpaceItem>
                   <DatePicker TValue="DateTime?" Format="yyyy/MM/dd"
                   Mask="yyyy/dd/MM" Placeholder="@("yyyy/dd/MM")"
                   @bind-Value = "Date2"/>
               </SpaceItem>
           <SpaceItem>
               <Text Strong>站名:</Text>
           </SpaceItem>
           <SpaceItem>
               <AutoComplete @bind-Value="@value"
                             Options="@options"
                             OnSelectionChange="OnSelectionChange"
                             OnActiveChange="OnActiveChange"
                             Placeholder="input here"
                             Style="width:150px"/>
           </SpaceItem>
           <SpaceItem>
               <Button Type="@ButtonType.Primary" OnClick="QueryButton_Clicked">查询</Button>
           </SpaceItem>
           </Space>
    </GridRow>

站名自动填充:

  1.  <AutoComplete @bind-Value="@value"
                             Options="@options"
                             OnSelectionChange="OnSelectionChange"
                             OnActiveChange="OnActiveChange"
                             Placeholder="input here"
                             Style="width:150px"/>

这个的实现,在上篇文章中已经介绍了,这里就不再重复讲了。

两个日期选择组件都使用了数据绑定:

  1. <SpaceItem>
        <DatePicker TValue="DateTime?" Format="yyyy/MM/dd"
                    Mask="yyyy/dd/MM" Placeholder="@("yyyy/dd/MM")"
                   @bind-Value = "Date1"/>
    </SpaceItem>
       
    <SpaceItem>
         <DatePicker TValue="DateTime?" Format="yyyy/MM/dd"
                   Mask="yyyy/dd/MM" Placeholder="@("yyyy/dd/MM")"
                   @bind-Value = "Date2"/>
    </SpaceItem>

其中:

TValue表示值的类型,这里设置为DateTime?

@bind-Value进行数据绑定,将日期选择组件的值与Date1和Date2绑定起来:

  1. DateTime? Date1;
    DateTime? Date2;

查询按钮:

  1. <Button Type="@ButtonType.Primary" OnClick="QueryButton_Clicked">查询</Button>

点击事件代码:

  1. async void QueryButton_Clicked()
    {
       if (Date1 != null && Date2 != null && value != null)
      {
           var cofig = new MessageConfig()
              {
                   Content = "正在更新中...",
                   Duration = 0
              };
           var task = _message.Loading(cofig);
           var condition = new Condition();
           condition.StartDate = (DateTime)Date1;
           condition.EndDate = (DateTime)Date2;
           condition.StationName = value;
           datas = weatherServer.GetDataByCondition(condition).ToArray();
           StateHasChanged();  
           task.Start();
      }
       else
      {
           await _message.Error("请查看开始日期、结束日期与站名是否都已选择!!!");
      }
    }

当条件成立时,创建Condition类型,写入开始日期、结束日期和站名,Condition类的定义如下:

  1. public class Condition
    {
        public DateTime StartDate{ get; set; }
        public DateTime EndDate { get; set; }
        public string? StationName { get; set; }    
    }

然后调用业务逻辑层的weatherServer中的GetDataByCondition方法:

  1. datas = weatherServer.GetDataByCondition(condition).ToArray();

weatherServer中的GetDataByCondition方法如下:

  1. public List<WeatherData> GetDataByCondition(Condition condition)
    {
        return dataService.GetDataByCondition(condition);
    }

因为涉及到数据库的读写,因此调用了数据库访问层中的dataService的GetDataByCondition方法。

数据库访问层中的dataService的GetDataByCondition方法如下:

  1.  public List<WeatherData> GetDataByCondition(Condition condition)
    {
         return db.Queryable<WeatherData>()
                  .Where(x => x.Date >= condition.StartDate &&
                              x.Date < condition.EndDate.AddDays(1) &&
                              x.StationName == condition.StationName).ToList();
    }

当重新查询时:

  1. StateHasChanged();  

调用这个方法组件会进行更新。在Blazor中,StateHasChanged 是一个方法,用于通知Blazor框架重新渲染组件及其子组件。Blazor组件的UI渲染是基于组件的状态(state)的,当组件的状态发生变化时,需要调用 StateHasChanged 方法来通知框架进行重新渲染。

  1. var cofig = new MessageConfig()
              {
                   Content = "正在更新中...",
                   Duration = 0
              };
    var task = _message.Loading(cofig);
    task.Start();

是给用户信息提示。

4、总结

以上通过一个完整的例子,说明了在winform中除了可以用girdcontrol做数据展示外也可以使用Ant Design Blazor中的Table做数据展示。

winform中也可以这样做数据展示✨的更多相关文章

  1. 记录一下SparkStreaming中因为使用redis做数据验证而导致数据结果不对的问题

    业务背景: 需要通过redis判断当前用户是否是新用户.当出现新用户后,会将该用户放入到redis中,以标明该用户已不是新用户啦. 出现问题: 发现入库时,并没有新用户入库,但我看了数据了,确实应该是 ...

  2. winform中利用反射实现泛型数据访问对象基类(2)

    在1的基础上做了一点改进 参数化处理 看上去更简洁 无主键情况下 update 方法需要改进 insert delete没有问题  /// <summary>     /// DAO基类 ...

  3. C#在winform中操作数据库,实现数据增删改查

    1.前言: 运行环境:VS2013+SQL2008+Windows10 程序界面预览: 使用的主要控件:dataGridview和menuStrip等. 2.功能具体介绍: 1.首先,我们要先实现基本 ...

  4. winform中利用反射实现泛型数据访问对象基类(3)

    继续完善了几点代码 满足没有主键的情况下使用 并且完善实体字段反射设置value时的类型转换 /// <summary> /// DAO基类 实体名必须要与数据表字段名一致 /// < ...

  5. winform中利用反射实现泛型数据访问对象基类(1)

    考虑到软件使用在客户端,同时想简化代码的实现,就写了一个泛型的数据访问对象基类,并不是特别健全,按道理应该参数化的方式实现insert和update,暂未使用参数化,抽时间改进. /// <su ...

  6. vue中使用Echart将一组数据展示出三种统计图

    1 <template> 2 <div class="container"> 3 <div id="myEchart" style ...

  7. 在DevExpress程序中使用Winform分页控件直接录入数据并保存

    一般情况下,我们都倾向于使用一个组织比较好的独立界面来录入或者展示相关的数据,这样处理比较规范,也方便显示比较复杂的数据.不过在一些情况下,我们也可能需要直接在GridView表格上直接录入或者修改数 ...

  8. WebGIS中利用AGS JS+eChart实现一些数据展示的探索

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 eChart提供了迁徙图.热点图.夜视图等跟地图能够很好的结 ...

  9. Winform中如何实现父窗体传递数据到子窗体并刷新子窗体

    原理:利用委托和事件,本文将以图文并茂的例子讲述,告诉我们So Easy --------------------------------------------------------------- ...

  10. 在DevExpress程序中使用PopupContainerEdit和PopupContainer实现数据展示

    在一些数据的即时查询场景中,我们可能需要对输入信息进行模糊查询并进行选择,例如在一些文本输入场景,如输入某个站点编码或者设备编码,然后获取符合的列表供用户选择的场景,本篇随笔介绍在DevExpress ...

随机推荐

  1. 通过AOP拦截Spring Boot日志并将其存入数据库

    本文分享自华为云社区<Spring Boot入门(23):[实战]通过AOP拦截Spring Boot日志并将其存入数据库>,作者:bug菌. 前言 在软件开发中,常常需要记录系统运行时的 ...

  2. 文心一言 VS 讯飞星火 VS chatgpt (86)-- 算法导论8.2 3题

    三.用go语言,假设我们在 COUNTING-SORT的第 10行循环的开始部分,将代码改写为: 10 for j = 1 to A.length 试证明该算法仍然是正确的.它还稳定吗? 文心一言: ...

  3. 微信小程序隐私保护协议修改方法 uniapp

    微信隐私保护协议指南 一天天没事闲的   01 在manifest.json 中添加一行 "__usePrivacyCheck__" : false   02 自定义一个弹窗组件 ...

  4. Xshell7 / Xftp7 永久免费,官网直连下载地址

    主要目的是让大家随时随地从官网下载Xshell和Xftp免费版(个人/家庭/学校免费) 最新变动:官方目前仅提供最新版以及上一个版本的软件下载!其他版本不提供下载 免费版5版本(最后一个版本,无任何限 ...

  5. Frida环境配置

    目录 安装Linux客户端 配置Android服务端 测试运行效果 官方手册 安装Linux客户端 github地址:https://github.com/frida/frida pip instal ...

  6. Kong网关

    Kong网关 一.kong网关核心概念 1. Upstream upstream 对象表示虚拟主机名,可用于通过多个服务对传入请求进行负载远的 2. Target 目标ip地址/主机名,其端口表示后端 ...

  7. Nacos启动报错:Please set the JAVA_HOME variable in your environment, We need java(x64) jdk8 or later

    可能原因: 1.JDK版本过低(应不低于1.8) 2.未设置jdk环境变量(可能性低) 3.jdk环境变量设置不适配nacos(博主就是这个原因) 解决方案: 1.直接在startup.cmd文件中设 ...

  8. 算法——AcWing算法提高课中代码和题解

    文章目录 第一章 动态规划 (完成情况:64/68) 数字三角形模型 最长上升子序列模型 背包模型 状态机模型 状态压缩DP 区间DP 树形DP 数位DP 单调队列优化DP 斜率优化DP 第二章 搜索 ...

  9. 可视化-vscode安装matplotlib工具

    可视化工具中,最流行的工具之一是 Matplotlib,它是一个数学绘图库,可以制作简单的图表,如折线图和散点图: 使用pip可以安装Matplotlib: 安装步骤:: 1.在vscode的终端输入 ...

  10. Maximum Diameter 题解

    Maximum Diameter 题目大意 定义长度为 \(n\) 的序列 \(a\) 的权值为: 所有的 \(n\) 个点的第 \(i\) 个点的度数为 \(a_i\) 的树的直径最大值,如果不存在 ...