WPF,这种情况如何异步体验

货郎大叔 2017-08-10 09:55:14
在WPF应用程序中,当遇到较长时间运算时,可以使用BackgroundWorker异步操作,然后主线程可以做一个加载状态的图标,以便给用户一个较好的体验。这其中,如果遇到要访问界面UI,则要Dispatcher将访问的代码封送到主线程去执行。

那现在,比如有一个较为复杂的,数据量较大的,给DataGrid设置ItemsSource,使得运算时间较长,这时如果使用BackgroundWorker异步操作的话,也行不通,因为设置DataGrid的ItemsSource的代码过程,本身就是访问界面UI的,这时,反而又需要使用Dispatcher将访问的代码封送到主线程去执行。那这样的结果,其实就是没有获得任何好的体验,程序任然卡得不要不要的。


在给DataGrid设置ItemsSource时,该怎么异步体验呢?
...全文
495 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
例如你UI 优化之后,一次刷新一批图层,那么此时也就可以把图层分成两类,让第二部分图层注册到以下一个 BeginInvoke(....) 中,增加(貌似的)流畅性。 总之首先是在帮顶过程中深入去调整,其次是绝不可能纠结一种过分的做法,而是各种做法相辅相成地灵活使用。
  • 打赏
  • 举报
回复
引用 12 楼 sr32r345 的回复:
看来,卡是肯定要卡得,因为这里的耗时操作不是计算数据,耗时操作本身就是操作UI,是设置ItemsSource。再怎么封送, 也是在主线程执行。 对吗? 可不可以把DataGrid弄成到非主线程中去?
如果你把绑定数据之前的数据处理已经异步处理了,那么纠结这一条语句怎么写,意思就不大了。应该深入到你的绑定的内部来细看。
  • 打赏
  • 举报
回复
引用 8 楼 sr32r345 的回复:
[quote=引用 7 楼 dy00544 的回复:] 数据如果太多 不要一次全部显示完,随用随取 另外你取数据丢给其他线程去操作,取完了再绑定吧。
数据本身花时间不多,就是设置ItemsSource这一步开始,就卡[/quote] 那么要从你的 DataGrid 内部处理机制的“深处”去改造。比如说它内部也有可以异步化的处理过程,比如说应该在处理前先禁止UI刷新、然后处理完毕之后才允许UI刷新,比如说应该只显示可见区域的内容、甚至在滚动滚动条时应该复用 Item 对象而不应该创建新的 Item 对象,比如说应该抽稀数据,比如说应该简化模型设计。等等。总之是在深入的地方进行重构。
MYsce 2017-08-13
  • 打赏
  • 举报
回复
async 、 await
货郎大叔 2017-08-12
  • 打赏
  • 举报
回复
我现在只想获得异步体验,这都是闲不了么
半拉调 2017-08-12
  • 打赏
  • 举报
回复
如果是单纯显示卡顿的问题,可以分段更新后在线程中加sleep(20) 实现了Inotify接口的页面更新是系统自己调配的,但是你如果本身太占CPU,系统会无法空出来做页面更新的。
货郎大叔 2017-08-12
  • 打赏
  • 举报
回复
还是不行,我对ItemsSource使用了Binding,还是不行
半拉调 2017-08-11
  • 打赏
  • 举报
回复
看了下,我觉得你没理解到WPF的Binding, 为什么是操作Datagrid的binding source呢? 前台设定binding ,后台一个Table,你应该操作Table吧? 这个才是binding的意义吧。
乱臣贼子 2017-08-11
  • 打赏
  • 举报
回复
你这点儿数据量,你这个UI界面,都不复杂,不大。理论上说是不会出现卡顿现象的,但是你出现了这个现象,那么说明你的程序的某个控件中执行了耗时操作,而你没有发现他。 你需要看看你的控件中哪里会出现耗时操作,跟踪下,也可以使用第三方工具跟踪下耗时在哪里!
xinweilee 2017-08-11
  • 打赏
  • 举报
回复
先绑定itemsource,在异步向Itemsource中添加数据
货郎大叔 2017-08-11
  • 打赏
  • 举报
回复
引用 7 楼 dy00544 的回复:
数据如果太多 不要一次全部显示完,随用随取 另外你取数据丢给其他线程去操作,取完了再绑定吧。
数据本身花时间不多,就是设置ItemsSource这一步开始,就卡
dy00544 2017-08-11
  • 打赏
  • 举报
回复
数据如果太多 不要一次全部显示完,随用随取 另外你取数据丢给其他线程去操作,取完了再绑定吧。
exception92 2017-08-11
  • 打赏
  • 举报
回复
在给DataGrid设置ItemsSource时,该怎么异步体验呢 -》使用C# 6.0中async、await 关键字。 需要.net framework4.5及以上框架支持。 使用关键字 简化了异步操作,下面是一个例子,尽可能让例子完整,xaml:

 <StackPanel Margin="10">
            <TextBox x:Name="tb" Width="600" Height="40"></TextBox>
            <GroupBox Header="加载数据">
                <DataGrid x:Name="dg" Margin="20"  Width="600" Height="500"  AutoGenerateColumns="True" CanUserAddRows="False">
                </DataGrid>
            </GroupBox>
            <ProgressBar x:Name="pb" Width="500" Height="30" IsIndeterminate="False" Minimum="0" Maximum="100"></ProgressBar>
            <TextBlock x:Name="tbTime"></TextBlock>
            <Button x:Name="btnClick" Width="120" Height="30" Content="Load" Click="btnClick_Click"></Button>
        </StackPanel>
btnClick_Click:

 /// <summary>
        /// 当前线程调度器
        /// </summary>
        private readonly Dispatcher _dispatcher = Dispatcher.CurrentDispatcher;

        private void btnClick_Click(object sender, RoutedEventArgs e)
        {
            SlowDudeAsync();
        }
         /// <summary>
        /// 异步读取数据
        /// </summary>
        public async void SlowDudeAsync()
        {
            tb.Text = "开始异步\r\n";
            pb.IsIndeterminate = true;
            // 计算耗时
            System.Diagnostics.Stopwatch stop = new System.Diagnostics.Stopwatch();
            stop.Start();
            await Task.Factory.StartNew(() => SlowDude()); ;
            tb.Text += "异步结束";
            pb.IsIndeterminate = false;
            stop.Stop();
            tbTime.Text = "耗时:" + stop.ElapsedMilliseconds + "ms";
        }
        /// <summary>
        /// 读取数据
        /// </summary>
        public void SlowDude()
        {
            // 查询数据到DataSet
            DataSet dt = DbHelperSQL.ExecuteDataSet("select * from xxxxx", null);
            this._dispatcher.BeginInvoke(new Action(() =>
            {
                dg.ItemsSource = dt.Tables[0].DefaultView;
            }));
        }
货郎大叔 2017-08-11
  • 打赏
  • 举报
回复
看来,卡是肯定要卡得,因为这里的耗时操作不是计算数据,耗时操作本身就是操作UI,是设置ItemsSource。再怎么封送, 也是在主线程执行。 对吗? 可不可以把DataGrid弄成到非主线程中去?
货郎大叔 2017-08-11
  • 打赏
  • 举报
回复
引用 1 楼 yenange 的回复:
试下用 async 、 await
结果一样,还是卡,很奇怪,使用async 、 await,感觉和同步一样的卡,窗口都不能动。

private async void GetShowCellInformationStruct(int QiShuCount, int StartQiShu, int EndQiShu)
        {
            var slowTask = Task.Factory.StartNew(new Action(() => 
            {
                curdp.BeginInvoke(DispatcherPriority.Normal, new Action(() => { DataGrid1.ItemsSource = a; }));                
            })); 
            await slowTask; //悬挂点。
        }
货郎大叔 2017-08-11
  • 打赏
  • 举报
回复
引用 4 楼 ilikeff8 的回复:
你这还是winform的思路,itemsource和加载进度条值和是否显示都绑定到属性并做必要的设置,而且实现inotifypropertychanged接口后,只对属性进行操作,另外,数据本身不要显示全部,你itemsource显示十万条记录什么的

不管你怎么绑定,最终设置itemsource的时候,都是和UI打交道,因为要一行一行的显示出来。
数据条目不多,一次显示不超过200行,但是UI显示稍显复杂一点点,还是要卡几秒。下面这种:
ilikeff8 2017-08-11
  • 打赏
  • 举报
回复
你这还是winform的思路,itemsource和加载进度条值和是否显示都绑定到属性并做必要的设置,而且实现inotifypropertychanged接口后,只对属性进行操作,另外,数据本身不要显示全部,你itemsource显示十万条记录什么的
  • 打赏
  • 举报
回复
给 ItemsSource 赋值只需要一瞬间,例如
dataGrid1.ItemsSource = a;
你不至于把“数据时间”算做是界面操作时间吧?!!
货郎大叔 2017-08-10
  • 打赏
  • 举报
回复
引用 1 楼 yenange 的回复:
试下用 async 、 await
async ?await? 请问,这是什么,第一次看到
吉普赛的歌 2017-08-10
  • 打赏
  • 举报
回复
试下用 async 、 await

110,529

社区成员

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

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

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