单线程的winfom程序中,设置一个控件的值是很easy的事情,直接 this.TextBox1.value = "Hello World!";就搞定了,但是如果在一个新线程中这么做,比如:
private void btnSet_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(SetTextBoxValue));
//当然也可以用匿名委托写成Thread t = new Thread(SetTextBoxValue);
t.Start("Hello World");
}
void SetTextBoxValue(object obj)
{
this.textBox1.Text = obj.ToString();
}
运行时,会报出一个无情的错误:
线程间操作无效: 从不是创建控件“textBox1”的线程访问它。
究其原因,winform中的UI控件不是线程安全的,如果可以随意在任何线程中改变其值,你创建一个线程,我创建一个线程,大家都来抢着更改"TextBox1"的值,没有任何秩序的话,天下大乱...
解决办法:
1.掩耳盗铃法(Control.CheckForIllegalCrossThreadCalls = false;)--仅Winform有效
using System;
using System.Threading;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;//这一行是关键
}
private void btnSet_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(SetTextBoxValue));
t.Start("Hello World");
}
void SetTextBoxValue(object obj)
{
this.textBox1.Text = obj.ToString();
}
}
}
设置Control.CheckForIllegalCrossThreadCalls为false,相当于不检测线程之间的冲突,允许各路线程随便乱搞,当然最终TextBox1的值到底是啥难以预料,只有天知道,不过这也是最省力的办法
2.利用委托调用--最常见的办法(仅WinForm有效)
using System;
using System.Threading;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
delegate void D(object obj);
public Form1()
{
InitializeComponent();
}
private void btnSet_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(SetTextBoxValue));
t.Start("Hello World");
}
void SetTextBoxValue(object obj)
{
if (textBox1.InvokeRequired)
{
D d = new D(DelegateSetValue);
textBox1.Invoke(d,obj);
}
else
{
this.textBox1.Text = obj.ToString();
}
}
void DelegateSetValue(object obj)
{
this.textBox1.Text = obj.ToString();
}
}
}
3.利用SynchronizationContext上下文 -- 最神秘的方法(Winform/Silverlight能用)
之所以说它神秘,是因为msdn官方对它的解释据说也是不清不楚
using System;
using System.Threading;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnSet_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(Run));
MyPram _p = new MyPram() { context = SynchronizationContext.Current, parm = "Hello World" };
t.Start(_p);
}
void Run(object obj)
{
MyPram p = obj as MyPram;
p.context.Post(SetTextValue, p.parm);
}
void SetTextValue(object obj)
{
this.textBox1.Text = obj.ToString();
}
}
public class MyPram
{
public SynchronizationContext context { set; get; }
public object parm { set; get; }
}
}
4.利用BackgroundWorker --最偷懒的办法(Winform/Silverlight通用)
BackgroundWorker会在主线程之外,另开一个后台线程,我们可以把一些处理放在后台线程中处理,完成之后,后台线程会把结果传递给主线程,同时结束自己。
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnSet_Click(object sender, EventArgs e)
{
//MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
using (BackgroundWorker bw = new BackgroundWorker())
{
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync("Hello World");
}
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
//MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
e.Result = e.Argument;//这里只是简单的把参数当做结果返回,当然您也可以在这里做复杂的处理后,再返回自己想要的结果(这里的操作是在另一个线程上完成的)
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//这时后台线程已经完成,并返回了主线程,所以可以直接使用UI控件了
this.textBox1.Text = e.Result.ToString();
//MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
}
}
}
5.Dispatcher.BeginInvoke--Silverlight的独门秘籍
代码
using System.Threading;
using System.Windows.Controls;
using System.Windows.Input;
namespace ThreadTest
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Thread t = new Thread(SetTextValue);
t.Start("Hello World");
}
void SetTextValue(object text)
{
this.Dispatcher.BeginInvoke(() => { this.txt.Text = text.ToString(); });
}
}
}
分享到:
相关推荐
WinForm C# 多线程编程并更新界面(UI) 在 Windows 窗体应用程序中,多线程编程是非常重要的,这样可以提高应用程序的响应速度和用户体验。下面我们来讨论如何在 WinForm 中使用 C# 实现多线程编程并更新界面(UI...
总结来说,C# WinForm应用中的跨线程修改UI是通过异步编程和UI线程同步机制来实现的。`Task`用于执行后台任务,`MethodInvoker`则帮助在主线程中安全地更新UI,确保程序的稳定性和正确性。这个实例提供了一个实用的...
本文将深入探讨如何在C# WinForm中利用多线程实现界面快速刷新。 首先,我们需要理解Windows Forms(WinForm)应用程序的基础架构。默认情况下,WinForm应用程序有一个主线程,负责处理所有UI事件,如用户交互和...
在C# WinForm应用开发中,我们经常遇到需要在后台执行耗时操作,同时保持用户界面(UI)的响应性。这就是异步编程的核心应用场景。VS2013支持.net框架4.0,该版本引入了Task类和异步编程模型,使得处理这种需求变得...
在C#编程中,开发Windows桌面应用程序时,我们经常遇到多线程操作,尤其是在WinForms应用中。当后台线程需要更新用户界面(UI)时,由于.NET Framework的安全机制,直接操作UI控件会引发“Cross-thread operation ...
本资源提供了"C# WinForm多线程防止界面假死"的源码示例,帮助初学者理解和实践如何在WinForm应用中正确使用多线程。 首先,理解WinForm中的主线程与工作线程的区别至关重要。主线程是负责更新和绘制UI的线程,而...
《C# WinForm高级设计(工控与界面)》是一个深入探讨C# Windows应用程序开发的资源集合,尤其关注WinForm技术在工控和用户界面设计中的应用。这个压缩包包含了丰富的学习材料,可以帮助开发者提升在C# WinForm平台...
总结起来,解决Winform界面卡死问题的关键在于理解和运用多线程以及委托。通过将耗时任务放到后台线程,并使用委托确保UI更新在主线程执行,可以有效避免界面卡死,提升用户体验。同时,理解.NET框架中的线程同步...
总的来说,C# Winform多线程下载的实现涉及到多线程编程、Winform UI交互以及HTTP文件下载,这些是开发高效桌面应用程序必备的基础技能。通过这样的实践,开发者能够提升处理并发任务的能力,优化用户体验,尤其是在...
特别是在C#多线程编程中,子线程更新UI控件是一个常见的问题。本文将总结C#子线程更新UI控件的方法,介绍两种常用的方法,以便读者更好地理解和应用。 一、使用控件自身的Invoke/BeginInvoke方法 Control类实现了...
在C#编程中,Windows Forms(Winform)应用程序经常需要处理多线程,以实现并发操作,提高程序的响应性和效率。本项目“C# Winform动态创建和关闭多线程源码 可运行”提供了一个完整的解决方案,适用于Visual Studio...
在多线程编程中,主线程通常是创建UI并处理用户交互的线程,而后台线程则用于执行耗时任务。.NET Framework中的控件都是线程感知的,它们只能在其创建的线程(UI线程)中被修改,这就是所谓的线程亲和性。 为了实现...
本文将详细讲解如何在WinForm应用中实现多线程异步更新UI。 1. **线程基础知识**:在Windows操作系统中,每个应用程序都有一条主线程,负责创建和管理UI。其他线程称为工作线程,用于执行非UI相关的任务。主线程与...
通过这个C# WinForm多线程模板示例,开发者可以学习到如何优雅地处理后台任务,保持UI响应,并理解多线程编程中的核心概念。同时,了解如何利用线程同步机制以及异步编程模型,能够更好地优化应用程序的性能和用户...
在`WinformThreadApp3`项目中,这些概念被集成在一起,展示了如何在Winform应用中同时使用异步编程、多线程和线程池进行数据库操作和日志记录。通过对这些技术的合理应用,开发者可以创建出高效、响应性强的桌面应用...
在C#编程环境中,开发Windows...总结,C#中的WinForm和WinCE多线程编程涉及创建线程、同步机制、UI更新、异常处理和性能优化等多个方面。通过深入理解这些概念和实践,开发者可以构建出高效、响应性的跨平台应用程序。
总结来说,C# Winform利用TCPListener和TCPClient进行网络通信,结合多线程处理客户端和服务器端的数据交互,委托确保了在安全的上下文中更新UI,从而实现了一个完整的聊天模式。这个过程中,不仅学习了网络编程的...
8. **多线程应用**:Winform支持多线程编程,可以创建新的线程执行耗时操作,避免阻塞UI线程,提升用户体验。 9. **设计时特性**:Visual Studio IDE提供了强大的Winform设计器,可以直接拖放控件,设置属性,预览...
这里我们将详细探讨如何实现“简单C# WinForm多线程委托调用进度条”。 首先,我们需要理解多线程的概念。在C#中,`System.Threading`命名空间提供了对线程的支持。主线程是应用程序的主要执行流,而额外创建的线程...