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中 / ...
随机推荐
- DiscuzX程序升级教程_不知道关闭论坛的看过来
DiscuzX程序升级教程,不知道关闭论坛的朋友看过来,适用于 1.0, 1.5 2.0 , 2.5Beta, 2.5RC,2.5, 3.0 1)关闭论坛:后台- 全局- 站点信息- 是否关闭 :是 ...
- java web dao 层和dao 实现层有什么好处
接口是为了屏蔽不同数据库的JDBC实现差异而出现的. 以常见的系统组织结构为例,管理系统里有一个部门department表用于存放部门信息,因为部门下面可能有子部门所以表中的字段要定义成类似树形结构的 ...
- 存在使i > j || i <= j不成立的数吗?
存在使i > j || i <= j不成立的数吗? 咋一看有点晕!一个数既不能大于也不能小于等于另一个数?那是什么数?答案是”非数“ 例子如下:‘ if(Double.NaN>Flo ...
- [置顶] Android应用开发之版本更新你莫愁
传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229 今天我们学习如何实现Android应用的自动更新版本功能,这是在各种语言编写的应用中都 ...
- Insertion Sort List
对链表进行插入排序,比对数组排序麻烦一点. ListNode *insertSortList(ListNode *head) { ListNode dummy(-); for (ListNode *c ...
- Linux 怎么查看服务的启动进程所占用的目录
lsof简介 lsof(list open files)是一个列出当前系统打开文件的工具.在linux环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件.所以 ...
- iPhone取消软件更新上边的1
去除设置的更新+1小红点提示主要分为越狱和非越狱设备两种方法. 越狱状态下方法: 首先将你的设备进行越狱: 越狱后安装ifile(这个自行搜索安装): 用ifile打开/System/Library/ ...
- [flag飞起]
重度Flag: Rush 未来程序・改 (note: 由于代码存放地址原因(物理)无法本周完成) 轻度Flag: 未来程序・改写完后刷QTREE与主席树 严重Flag: 计算几何...
- 谷歌、百度、1万ip能赚多少钱?1000IP能够值多少钱呢?
谷歌.百度.1万ip能赚多少钱?1000IP能够值多少钱呢? (2014-04-03 11:50:52) 转载▼ 标签: 广告联盟 百度联盟 谷歌联盟 ip赚钱 很多在人问:谷歌.百度:1 ...
- ASP.NET 画图与图像处理-如何直接输出到页面
有时候我们生成的图片并不需要保存到磁盘中,而是直接输出到页面,比如验证码.实时报表等,如何做呢?请参考如下: protected void Page_Load(object sender, E ...