wpf同步与异步执行技术
Wpf的同步与异步执行技术
在WPF, 创建的线程DispatcherObject才能访问该对象。例如,从主UI 线程派生的后台线程不能更新的内容Button UI 线程上创建。为了使后台线程访问的内容属性的Button, ,后台线程必须将工作委托给Dispatcher与UI 线程关联。这通过使用实现Invoke 或BeginInvoke。 Invoke 是同步
和BeginInvoke是异步的。该操作将添加到事件队列的Dispatcher指定DispatcherPriority。
1、同步
Invoke 是同步操作;因此,控件不会返回对调用对象直到回调返回后。
同步执行
this.Dispatcher.Invoke(new Action(() => {
//Do Something
//更新UI操作
}));
例如:
如果是窗体本身可使用类似如下的代码:
那么假如是在一个公共类中弹出一个窗口、播放声音等呢?这里我们可以使用:System.Windows.Application.Current.Dispatcher,如下所示
2、异步执行
案例:Wpf 执行异步操作时显示Gif动画。
1)在按钮方法中创建并执行线程:
2)定义异步操作
3)在异步操作中异步修改UI中的控件属性。且该操作中不能执行耗时多的操作,以防UI卡顿。本质是进行两次异步操作。
private void btnRun_Click(object sender, RoutedEventArgs e)
{
startgif.Visibility = Visibility.Visible;
btnClear.IsEnabled = false;
btnRun.IsEnabled = false;
lblShow.Content += "开始系统检查......\n";
//记录操作时间
lblShow.Content += "in btnRun_Click " + DateTime.Now.ToString() + "\n";
//在新线程中异步执行系统检查
Thread newThread = new Thread(GetSystemCheckResult); //创建线程,不带参数
newThread.Start(); //执行线程
//记录操作时间
lblShow.Content += "out btnRun_Click " + DateTime.Now.ToString() + "\n";
}
1. Thread newThread = new Thread(new ParameterizedThreadStart(GetResult)); //可传入参数的线程
2. newThread.Start(inputNumber); //inputNumber为传的参数
1.private void GetResult(object inputNumber) //使用参数inputNumber进行异步操作
2.{
3.double result=CalcSum((Int64)inputNumber);
4.this.Dispatcher.BeginInvoke((Action)delegate()
5. {
6.//this.textBox2.Text = CalcSum((Int64)inputNumber).ToString();
7.this.textBox2.Text = result.ToString();
8. });
9.}
C# 多线程用委托实现异步_调用委托的BeginInvoke和EndInvoke方法
年12月04日15:38:18
?标签:
?异步/
?线程/
?delegate
?5173
1.C#中的每一个委托都内置了BeginInvoke和EndInvoke方法,如果委托的方法列表里只有一个方法,那么这个方法就可以异步执行(不在当前线程里执行,另开辟一个线程执行)。委托的BeginInvoke和EndInvoke方法就是为了上述目的而生的。
2.原始线程发起了一个异步线程,有如下三种执行方式:
方式一:等待一直到完成,即原始线程在发起了异步线程以及做了一些必要处理之后,原始线程就中断并等待异步线程结束再继续执行。
方式二:轮询,即原始线程定期检查发起的线程是否完成,如果没有则可以继续做一些其它事情。
方式三:回调,即原始线程一直执行,无需等待或检查发起的线程是否完成。在发起的线程执行结束,发起的线程就会调用用户定义好的回调方法,由这个回调方法在调用EndInvoke之前处理异步方法执行得到的结果。
3.一个控制台小程序,使用了上面三种方式,执行结果如下:
4.代码:
[csharp]view plain copy
https://www.360docs.net/doc/a14431899.html,ing System;
https://www.360docs.net/doc/a14431899.html,ing System.Collections.Generic;
https://www.360docs.net/doc/a14431899.html,ing System.Linq;
https://www.360docs.net/doc/a14431899.html,ing System.Runtime.Remoting.Messaging;
https://www.360docs.net/doc/a14431899.html,ing System.Text;
https://www.360docs.net/doc/a14431899.html,ing System.Threading;
7.
https://www.360docs.net/doc/a14431899.html,space用委托实现异步_调用BeginInvoke和EndInvoke方法
9.{
10.
11.delegate long MyDel(int first,int second); //声明委托类型
12.
13.class Program
14. {
15.//声明委托类型的方法
16.static long Sum(int x,int y)
17. {
18. Console.WriteLine(" Inside Sum");
19. Thread.Sleep(200);
20.return x + y;
21. }
22.
23.//定义当异步线程执行结束要执行的回调函数
24.static void CallWhenDone(IAsyncResult iar)
25. {
26. Console.WriteLine(" Inside CallWhenDone");
27. AsyncResult ar = (AsyncResult)iar;
28. MyDel del = (MyDel)ar.AsyncDelegate;
29.
30.long result = del.EndInvoke(iar);
31. Console.WriteLine(" The result is {0}.", result);
32. }
33.
34.//方式一:等待异步线程结束,再继续执行主线程
35.static void WaitUntilDoneStyle()
36. {
37. MyDel del = new MyDel(Sum);
38. Console.WriteLine("Before BeginInvoke");
39. IAsyncResult iar = del.BeginInvoke(3, 5, null, null); //开始异步调用
40. Console.WriteLine("After BeginInvoke");
41.
42. Console.WriteLine("Doing main stuff before");
43.long result = del.EndInvoke(iar); //等待异步线程结束并获取结果
44. Console.WriteLine("After EndInvoke:{0}", result);
45. Console.WriteLine("Doing main stuff after");
46. }
47.
48.//方式二:轮询检查异步线程是否结束,若没结束则执行主线程
49.static void LunXunPollingStyle()
50. {
51. MyDel del = new MyDel(Sum);
52. Console.WriteLine("Before BeginInvoke");
53. IAsyncResult iar = del.BeginInvoke(3, 5, null, null); //开始异步调用
54. Console.WriteLine("After BeginInvoke");
55.
56.while (!iar.IsCompleted)
57. {
58. Console.WriteLine("Not Done.Doing main stuff");
59.//继续处理主线程事情
60.for (long i = 0; i < 10000000; i++)
61. ;
62. }
63. Console.WriteLine("Done");
64.long result = del.EndInvoke(iar); //调用EndInvoke来获取结果并进行清理
65. Console.WriteLine("Result: {0}", result);
66. }
67.
68.//方式三:回调方式,当异步线程结束,系统调用用户自定义的方法来处理结果(包括调用委托的EndInvoke方法)
69.static void CallBackStyle()
70. {
71. MyDel del = new MyDel(Sum);
72. Console.WriteLine("Before BeginInvoke");
73. IAsyncResult iar = del.BeginInvoke(3, 5, new AsyncCallback(CallWhenDone), null);
74. Console.WriteLine("After BeginInvoke");
75. Console.WriteLine("Doing more work in main.");
76. Thread.Sleep(500);
77. Console.WriteLine("Done with Main. Exiting.");
78. }
79.
80.static void Main(string[] args)
81. {
82.//方式一:等待异步线程结束,再继续执行主线程
83. Console.WriteLine();
84. Console.WriteLine("--------方式一:等待异步线程结束,再继续执行主线程--------");
85. WaitUntilDoneStyle();
86.
87.//方式二:轮询检查异步线程是否结束,若没结束则执行主线程
88. Console.WriteLine();
89. Console.WriteLine("--------方式二:轮询检查异步线程是否结束,若没结束则执行主线程--------");
90. LunXunPollingStyle();
91.
92.//方式三:回调方式,当异步线程结束,系统调用用户自定义的方法来处理结果(包括调用委托的EndInvoke方法)
93. Console.WriteLine();
94. Console.WriteLine("--------方式三:回调方式,当异步线程结束,系统调用用户自定义的方法来处理结果(包括调用委托的EndInvoke方法)----
----");
95. CallBackStyle();
96. }
97.
98.
99. } 100.}
Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析
年09月15日18:06:59
?标签:
?thread/
?c#/
?c#4.0/
?异步/
?delegate
?17372
前段时间,公司同事开发了一个小工具,在工具执行过程中,UI界面一直处于卡死状态。
通过阅读代码发现,主要是由于Dispatcher.BeginInvoke()方法使用不当导致的。
本文将通过一个WPF模拟程序来演示一下界面卡死的现象,并通过修改代码来解决界面卡死的问题。
希望通过对本文的学习,大家能对Dispatcher.BeginInvoke()方法有一个新的认识。
文章开篇直接给出界面卡死的示例代码。
示例WPF程序,用来计算1~n的和值,这里的n可以是1亿~25 亿之间的某个值,通过界面录入,结果显示在n输入框后面的文本框中,既然是WPF程序,代码包含xaml及cs代码两部分,本文一并给出。
以下为cs代码:
[csharp]view plain copy
https://www.360docs.net/doc/a14431899.html,ing System;
https://www.360docs.net/doc/a14431899.html,ing System.Windows;
https://www.360docs.net/doc/a14431899.html,ing System.Threading;
4.
https://www.360docs.net/doc/a14431899.html,space DispatcherExample
6.{
7.///
8./// MainWindow.xaml 的交互逻辑
9.///
10.public partial class MainWindow : Window
11. {
12.public MainWindow()
13. {
14. InitializeComponent();
15. }
16.
17.private void button1_Click(object sender, RoutedEventArgs e)
18. {
19. Int64 inputNumber;
20.if (!Int64.TryParse(this.textBox1.Text, out inputNumber))
21. {
22. MessageBox.Show("请输入1亿-10亿皑间的整型数据!");
23.return;
24. }
25.if (inputNumber > 2500000000 || inputNumber<100000000)
26. {
27. MessageBox.Show("请输入1亿-10亿间的整型数据!");
28.return;
29. }
30. Thread newThread = new Thread(new ParameterizedThreadStart(GetResult));
31. newThread.Start(inputNumber);
32. }
33.
34.private void GetResult(object inputNumber)
35. {
36.this.Dispatcher.BeginInvoke((Action)delegate()
37. {
38.this.textBox2.Text = CalcSum((Int64)inputNumber).ToString();
39. });
40. }
41.
42.private double CalcSum(Int64 inputNumber)
43. {
44.double sum=0;
45.for (int i = 0; i < inputNumber; i++)
46. {
47. sum +=i;
48. }
49.return sum;
50. }
51. }
52.}
以下为xaml代码:
[html]view plain copy
1. 2.xmlns="https://www.360docs.net/doc/a14431899.html,/winfx/2006/xaml/presentation" 3.xmlns:x="https://www.360docs.net/doc/a14431899.html,/winfx/2006/xaml" 4.Title="求(和)你亿万次~~"Height="350"Width="525"ResizeMode="NoResize"> 5. 6. 7. 8. 9. 10.
执行程序,界面如下:
输入2500000000,点击“计算和值”按钮,程序开始计算和值,界面卡死,无法再操作该程序(如移动位置或重新输入等)。
分析代码,发现问题应该出在下面的代码中,因为该部分代码中存在调用UI主线程的操作,此种操作不当往往会导致界面卡死的现象。[csharp]view plain copy
1.private void GetResult(object inputNumber)
2.{
3.this.Dispatcher.BeginInvoke((Action)delegate()
4. {
5.this.textBox2.Text = CalcSum((Int64)inputNumber).ToString();
6. });
7.}
那么,问题到底出在哪里呢?
要想弄清楚这点,还得了解一下Dispatcher.BeginInvoke()方法。
MSDN上对Dispatcher.BeginInvoke方法的解释如下:
Dispatcher.BeginInvoke 方法 (Action)
在与 Dispatcher关联的线程上异步执行指定的委托。
那么本实例中,与 Dispatcher关联的线程是什么呢?
要想弄清楚这点很简单。只要知道this.Dispatcher.BeginInvoke()中的this指的是什么就可以了。在Visual studio中将鼠标至于th is上,发现this指的是当前的窗体类(如下图),即程序的主线程。
Unity3D游戏开发之添加背景图片
Unity3D游戏开发之添加背景图片 每个游戏在开始前都有登陆注册界面,但是登陆注册界面不只是几个Label,几个Button 组成的,还要有背景图片,可以怎么我们在只学习了GUI的前提下,怎么添加背景图片呢?我今天主要的任务就是做登陆注册界面,登陆注册界面要想好看点就要有背景图片,在unity中添加背景图片有两种方法,一种是通过代码来完成,还有一种是手动添加,我们都 来看看吧。 先来看看效果图: 通过代码完成: 1.//声明一张图片 2.public Texture2D img; 3. 4.//通过OnGUI方法执行下面操作 5.void OnGUI() 6.{ 7. string aa = ""; 8. 9. //构造一个空的GUIStyle 10. GUIStyle bb = new GUIStyle(); 11. 12. //设置bb正常显示时是背景图片
13. bb.normal.background = img; 14. https://www.360docs.net/doc/a14431899.html,bel(new Rect(0, 0, 1370, 780), aa, bb); 15.} 手动添加: 1、先创建一个新的摄像机,命名为Background Camera; 2、新建一个GUI Texture,命名为Background Image; 3、在Background Image的Inspector面板【狗刨学习网】中点击Layer下拉窗口, 选择“Add Layer”添加一个新的层名称为“Background Image”; 4、选中Background Image,做如下操作: 5、该GameObject的Layer值设置为之前你添加的Background Image; 6、选中Background Camera,进行如下操作:
Java程序添加漂亮背景图片的方法
整理后可执行代码如下: importjava.awt.*; importjavax.swing.*; public class TestBackgroundColor extends JFrame { public static void main(String[] args) { // TODO Auto-generated method stub TestBackgroundColortbc = new TestBackgroundColor(); tbc.setVisible(true); } privateJPanelimagePanel; privateImageIcon background; publicTestBackgroundColor() { background = new ImageIcon("渐变背景14.png");//背景图片 JLabel label = new JLabel(background);//把背景图片显示在一个标签里面 //把标签的大小位置设置为图片刚好填充整个面板 label.setBounds(0,0,background.getIconWidth(),background.getIconHeight()); //把内容窗格转化为JPanel,否则不能用方法setOpaque()来使内容窗格透明 imagePanel = (JPanel)this.getContentPane(); imagePanel.setOpaque(false); //内容窗格默认的布局管理器为BorderLayout imagePanel.setLayout(new FlowLayout()); imagePanel.add(new JButton("测试按钮")); this.getLayeredPane().setLayout(null); //把背景图片添加到分层窗格的最底层作为背景 this.getLayeredPane().add(label,new Integer(Integer.MIN_VALUE)); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(background.getIconWidth(),background.getIconHeight()); this.setVisible(true);
(完整word版)修改BUTTON背景颜色
//定义色彩 const COLORREF CLOUDBLUE = RGB(128, 184, 223); const COLORREF WHITE = RGB(255, 255, 255); const COLORREF BLACK = RGB(1, 1, 1); const COLORREF DKGRAY = RGB(128, 128, 128); const COLORREF LTGRAY = RGB(192, 192, 192); const COLORREF YELLOW = RGB(255, 255, 0); const COLORREF DKYELLOW = RGB(128, 128, 0); const COLORREF RED = RGB(255, 0, 0); const COLORREF DKRED = RGB(128, 0, 0); const COLORREF BLUE = RGB(0, 0, 255); const COLORREF DKBLUE = RGB(0, 0, 128); const COLORREF CYAN = RGB(0, 255, 255); const COLORREF DKCYAN = RGB(0, 128, 128); const COLORREF GREEN = RGB(0, 255, 0); const COLORREF DKGREEN = RGB(0, 128, 0); const COLORREF MAGENTA = RGB(255, 0, 255); const COLORREF DKMAGENTA = RGB(128, 0, 128); //在.h文件定义彩色按钮 CColorButton m_btnUp; //在.cpp文件调用函数着色 VERIFY(m_btnUp.Attach(IDC_BUTTON1, this, RED, WHITE, DKRED)); //CColorButton 类原型 //colorbtn.h #ifndef __COLORBTN_H__ #define __COLORBTN_H__ class CColorButton : public CButton { DECLARE_DYNAMIC(CColorButton) public: CColorButton(); virtual ~CColorButton(); BOOL Attach(const UINT nID, CWnd* pParent, const COLORREF BGColor = RGB(192, 192, 192), // gray button const COLORREF FGColor = RGB(1, 1, 1), // black text const COLORREF DisabledColor = RGB(128, 128, 128), // dark gray disabled text const UINT nBevel = 2
给电脑的右键菜单添加背景图片
给电脑的右键菜单添加背景图片 有了电脑,要让电脑好看些,这就需要多多美化电脑了。现在说下,怎样给右键菜单添加背景图片,你可以给自己的右键背景图片修改成美女哦。那多爽眼啊。嘻嘻。 开始: 第一步,下载动态链接库文件 先下载并解压添加右键菜单背景图片动态链接库文件(下载地址 https://www.360docs.net/doc/a14431899.html,/soft/utilitie/systems/133/407633.shtml )。打开解压文件夹,里面的“ContextBG.dll”文件就是即将用到的动态链接库文件。为方便使用,将此文件复制到“C:\\Windows”文件夹中。 第二步,添加右键弹出菜单背景图片 依次单击“开始”→“运行”,打开“运行”对话框。在“运行”对话框中输入 “regsvr32 c:\\windows\\ContextBG.dll”(不包括引号),单击确定,弹出一个regsvr32加载成功的对话框。这时,再右击桌面上的图标,你就发现弹出菜单已经有虎哥的背景图片了(图1)。
小贴士:遗憾的是,右击我的电脑、盘符等系统图标弹出菜单不能出现背景图片。第三步,取消右键菜单背景图片 如果要取消右键菜单背景图片,同样在“运行”对话框中输入“regsvr32 /u c:\\windows\\ContextBG.dll”,单击确定,出现加载成功对话框,完成对图片的卸载。 如果看倦了虎哥的图片该怎样更换呢?你可以通过附带下载的ResHacker 工具软件来修改“ContextBG.dll”库文件进行图片的更换。 打开ResHacker工具软件,依次单击“文件→打开”,弹出打开文件对话框,指定并打开C盘Windows文件夹下的“ContextBG.dll”动态链接库文件。然后,单击“操作”菜单下的“替换位图”命令,弹出“替换位图”对话框(图2)。在对话框的右上角,可以清楚地看到虎哥的图片,单击“打开新位图文件”按钮,弹出“打开”文件对话框,指定打开事先准备好的一张位图图片(*.bmp格式图片),单击“替换”按钮完成图片替换。最后,单击“文件”菜单中“保存”命令,保存替换图片后的动态链接库文件。
给按钮添加背景图片
package background; import java.awt.Container; import java.awt.Graphics; import java.awt.Image; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class JpanelBackgroundDemo extends JFrame{ MyPanel panel; JButton btn; Container c; public JpanelBackgroundDemo(){ setVisible(true); setSize(400,400); setLayout(null);// 不使用任何布局 c = getContentPane(); panel = new MyPanel(new ImageIcon("./src/images/chenhe.png").getImage()); panel.setBounds(0, 0, 300, 300); c.add(panel); btn = new JButton("测试按钮"); panel.add(btn); } public static void main(String[] args) { new JpanelBackgroundDemo(); } } // 重写容器类比如JPanel类的PaintComponent()方法 class MyPanel extends JPanel{ Image img;
qss美化___按钮
Qt开发界面程序时为按钮控件添加背景图片 Qt本身直接创建的按钮看起来有些单调,如,当然,程序员可以在程序代码里通过写相关的setStyle类的函数来自定义按钮样式,如设置颜色、形状等。但有时这些样式仍不能满足客户的特殊需求,这就需要为按钮添加背景图片。Qt自身支持的强大的qss美化文件为我们美化界面提供了极大方便,本文就最常用、简单的按钮美化给出简单教程。 1.首先,我们需要自己新建一个文本文件,写入以下内容: QPushButton#MyBtn{ border-image:url(:/my_ObjectName/Resources/ Normal/btn_Pic.bmp); } QPushButton# MyBtn:hover{ border-image:url(:/my_ObjectName /Resources/ Go/ btn_Pic.bmp); } QPushButton# MyBtn:pressed{ border-image:url(:/my_ObjectName /Resources/ Press/ btn_Pic.bmp); } QPushButton# MyBtn:!enabled{ border-image:url(:/my_ObjectName /Resources/ Null/ btn_Pic.bmp); } 将文件保存为my_qssFile.qss (注意:后缀是.qss),并将该文件放在你工程源代码的那个文件夹的目录下面。 说明:Normal文件夹下存放的是按钮正常状态下的背景图片,Go文件夹下存放的是鼠标经过该按钮时的按钮背景图片,Press文件夹下存放鼠标点击按下时的背景图片,Null文件夹下存放该按钮不可用时(setEnabled(false))的背景图片. 2.以记事本方式打开该目录下的.qrc文件(注意:该文件是建立工程时,系统自动生成的,不需要你改名字),在 前回车新建一行,在该行写如下代码:
MFC添加背景图片
问题 有的程序员希望在自己的应用程序中以有趣味的位图来代替对话框中令人讨厌的灰色背景,希望位图在对话框中看起来象墙纸而且并不影响对话框中的控制或静态文本的显示。 许多程序员找不到一个改变窗口背景的简单方法,是否有方法利用Windows API 函数来改变对话框的背景为某个位图呢? 方法 改变对话框的背景为某个位图并不困难,关键是需要清楚对话框和窗口是如何设置背景颜色的,以及程序员应该如何修改对话框和窗口改变显示的行为。 当Windows 准备改变对话框背景的颜色时,通常发送两个消息给对话框。第一个消息是WM_ERASEBKGND,此消息指示对话框绘制对话框的背景颜色,以“抹去”屏幕上对话框显示区域的任何显示。 第二个消息是WM_CTLCOLOR,发送此消息给对话框或窗口来表示Windows 需要知道对话框中控制的颜色。 在本节中,将重置对消息WM_ERASEBKGND 的处理,以便将位图绘制在窗口的背景上。另外,将重置对消息WM_CTLCOLOR 的处理,以避免对话框中的控制“剪补”位图。最后的结果是对话框的背景位图绘制在对话框背景上,控制在背景位图的“上面”。 步骤 按照下列步骤实现一个例子程序。运行此例子程序,选择菜单Dialog 和菜单项Bitmap Background,将弹出一个对话框,显示背景位图和几个控制。 实现例子程序的具体步骤如下: 1.在Visual C++中,利用AppWizard 创建新的项目文件,并命名此项目文件为 Ld145。 2.进入资源编辑器并创建新的对话框模板。在对话框中,添加几个静态文本域和编辑域,以及几个单选按钮和列表框。对话框的实际组成并不重要,只要能够覆盖部分位图就可以了。 3.选择ClassWizard,为刚创建的对话框模板创建对话框类,新类命名为 CBitma PB kgdDlg。 4.在资源编辑器中创建新的位图。 5.进入ClassWizard,从下拉列表中选择CBitmapBkgdDlg,从对象列表中选择对象CBitmapBkgdDlg,从消息列表中选择消息WM_INITDIALOG,点击按钮Add Function,在CBitmapBkgdDlg 的方法OnInitDialog 中添加下列代码: BOOL CBitmapBkgdDlg::OnInitDialog() { CBitmap * pBmpOld; RECT rectClient; VERIFY(m_brush=(HBRUSH)GetStockObject(HOLLOW_BRUSH)); VERIFY(m_Bitmap.LoadBitmap(IDB_BITMAP1)); m_Bitmap.GetObject(sizeof(BITMAP),&m_bmInfo);
QT 对话框添加背景图片的方法
QT 对话框添加背景图片的方法 1. QPalette的方法 #include
Android使用xml改变button背景图片
Android使用xml改变button背景图片 这篇文章我们使用Android XML来改变各种按钮状态(获得焦点、获得焦点并按下、失去焦点、默认)时的背景图,首先我们自己定义一个imgbutton.xml代码: