WPF MVVM模式下的无阻塞刷新探讨
很多时候我们需要做一个工作,在一个方法体里面,读取大数据绑定到UI界面,由于长时间的读取,读取独占了线程域,导致界面一直处于假死状态。例如,当应用程序开始读取Web资源时,读取的时效是由网络链路的速度决定的,那么在读取的过程中整个程序都必然处于一种等待状态,这不是我们想要看到的。那么我们有没有一种机制既能解决效率问题同时可以提供代码的可用性呢?有人可能会说,我们可以使用线程池。线程真的是万能的吗?当处理大并发数据量时就能说明这个问题,线程池最大的并发量有限制,而且线程是极度占用资源。
.NET 4.5下提供了一种异步方式,能够有效的避免效率瓶颈并增强应用程序的可维护性,这种机制类似于Node.js原理,这是一个完全单线程的方法,当有数据传递过程时,它首先把数据交给异步处理,再完成后再通过回调返回数据集,我们可以理解为c#版的闭包。它的最大作用是把原来的等待换成异步方式,把UI解放出来,因为UI的活动都是共用一个域的。
先看看传统模式下的无阻塞刷新,首先是XAML页面文件
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
</Grid.RowDefinitions>
<ListView Grid.Row="0" Width="auto" Height="auto" Name="lvData" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView.View>
<GridView>
<GridViewColumn Header="编号" DisplayMemberBinding="{Binding Path=Id}" Width="100" />
<GridViewColumn Header="随机数" DisplayMemberBinding="{Binding Path=Code}" Width="160"/> </GridView>
</ListView.View> </ListView> </Grid>
再新建一个ViewModel类,这个类的作用是为我们的MVVM模式提供一个数据源
public class RandomViewModel
{
public RandomViewModel()
{
Model = new ObservableCollection<RandomData>();
} public ObservableCollection<RandomData> Model; public List<RandomData> dataList; public void FillData()
{
Model.Clear();
for (int i = ; i < dataList.Count; i++)
{
Model.Add(dataList[i]);
} } public void GetData()
{
dataList = new List<RandomData>();
Random random = new Random();
for (int i = ; i < ; i++)
{ dataList.Add(new RandomData()
{
Id = i,
Code = random.NextDouble()
});
}
}
}
public class RandomData
{
public int Id { get; set; }
public double Code { get; set; }
}
传统模式下的无刷新调用,先在线程内部计算出需要绑定的数据,然后再使用Invoke填充Model.
Thread thread = new Thread(p =>
{
while (true)
{
ViewModel.GetData();
this.Dispatcher.Invoke(new Action<List<RandomData>>(result =>
{
ViewModel.FillData();
}), ViewModel.dataList); Thread.Sleep();
}
});
thread.IsBackground = true;
thread.Start();
在代码中嵌入线程函数,代码是很分散的,同时也消耗大量资源。为了让我们代码尽可能的做到内外同步执行。我们使用async、await、Task
private async Task AsyncAccess()
{
while (true)
{
var getDataListTask = new Task(() =>
{
Thread.Sleep();
ViewModel.GetData();
}); getDataListTask.Start(); await getDataListTask; var fillModelTask = Task.Factory.StartNew(() =>
{
ViewModel.FillData();
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); await fillModelTask;
} }
理论上说,Task.Factory.StartNew也是在线程池上执行,可表示异步操作而且更加通用,其中在Task前加上await使用成为异步函数,不然UI界面仍会有卡顿的现象。
最后一个Invoke方法,需要通过SynchronizationContext.SetSynchronizationContext方法在多线程环境下设置SynchronizationContext.Current属性,将线程控制域转交至UI,设置当前SynchronizationContext相关的TaskScheduler,利用这个TaskScheduler,Task将通过当前SynchronizationContext来执行,实际上上述代码在WPF下等效于调用Dispatcher.BeginInvoke方法。
.net 4.5下已默认封装的相关类库有
访问Web | HttpClient , SyndicationClient |
使用文件 | StorageFile, StreamWriter, StreamReader,XmlReader |
使用图像 | MediaCapture, BitmapEncoder, BitmapDecoder |
WCF程序开发 | Synchronous and Asynchronous Operations |
使用sockets | Socket |
WPF MVVM模式下的无阻塞刷新探讨的更多相关文章
- wpf mvvm模式下CommandParameter传递多参
原文:wpf mvvm模式下CommandParameter传递多参 CommandParameter一般只允许设置一次,所以如果要传递多参数,就要稍微处理一下.我暂时还没找到更好的方案,下面介绍的这 ...
- WPF MVVM模式下ComboBox级联效果 选择第一项
MVVM模式下做的省市区的级联效果.通过改变ComboBox执行命令改变市,区. 解决主要问题就是默认选中第一项 1.首先要定义一个属性,继承自INotifyPropertyChanged接口.我这里 ...
- WPF MVVM模式下路由事件
一,路由事件下三种路由策略: 1 冒泡:由事件源向上传递一直到根元素.2直接:只有事件源才有机会响应事件.3隧道:从元素树的根部调用事件处理程序并依次向下深入直到事件源.一般情况下,WPF提供的输入事 ...
- WPF MVVM模式下实现ListView下拉显示更多内容
在手机App中,如果有一个展示信息的列表,通常会展示很少一部分,当用户滑动到列表底部时,再加载更多内容.这样有两个好处,提高程序性能,减少网络流量.这篇博客中,将介绍如何在WPF ListView中实 ...
- wpf mvvm模式下 在ViewModel关闭view
本文只是博主用来记录笔记,误喷 使用到到了MVVM中消息通知功能 第一步:在需要关闭窗体中注册消息 public UserView() { this.DataContext = new UserVie ...
- wpf mvvm模式下的image绑定
view文件 <Image Grid.Column="2" Width="48" Height="64" Stretch=" ...
- WPF中在MVVM模式下,后台绑定ListCollectionView事件触发问题
问题:WPF中MVVM模式下 ListView绑定ListCollectionView时,CurrentChanged无法触发 解决方案: 初期方案:利用ListView的SelectionChang ...
- WPF实战案例-MVVM模式下在Xaml中弹出窗体
相信很多学习和开发wpf项目的同学都了解过mvvm模式,同样,在mvvm模式下会有一个不可忽视的问题,就是怎么在xaml中弹出窗体,而不破坏MVVM本身的结构. 关于弹出窗体的方式还是很多的,本文先讲 ...
- MVVM模式下WPF动态绑定展示图片
MVVM模式下WPF动态展示图片,界面选择图标,复制到项目中固定目录下面,保存到数据库的是相对路径,再次读取的时候是根据数据库的相对路径去获取项目中绝对路径的图片展示. 首先在ViewModel中 / ...
随机推荐
- HDU 4925 Apple Tree(模拟题)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4925 解题报告:给你n*m的土地,现在对每一块土地有两种操作,最多只能在每块土地上进行两种操作,第一种 ...
- :( Call to a member function Table() on a non-object 错误位置
:( Call to a member function Table() on a non-object 错误位置 $Model不是模板,是你自己先前链接数据库返回的对象...我的是改为$Form
- JSoup——用Java解析html网页内容
当需要从网页上获取信息时,需要解析html页面.筛选指定标签,并获取其值是必不可少的操作,解析html页面这方面的利器,Python有BeautifulSoup,Java一直没有好的工具,之前的Htm ...
- Java--读写文件综合
package javatest; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream ...
- Nikto是一款Web安全扫描工具,可以扫描指定主机的web类型,主机名,特定目录,cookie,特定CGI漏洞,XSS漏洞,SQL注入漏洞等,非常强大滴说。。。
Nikto是一款Web安全扫描工具,可以扫描指定主机的web类型,主机名,特定目录,cookie,特定CGI漏洞,XSS漏洞,SQL注入漏洞等,非常强大滴说... root@xi4ojin:~# cd ...
- A PHP extension for Facebook's RocksDB
A PHP extension for Facebook's RocksDB 31 commits 2 branches 0 releases 2 contributors C++ 90.5% C 8 ...
- php __set() __get() __isset() __unset()四个方法的应用
一般来说,总是把类的属性定义为private,这更符合现实的逻辑.但是,对属性的读取 和赋值操作是非常频繁的,因此在PHP5 中,预定义了两个函数“__get()”和“__set()”来获 取和赋值其 ...
- CentOS6.5以runlevel 3开机时自动连接某无线设置示例
[参考]http://blog.csdn.net/simeone18/article/details/8580592 [方法一] 假设无线网卡代号为wlan0,无线AP的essid为:TheWiFi, ...
- Python yield 使用浅析(转)
Python yield 使用浅析 初学 Python 的开发者经常会发现很多 Python 函数中用到了 yield 关键字,然而,带有 yield 的函数执行流程却和普通函数不一样,yield 到 ...
- host
#Google Services START209.116.186.241 0.docs.google.com209.116.186.241 0.drive.google.com209.116.186 ...