wpf DoEvents
原文:wpf DoEvents 如果在执行一段卡UI的代码,这时如何让UI响应。如果存在代码需要获得依赖属性,那么代码就需要在UI线程执行,但是这时就会卡UI,为了让UI响应,所以就需要使用 先做一个例子让大家知道 这时点击确定可以看到,需要等待一些时间才可以响应界面 如果加上了 DoEvents 就可以看到下图的效果 在呆磨的程序做一些修改,请看代码 所以只需要在循环加上代码就可以了。可以复制下面的两个方法到需要使用让UI响应的地方,在需要的地方调用,使用的方法很简单。 建议在下面的地方使用: 请看一下底层的 会导致UI重绘的消息:0xC25A及0xC262 所以发送这个消息就可以让UI响应 这里的坑是 PushFrame 的坑,关于他的原理,请看 https://walterlv.github.io/post/dotnet/2017/09/26/dispatcher-push-frame.html 如果点击确定按钮之后,再次点击确定按钮,那么就会出现很多个重复的数。如果使用这个方法,那么需要禁用确定按钮,小心用户多次点击。 在使用方法的时候拖动窗口,可能让窗口卡死。 复现步骤: 修改上面呆磨代码,加上 但是这时使用 Alt+Tab 到其他窗口,然后回来,可以看到窗口正常 实际上尝试改变窗口大小也会让窗口卡死,请看WPF application intermittently hangs when using Dispatcher.Invoke and/or Dispatcher.PushFrame while user is resizing or draging window 我必须说,不仅是 OnLoad 会出现这些坑,在很多情况也会,但是我还不知道条件。 请把 接着把 下面的代码是创建一个 time 不停在里面使用 这时拖动窗口会出现冻结,和上面一样。 实际把上面代码的运算去掉也会冻住,但是我尝试10次,有2次在放开的时候才冻住。 实际上垃圾wr是不是要让开发者去写这样的方法?实际上垃圾wr已经做了这个东西,但是没有直接告诉开发者,请尝试使用下面的代码代替上面呆磨 关键就是 但是直接使用 实际上 最后的方法是在UI主线程执行的函数上添加 建议使用最后的方法,因为这个方法可以解决坑,而且使用简单 实际上,使用了上面无论哪个方法都不会让界面一直都响应,如果页面有一个循环的动画,就可以看到动画播放实际上有些卡,下面写一个呆磨就可以知道。在上面的界面添加下面的代码,不停做动画。 这时点击按钮,可以看到动画有些卡,点击窗口拖动就可以看到动画正常。 本文会经常更新,请阅读原文:
DoEvents来让UI响应。
首先需要知道,DoEvents是在 WinForm 有的,在 WPF 没有这个函数,但是可以自己写出来。DoEvents的作用,使用的呆磨很简单,请看代码<Window x:Class="ZuindmMbx.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ZuindmMbx"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListView ItemsSource="{Binding KatudefZubpobryk}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="确定" HorizontalAlignment="Left" Margin="424,292,0,0" VerticalAlignment="Top" Width="75" Click="Button_OnClick"/>
</Grid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public ObservableCollection<string> KatudefZubpobryk { get; set; } = new ObservableCollection<string>();
private void Button_OnClick(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 10; i++)
{
Foo(10);
KatudefZubpobryk.Add(i.ToString());
}
}
private void Foo(int n)
{
for (int i = 0; i < n; i++)
{
Foo(n - 1);
}
}
}


用法
private void Button_OnClick(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 10; i++)
{
Foo(10);
KatudefZubpobryk.Add(i.ToString());
DoEvents();
}
}
public static void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
private static Object ExitFrame(Object state)
{
((DispatcherFrame) state).Continue = false;
return null;
}
原理
PushFrameImpl 下面的代码有删减
存在的坑
OnLoaded,里面使用Dispatcher.Invoke或DoEvents,然后运行拖动窗口,这时窗口卡死 public MainWindow()
{
InitializeComponent();
DataContext = this;
Loaded += OnLoaded;
}
private async void OnLoaded(object sender, RoutedEventArgs e)
{
await Task.Delay(2000);
Dispatcher.Invoke(() => { }, DispatcherPriority.Background);
}
OnLoad 上其他坑
await Task.Delay(2000)换为Foo(10);进行一些计算,这时在软件启动的时候,尝试拖动窗口,可以看到窗口是没有显示内容,但是鼠标放开的时候,就可以看到界面显示。 private void OnLoaded(object sender, RoutedEventArgs e)
{
Foo(10);
Dispatcher.Invoke(() =>
{
}, DispatcherPriority.Background);
}
Invoke换为DoEvents,结果相同,在启动拖动窗口,窗口没有内容。使用 DispatcherTimer 出现窗口冻结
Dispatcher.Invoke public MainWindow()
{
InitializeComponent();
DataContext = this;
Loaded += OnLoaded;
DispatcherTimer time = new DispatcherTimer();
time.Interval = new TimeSpan(0, 0, 1);
time.Tick += Time_Tick;
time.Start();
}
private void Time_Tick(object sender, EventArgs e)
{
Foo(10);
Dispatcher.Invoke(() => { }, DispatcherPriority.Background);
}
推荐方法
private void Button_OnClick(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 10; i++)
{
Foo(10);
KatudefZubpobryk.Add(i.ToString());
Dispatcher.Invoke(() => { }, DispatcherPriority.Background);
}
}
Dispatcher.Invoke(() => { }, DispatcherPriority.Background);,这句代码就是在主线程插入一个Background 因为优先级,所以这时就可以让UI处理其他的输入

Dispatcher.Invoke代码太长,是不是可以使用比较简单的?实际上还是有的,请看代码。 private async void Button_OnClick(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 10; i++)
{
Foo(10);
KatudefZubpobryk.Add(i.ToString());
await System.Windows.Threading.Dispatcher.Yield();
}
}
System.Windows.Threading.Dispatcher.Yield这个方法的实现和Dispatcher.Invoke(() => { }, DispatcherPriority.Background一点也不同,他使用的是 async 以及其他我还不知道怎么说的科技。async和直接使用Dispatcher.Yield就可以在循环中让UI响应。不会在循环中让UI卡住。 <Grid>
<Grid.Triggers>
<EventTrigger RoutedEvent="Grid.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<DoubleAnimation Storyboard.TargetName="T" Storyboard.TargetProperty="Angle" From="0" To="360" Duration="0:0:1"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Grid x:Name="G" Background="#565656" Width="200" Height="200"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RenderTransform>
<RotateTransform x:Name="T" CenterX="100" CenterY="100" Angle="0"></RotateTransform>
</Grid.RenderTransform>
</Grid>
</Grid>
https://lindexi.gitee.io/lindexi/post/wpf-DoEvents.html
,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用
知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议
进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:
https://lindexi.gitee.io
),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请
与我联系
。
wpf DoEvents的更多相关文章
- 2018-8-10-wpf-DoEvents-
title author date CreateTime categories wpf DoEvents lindexi 2018-08-10 19:16:51 +0800 2018-2-13 17: ...
- 2018-2-13-wpf-使用-Dispatcher.Invoke-冻结窗口
title author date CreateTime categories wpf 使用 Dispatcher.Invoke 冻结窗口 lindexi 2018-2-13 17:23:3 +080 ...
- WPF实现DoEvents
WPF实现DoEvents 原创 2011年06月30日 12:23:00 标签: wpf / object 2550 static void DoEvents() { DispatcherFrame ...
- WPF多线程演示
WPF中的几种处理线程的工作方式: 1.简单的DispatcherTimer类似Timer控件 2.需要处理UI同步时,Dispatcher DispatcherOpertion 3.增强的Threa ...
- WPF刷新界面之坎坷路
WPF刷新界面之坎坷路 项目需要一个硬件检测功能,需要用到界面刷新,刚开始想用个定时器,对检测过的硬设定时添加后刷新界面. 但是很遗憾,定时器并不能进行刷新.后台检测List数据里面已经添加了很多了很 ...
- 【WPF】DispatcherFrame 是个啥玩意儿
对于 WPF 的线程模型,Dispatcher 对象相信各位大伙伴已经不陌生,尤其是跨线程更新UI的时候,都会用它来调度消息.与 Dispatcher 对象有关的,还有一个叫 DispatcherFr ...
- Self-Host c#学习笔记之Application.DoEvents应用 不用IIS也能執行ASP.NET Web API
Self-Host 寄宿Web API 不一定需要IIS 的支持,我们可以采用Self Host 的方式使用任意类型的应用程序(控制台.Windows Forms 应用.WPF 应用甚至是Wind ...
- DataGrid列表信息保存为EXCEL到指定的路径 ---------继续DataGrid在WPF的数据绑定
一.许多WPF或者Winform程序在保存数据时,会以EXCEL或者文本的形式展现可视化界面的数据,本文就简单介绍下将DataGrid列表信息保存为EXCEL到指定的路径下,例子很简单,用的着的直接用 ...
- 深入了解 WPF Dispatcher 的工作原理(PushFrame 部分)
在上一篇文章 深入了解 WPF Dispatcher 的工作原理(Invoke/InvokeAsync 部分) 中我们发现 Dispatcher.Invoke 方法内部是靠 Dispatcher.Pu ...
随机推荐
- 微信支付v2开发(7) 告警通知
本文介绍微信支付中如何获得告警通知. 一.告警通知 为了及时通知商户异常,提高商户在微信平台的服务质量.微信后台会向商户推送告警通知,包括发货延迟.调用失败.通知失败等情况,通知的地址是商户在申请支付 ...
- JS学习笔记 - fgm练习 2-5 - 函数传参 设置div样式
练习地址:http://www.fgm.cc/learn/lesson2/05.html <script> window.onload = function(){ var oDiv = d ...
- ZOJ 1586 QS Network MST prim水题
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=586 题目大意: QS是一种生物,要完成通信,需要设备,每个QS需要的设备的价格 ...
- GO语言学习(四)GO语言语言结构
Go Hello World 实例 Go 语言的基础组成有以下几个部分: 包声明 引入包 函数 变量 语句 & 表达式 注释 接下来让我们来看下简单的代码,该代码输出了"Hello ...
- linux终端下一些“风骚”的按键操作及Linux终端命令
linux终端下一些"风骚"的按键操作 <backspace> 删除 <ctrl-l> 清空屏幕, 相当于clear tab ...
- Swift 带有动画效果的TabBarItem
额...貌似挺长时间没有总结新知识了,最近在看swift,之前swift刚出来的时候大体看了一遍,后来时间长了没看加之swift2.0做了比较大的调整,公司项目也不是用swift写的,也就没怎么看了, ...
- 【solr基础教程之二】索引 分类: H4_SOLR/LUCENCE 2014-07-18 21:06 3331人阅读 评论(0) 收藏
一.向Solr提交索引的方式 1.使用post.jar进行索引 (1)创建文档xml文件 <add> <doc> <field name="id"&g ...
- oracle 之 COMMENT 分类: H2_ORACLE 2014-04-24 15:30 386人阅读 评论(0) 收藏
http://blog.csdn.net/liguihan88/article/details/3002403 无疑注释现在都被大家接受和认可,在大家编程用的IDE中都提供或有第三方插件来支持提取注释 ...
- linux ps命令,查看某进程cpu和内存占用率情况, linux ps命令,查看进程cpu和内存占用率排序。 不指定
背景:有时需要单看某个进程的CPU及占用情况,有时需要看整体进程的一个占用情况.一. linux ps命令,查看某进程cpu和内存占用率情况[root@test vhost]# ps auxUSER ...
- Android中的动画详解系列【4】——Activity之间切换动画
前面介绍了Android中的逐帧动画和补间动画,并实现了简单的自定义动画,这一篇我们来看看如何将Android中的动画运用到实际开发中的一个场景--Activity之间跳转动画. 一.定义动画资源 如 ...