首页 > 社交 > 科普中国

WinForm(九)UI加载“大”数据

常驻编辑 科普中国 2022-09-20 递归   加载   数据   窗体   中国   文件夹   思路   菜单   速度   用户

由于WinForm的UI是绘制的,所以在加载大量数据数据时会有一定的延时,本篇就讨论几个减少延时的方法。krT拜客生活常识网

在加载有规律数据时,可以考虑用递归,简单方便快捷来加载数据,如下,把一个文件夹下的所有文件或文件夹加载到树形菜单上,以树形展示,代码实现如下。krT拜客生活常识网

var rootPath = "d://abc/bcd";
var rootNode = treeView1.Nodes.Add(rootPath, Path.GetFileName(rootPath));
LoadFile(rootNode);




void LoadFile(TreeNode node)
{
    foreach (var file in Directory.GetFiles(node.Name))
    {
        node.Nodes.Add(file, Path.GetFileName(file));
    }
    foreach (var dir in Directory.GetDirectories(node.Name))
    {
        var childNode = node.Nodes.Add(dir, Path.GetFileName(dir));
        LoadFile(childNode);
    }
}

上面的是练了个手,接下来我们加载一个大点的数据,一个全国的行政区划表,有省,市 ,县,乡镇四级,一共49000多条数据,数据字段有sid,pid,name。本篇我们主要是看从内存list到UI上,所以加载数据不是重点,可以是数据库,也可以是文件中,最终数据会在内存的list中。krT拜客生活常识网

class Province
{
    public string sid { get; set; }
    public string pid { get; set; }
    public string name { get; set; }
}


krT拜客生活常识网

var rootNode = treeView1.Nodes.Add("0", "中国");
LoadProvince(rootNode);


void LoadProvince(TreeNode node)
{
    foreach (var item in list.Where(s => s.pid == node.Name))
    {
        var childNode = node.Nodes.Add(item.sid, item.name);
        LoadProvince(childNode);
    }
}

如果直接用递归加载,速度太慢,为了加快速度,就得并行加载了,于时就增加Task.Run,因为是大多线程中异步操作UI,所以还得用this.Invoke,代码如下。运行,会看到,速度显然快了不了,但还不是理想结果,理想是无感。krT拜客生活常识网

var rootNode = treeView1.Nodes.Add("0", "中国");
LoadProvince(rootNode);
void LoadProvince(TreeNode node)
{
    Task.Run(() =>
    {
        foreach (var item in list.Where(s => s.pid == node.Name).OrderBy(s => s.sid))
        {
            this.Invoke(() =>
            {
                node.Nodes.Add(item.sid, item.name);
                if (node.Level == 0)
                {
                    node.Expand();
                }
            });
        }
        foreach (TreeNode childNode in node.Nodes)
        {
            LoadProvince(childNode);
        }
    });
}

后来又想到,可不可以把树形菜单给序列化,窗体启动时,返序列化回来,用BinaryFormatter来实现(现在官方不鼓励用),首先TreeView不支持序列化,只能换成TreeView的Nodes属笥来序列化。窗体启动时,它的加载速度与上面的异步递归差不多,没有明显改善。krT拜客生活常识网

即然一次加载大量数据不行,就再换一下思路,一次加载少一些,因为是UI,用户肯定有交互,利用用户的交互来触发加载他想要看的数据,这个少量多少为好,对于树形控件来说,如果想看不出来,那就是两级,用户点开第二级的时候再加载两级,这样用户始终感觉用数据。krT拜客生活常识网

private void Form1_Load(object sender, EventArgs e)
{
    var rootNode = treeView2.Nodes.Add("0", "中国");
    LoadProvince(rootNode, 1);
    this.treeView2.BeforeExpand += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeView2_BeforeExpand);
}
private void treeView2_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
    if (e.Node != null & e.Node.Nodes != null &&e.Node.Nodes.Count > 0)
    {
        e.Node.Nodes.Clear();
        LoadProvince(e.Node, 1);
    }
}

性能的问题永远没有最好,也没有一种方式能就通吃各种场景,得一个个换思路来解决,不过上面的思路肯定不是最好的,如果你有一次性加载全部更快的解决方案,请告我,我实现,然后再分享给更多的人。krT拜客生活常识网

相关阅读:

  • 中国第一代程序员王小波
  • Vue实现无限级树形选择器(无第三方依赖)
  • rsync用法教程(已验证)
  • Java中各种锁的介绍
  • 台式电脑开机加载不出桌面,电脑一直加载不出桌面怎么办
  • 转角遇到城市美容师,这个街道加载“一键美颜”模式!
  • 加载、读取资源的方式
  • HTML5实现头像的上传
  • 幼儿园大班数学试卷
  • 令人震撼!iPhone
    • 网站地图 |
    • 声明:登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。文章内容仅供参考,不做权威认证,如若验证其真实性,请咨询相关权威专业人士。