WinForm 中也可以这样做数据展示

前言

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

效果

先来看看实现的效果

具体实现

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

引入Ant Design Blazor的Table组件:

xml 复制代码
 <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的接口,它的定义如下:

c# 复制代码
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的定义如下:

c# 复制代码
WeatherData[] datas = Array.Empty<WeatherData>();

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

c# 复制代码
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,这样可以吗?

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

c# 复制代码
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类,然后该对象隐式转换为接口类型,再通过接口调用实现类的方法,输出结果为:

c# 复制代码
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",在代码区域添加了:

c# 复制代码
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> 是一个泛型委托类型,表示一个带有一个输入参数和一个输出参数的方法,详细学习,也可以查看官方文档:

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

c# 复制代码
Expression<Func<Person, string>> getNameExpression = person => person.Name;

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

所以代码:

c# 复制代码
<PropertyColumn Property="c=>c.StationName">            
</PropertyColumn>

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

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

代码如下:

xml 复制代码
<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>

站名自动填充:

xml 复制代码
<AutoComplete @bind-Value="@value"
                          Options="@options"
                          OnSelectionChange="OnSelectionChange"
                          OnActiveChange="OnActiveChange"
                          Placeholder="input here" 
                          Style="width:150px"/>

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

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

xml 复制代码
 <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绑定起来:

c# 复制代码
DateTime? Date1;
DateTime? Date2;

查询按钮:

xml 复制代码
<Button Type="@ButtonType.Primary" OnClick="QueryButton_Clicked">查询</Button>

点击事件代码:

c# 复制代码
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类的定义如下:

c# 复制代码
public class Condition
{
    public DateTime StartDate{ get; set; }
    public DateTime EndDate { get; set; }
    public string? StationName { get; set; }     
}

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

c# 复制代码
datas = weatherServer.GetDataByCondition(condition).ToArray();

weatherServer中的GetDataByCondition方法如下:

c# 复制代码
public List<WeatherData> GetDataByCondition(Condition condition)
{
    return dataService.GetDataByCondition(condition);
}

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

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

c# 复制代码
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();
}

当重新查询时:

c# 复制代码
StateHasChanged();  

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

c# 复制代码
var cofig = new MessageConfig()
{
    Content = "正在更新中...",
    Duration = 0
};
var task = _message.Loading(cofig);
task.Start();

是给用户信息提示。

总结

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

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

优秀是一种习惯,欢迎大家留言学习!

作者:mingupupu

出处:cnblogs.com/mingupupu/p/17903806.html

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!

相关推荐
用户36674625267417 分钟前
接口文档汇总 - 2.设备状态管理
c#
序安InToo17 分钟前
第6课|注释与代码风格
后端·操作系统·嵌入式
xyy12317 分钟前
C#: Newtonsoft.Json 到 System.Text.Json 迁移避坑指南
后端
洋洋技术笔记20 分钟前
Spring Boot Web MVC配置详解
spring boot·后端
JxWang0520 分钟前
VS Code 配置 Markdown 环境
后端
navms23 分钟前
搞懂线程池,先把 Worker 机制啃明白
后端
JxWang0524 分钟前
离线数仓的优化及重构
后端
Nyarlathotep011325 分钟前
gin01:初探gin的启动
后端·go
JxWang0525 分钟前
安卓手机配置通用多屏协同及自动化脚本
后端
用户36674625267425 分钟前
接口文档汇总 - 3.PLC通信管理
c#