winform异步线程更新UI问题(求讨论,求指教,求保养)
刚才看到有人问为了winfrom中,在大数据绑定的时候出现画面假死的状态,为了解决这个问题希望通过再开一个线程来给控件绑定数据,可是画面还是会假死。
现在看到的方法有
1.掩耳盗铃法(Control.CheckForIllegalCrossThreadCalls = false;)
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(); } }}
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()); } } }
// 代码中自己定义的按钮(非显示按钮) private Button testBtn = new Button(); private void button1_Click(object sender, EventArgs e) { Thread thr = new Thread(ControlParent); thr.Start(); } private void ControlParent() { Thread.Sleep(3000); // 给自己定义的按钮赋值没有问题 testBtn.Text = "eeee"; // 给画面上显示的按钮赋值,InvalidOperationException错误(这里迷糊了,子线程不能直接给主线程赋值,那么主线程是什么?) this.button1.Text = "asda";// InvalidOperationException!!!!!!!!!!! }
this.lbprogressBar.Text = pro.ToString("N2") + "%";
if (pro >= 100)
{
pro = 100;
}
this.progressBar1.Value = Convert.ToInt32(pro);
}));
[解决办法]
this.BeginInvoke((MethodInvoker)delegate{ this.button1.Text = "asda";});
[解决办法]
主线程就是UI线程啊。
你在非UI线程上默认是不能更新UI线程上的东西的。你需要将更新这个委托交给UI线程自己去执行。
你可以在ControlParent中这样写来更新BUTTON1
this.Invoke(()=>{button1.Text="asda";});
[解决办法]
数据集.Fill(缓存数据表, 表名);/这里会是时钟控件无法执行/ 建立连接.Close();
一般读数据库ACCESS会出现这种情况,慢的电脑会使主界面状态栏中显示时间停顿5-10秒不等,即使使用线程或一部也无法解决。图片一般使用异步也就可以了,慢的电脑也不显得慢。
[解决办法]
[code=C#][/code]
using System;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate void DeleWork();//委托
private Button testBtn = new Button();
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(threadWork);
thread.IsBackground = true;
thread.Start();
}
private void threadWork()
{
DeleWork ThreadDeleWork = new DeleWork(FormDeleWork);
while (true)
{
Thread.Sleep(1000);
this.BeginInvoke(ThreadDeleWork);
}
}
private void FormDeleWork()
{
testBtn.Text = "eeee";
this.button1.Text = "asda";
textBox1.Text = testBtn.Text;
}
}
}
[解决办法]
一、子线程操作主线程的控件用委托就行;
二、把延时的工作放到委托入口之外就不会假死了。
希望对你有帮助。
[解决办法]
该UI做的就让UI去做,不该UI去做的就不要让UI去做。
如果你让UI做的事情太多,比如加载1G的图片这种巨大的操作。那UI本身不做优化的话不卡死就怪了。
[解决办法]
LZ是担心这代码段会被不同你的线程访问时冲突吧
void SetTextBoxValue(object obj)
{
this.textBox1.Text = obj.ToString();
}
这样的话你可以加把锁如:
object locker=new object();
void SetTextBoxValue(object obj)
{
lock(locker)
{
this.textBox1.Text = obj.ToString();
}
}
这样就可以只有一个线程对SetTextBoxValue进行访问了,其他要访问的线程将会等待,直到SetTextBoxValue完成
[解决办法]
简便通用的方法
public static void CrossThreadInvoke(Control ctrl, Action action) { if (ctrl.InvokeRequired) { ctrl.Invoke(action); } else { action.Invoke(); } }
[解决办法]
try
public class Utils { public static void CrossThreadInvoke(Control ctrl, Action action) { if (ctrl.InvokeRequired) { ctrl.Invoke(action); } else { action.Invoke(); } } }
[解决办法]
Semaphore semaphore = new Semaphore(0, 1); LoadMainForm(semaphore ) while (!semaphore.WaitOne(TimeSpan.FromMilliseconds(40), false)) { Application.DoEvents(); } private void LoadMainForm(Semaphore semaphore ){ ThreadPool.QueueUserWorkItem(delegate{ try{ mainForm = new frmMain(); semaphore.Release(); } catch (Exception ex){ semaphore.Release(); } }); }
[解决办法]