C#主界面卡的问题

秋山澪公主 2017-03-03 10:12:05
以下代码已经另开线程了,但是还是因为往主线程上的控件赋值的时候因为变量复杂庞大还是会卡住,有解决办法吗?
TreeNode treeNodeRoot = new TreeNode();
//另开一个线程计算得到treeNodeRoot ,但得到的treeNodeRoot很庞大
treeNodeRoot = Utility.TraverseJsonTree(jTree, treeNodeRoot);
treeView_result.Invoke(
new MethodInvoker
(
delegate
{
treeView_result.Nodes.Add(treeNodeRoot);//treeNodeRoot加到treeView_result上展示时会卡住界面主线程

}
));
...全文
358 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
得到的节点很多的话,可以做延迟加载,没必要一次性加载完。
「已注销」 2017-04-06
  • 打赏
  • 举报
回复
所有与界面相关的操作都放到ui线程,所有非ui的工作都放到单独的其他线程去完成,参考 http://www.cnblogs.com/zzfstudy/p/6193640.html
xuggzu 2017-03-04
  • 打赏
  • 举报
回复
treenoderoot太大影响时间,那就写个线程自己解析此node自己添加到tree
sp1234_maJia 2017-03-04
  • 打赏
  • 举报
回复
嗯,刚刚重新看了一下,上面代码中 var r = n.Nodes; n.Nodes.Clear(); 这里的 r 应该的意思是要对 n.Nodes 进行复制(产生另外一个 TreeNode 集合),因此少写了一两行语句!你自己理解就好。 这个例子只是说它比较复杂,不实际。而比较复杂不实际的根源,其实就是自以为比较技术化地搞“一次性产生了TreeRoot”造成的。
  • 打赏
  • 举报
回复
如果你一开始弄出了一个庞大的 Tree Root,然后再去“分步去加载”,你需要一个节点一个节点地加载(加载前先把你找到的数据节点的“子节点”先脱离原来的父子节点关系,然后判断当计数小于一定限制时就同步再加回原来的位置,否则就异步地把子节点。 我随便写一下大概意思(随便写的,只是一个示意)
public void 加载(TreeNodeCollection 数据, TreeNodeCollection 实际控件)
{
    加载(数据, 实际控件, 0);
}

public int 加载(TreeNodeCollection 数据, TreeNodeCollection 实际控件, int index)
{
    foreach (TreeNode n in 数据)
    {
        var r = n.Nodes;
        n.Nodes.Clear();
        实际控件.Add(n);
        index++;
        if (index <= 30)
            index = 加载(r, n.Nodes, index);     //把r加载到n下边
        else        //如果大于30步则异步加载
            ThreadPool.QueueUserWorkItem(h =>
            {
                this.BeginInvoke((Action)delegate
                {
                    加载(r, n.Nodes, 0);      //把r加载到n下边,index从0开始计数
                });
            });
    }
    return index;
}
你可以清晰地看到,实际上想当然地“另开一个线程计算得到庞大的 treeNodeRoot”好像挺高大上似地,好像很技术化似地,其实它一点也不技术。单纯技术化是很幼稚的,它反而造成你不得不写出非常复杂、诡异的后续代码。 而如果你稍微动脑筋、用心设计一个“事件驱动”模型,你只需要得到2层节点的 treeNodeRoot,然后在加入节点时动态注册监听其 Expand 事件,在事件中再去判断对于当前 第 n 层节点是否需要加载第 n+2层子节点,只要这样离散地把数据模型插入用户交互细节中,你的“计算子节点”的业务逻辑是细节的、小的,你的程序的用户体验是好的、流畅的。而且代码写起来也很简单,比上面的这个要容易理解多了。
  • 打赏
  • 举报
回复
处理用户体验问题,一定要变通,千万不要死守一些初学的技术。从自然出发越简单极致才越会有好的用户体验。 它可比你知道的技术知识更丰富,更有创意,更重要。
  • 打赏
  • 举报
回复
引用 楼主 Kel_Thuzad 的回复:
但得到的treeNodeRoot很庞大 treeNodeRoot = Utility.TraverseJsonTree(jTree, treeNodeRoot); treeView_result.Invoke( new MethodInvoker ( delegate { treeView_result.Nodes.Add(treeNodeRoot);//treeNodeRoot加到treeView_result上展示时会卡住界面主线程 } ));
要让主线程(显得)“流畅”,至少有两个方面要去做。第一就是牺牲性能而提高流畅的用户体验,实际上加载时间长了但是用户通常反而感觉比较流程,那么就要每当加载一部分(比如说20个 treeNode 之后)就把剩下的加载异步地注册到下一个 Control.BeginInvoke 回调中去处理。这时候就要有点“悟性”,要知道牺牲性能换来用户体验,要辩证地搞清楚目的而不要空谈技术。 第二,更多但更通用的情况其实是复杂一点,也就是只计算和1、2层 Nodes(而你说你一次性计算了整个树,这对于大数据来说更是空谈),然后在树上只加载2层。此时界面上自然只展示一层。当用界面操作展开第一层,在这个“展开”事件中才动态加载被展开的节点下的第三层,当用户在界面上展开某个第2层节点时才动态加载它下面的第4层节点..........这样的设计是基于事件驱动的,是离散的。客观上,实际上它跟上面第一点有本质的相同的地方,就是加载时都是离散的。但是这就更将离散推入实际深处,根本摒弃了想当然的什么“一次性计算得到树”了。 你会看到,空洞地搞技术、一次性得到树,其实是问题的根源。反而有些人会自己为很懂技术,其实真正的技术是要重构,要反技术,才能改进技术。
threenewbee 2017-03-03
  • 打赏
  • 举报
回复
treeView_result.Nodes.Add(treeNodeRoot);
如果性能耗在这里,那么多线程也没用,你可以隐藏下treeview,等更新完显示
或者在你的循环中加入application.doevents() 接收消息,避免卡住
水哥阿乐 2017-03-03
  • 打赏
  • 举报
回复
性能是个无止境的话题,值类型和址类型也同样是个矛盾,一个是耗内存,一个是耗CPU, webserver webfrom winform 数据层 xml sql xsd............. 框架基类 IO,集合,字符 .... CLR 元数据 IL system 另外不知道你是否记得上面的net基础,不要轻易动界面层,越到底层效率越高,号称软件界的爱因思坦比尔乔伊曾高度评价过XML是计算界最伟大的发明之一,对tree结构最好的表现莫过于xml,所以建议你先将取得的树结构存成XML. 以后要用时随用随取,既然你卡在树上,那么你应该在树上解决

110,535

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧