「玩一玩」InvokeHelper,让跨线程访问/修改主界面控件不再麻烦
--------------------编程问答-------------------- 野比君睡了没?
--------------------编程问答-------------------- 你还不睡啊 --------------------编程问答-------------------- 这位兄台,好象你的代码很复杂。我前几天写了一下,表述力不佳,仅贴代码。
public class ThreadRunCode
{
public Thread th;
public bool bExceptRun=true;//是否结束线程,这个可以在外控制线程
public bool bSleep=true;//本次线程的时间片是否执行事件。
private System.Windows.Forms.Form frm;
public delegate void ThreadRunMthod();
public event ThreadRunMthod threadRunMthod;
public void RunThread()
{
th = new Thread(new ThreadStart(RunThreadCode));
th.Start();
}
private void RunThreadCode()
{
do
{
if (bSleep)
{
continue;
}
this.frm.Invoke(threadRunMthod);
} while (bExceptRun);
}
}
在Form中调用举例:
public int i;
//others code
ThreadRunCode threadRunCode=new ThreadRunCode(this);
threadRunCode.threadRunMthod += new ThreadRunMthod(ThreadRunCode_threadRunMthod);
threadRunCode.bSleep=false;
threadRunCode.RunThread();
//others code
void ThreadRunCode_threadRunMthod()
{
textBox1.text=(i++).ToString();
}
这样写是不是也可以实现多线程,其实我在想,多线程同一时刻尽量少,应该他存在的时候才启动。比如你说的例子,我认为在要修改界面的时候再建一个线珵,修改完后就终止线程,再改变的时候再建一个。
--------------------编程问答-------------------- 这个有点意思,平时用的蛮多,从来没想到去封装成类 --------------------编程问答-------------------- 思路上不一样。我写的这个是「在多线程时修改控件」,而不是「为了改控件而多线程」。欢迎你照你的思路完善下去,然后争取做到最简化。 --------------------编程问答-------------------- 远离反射,通常更能够保证性能。而且以下方法更加直观和方便。
在你的工程中的扩展方法类中写下一个SafeCall方法:
using System;它只是把你要保护起来的代码作为一个回调而已。然后任何需要保护一些代码的地方都可以这样调用:
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public static class Extensions
{
public static void SafeCall(this Control ctrl, Action callback)
{
if (ctrl.InvokeRequired)
ctrl.Invoke(callback);
else
callback();
}
}
}
using System;--------------------编程问答-------------------- c#是很优雅的语言。通常你都不需要使用沉重和弯弯绕的“反射”技巧来,而可以更加轻松地封装你的方法。 --------------------编程问答-------------------- 当然,使用lamda是我的一个“坏毛病”。其实这里完全可以使用传统的匿名委托写法:
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(h =>
{
for (var i = 0; i < 10000000; i++)
{
label1.SafeCall(() =>
{
label1.Text = i.ToString();
});
Thread.Sleep(100);
}
});
}
}
}
using System;--------------------编程问答-------------------- 注明一下:此文内容基于.NET 2.0
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(h =>
{
for (var i = 0; i < 10000000; i++)
{
label1.SafeCall(delegate()
{
label1.Text = i.ToString();
});
Thread.Sleep(100);
}
});
}
}
}
新的.NET有很方便的实现跨线程访问的能力,参见楼上 --------------------编程问答-------------------- 太好了,正纠结于这个问题 --------------------编程问答-------------------- 多线程交给系统去处理吧。 --------------------编程问答--------------------
不错,作为分享,应该使用较新的技术。
C#的出路不在于跟java比谁更老。 --------------------编程问答-------------------- 不会新技术,没招。。相信用2.0的还是不少的。。 --------------------编程问答-------------------- 支持一个 --------------------编程问答--------------------
连P哥也习惯于复制粘贴了。。。 --------------------编程问答-------------------- 标记,收藏~
看看有好用的方法,以后再用上。之前用过的是类似与#3的方法。 --------------------编程问答--------------------
学习来着
--------------------编程问答-------------------- 其实我是来灌水的 --------------------编程问答-------------------- --------------------编程问答-------------------- 正好最近用多线程,学习了。 --------------------编程问答--------------------
public delegate void DoWorkD(int N);
public DoWorkD d;
public void DoWork(int Nums)
{
if (textBox1.InvokeRequired)
{
textBox1.Invoke(d, Nums);
}
else
textBox1.Text += Nums.ToString() + "-";
}
public void ThreadDoWork()
{
Thread.Sleep(new Random().Next(100, 1000));
int i=0;
while (true)
{
d = new DoWorkD(DoWork);
Thread.Sleep(new Random().Next(100, 1000));
DoWork(i);
i++;
}
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 20; i++)
{
Thread a = new Thread(ThreadDoWork);
a.IsBackground = true;
a.Start();
}
}
这样就可以了.net 2.0
例子在这http://download.csdn.net/detail/wawd74520/4479927 --------------------编程问答-------------------- 学习来着 哈哈 --------------------编程问答-------------------- --------------------编程问答--------------------
其实楼主的做法,就是想省略掉声明一大堆的委托 --------------------编程问答-------------------- 唉。还得从效率上考虑啊。
尤其是多线程 --------------------编程问答-------------------- 实在不行,其实可以把句柄传过去。怎么改都可以。- - 虽然很烂 --------------------编程问答-------------------- 乔巴过来学习下 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 只用一行代码的飘过
--------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 多线程学好了还真管用! --------------------编程问答-------------------- 支持一个,我也是用.net 2.0的。现在有这个InvokeHelper,应该会方便很多了。
野比,加一个:BeginInvoke 下去会更完美一点。
以前破旧的代码:
--------------------编程问答-------------------- 这是一个值得学习的东西,不过这知识实现一个功能,其实还可以网上面加东西 --------------------编程问答-------------------- 昨天加班 木上Q就躺了 --------------------编程问答-------------------- Invoke(new MethodInvoke(new Action(deleagte()
Private Delegate Sub ShowMsgCallBack(ByVal msg As String)
Private Delegate Sub SetBtnTextCallBack(ByVal text As String)
Private Sub ShowPanel()
If Me.PnlDownInfo.InvokeRequired Then
Dim mi As New MethodInvoker(AddressOf ShowPanel)
Me.BeginInvoke(mi)
Else
Me.PnlDownInfo.Visible = Not Me.PnlDownInfo.Visible
End If
End Sub
Private Sub ShowMsg(ByVal msg As String)
If Me.LBDownloadInfo.InvokeRequired Then
Dim cb As New ShowMsgCallBack(AddressOf ShowMsg)
'如使用Invoke会等到函数调用结束,而BeginInvoke不会等待直接往后走
Me.BeginInvoke(cb, New Object() {msg})
Else
Me.LBDownloadInfo.Text = msg
Me.LBDownloadInfo.Refresh()
End If
End Sub
Private Sub PerFinishDownLoad(ByVal fname As String)
If Me.LvFiles.InvokeRequired Then
Dim cb As New ShowMsgCallBack(AddressOf PerFinishDownLoad)
Me.BeginInvoke(cb, New Object() {fname})
Else
Dim item As ListViewItem
item = Me.LvFiles.FindItemWithText(fname)
If item IsNot Nothing Then
item.SubItems(2).Text = "完成"
End If
End If
End Sub
Private Sub ResetDownLoadPrg()
If Me.InvokeRequired Then
Dim mi As New MethodInvoker(AddressOf ResetDownLoadPrg)
Me.BeginInvoke(mi)
Else
Me.SmoothProgressBar1.Value = 0
Me.LBDownloadInfo.Text = "下载信息"
End If
End Sub
Private Sub ResetDownLoadBtn()
If Me.BtnRunUpdate.InvokeRequired Or Me.BtnCancel.InvokeRequired Then
Dim mi As New MethodInvoker(AddressOf ResetDownLoadBtn)
Me.BeginInvoke(mi)
Else
Me.BtnRunUpdate.Enabled = True
Me.BtnRunUpdate.Text = "完成(&F)"
Me.BtnCancel.Enabled = False
End If
End Sub
{
})));
子线程中需要访问 控件的话,我现在习惯了这样,很少判断这InvokeRequired个属性了 --------------------编程问答-------------------- 我没看错????
循环创建了20个线程?访问同一个控件?没加锁?
--------------------编程问答-------------------- 还是SP大哥技术牛,这时候想到了用扩展方法......
向你学习,另外这个获取异步委托的返回值,怎么做啊,这个异步委托,很少用,不太熟悉.
--------------------编程问答-------------------- 虽然看不到,但是先Marki下。 --------------------编程问答-------------------- --------------------编程问答-------------------- 好像很水的内容 --------------------编程问答-------------------- --------------------编程问答-------------------- 不错,感谢楼主分享 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 看来要多学习了 --------------------编程问答-------------------- 探讨的问题越来越精彩了,不错 --------------------编程问答-------------------- 哇!不懂! --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 从来还没用过多线程,看了这篇帖子,现在可以试试水了 --------------------编程问答-------------------- 好帖先收藏一哈 嘿嘿 --------------------编程问答-------------------- 的确我也感觉线程与UI的通讯很麻烦,至少我觉得写出来的代码一点都不优雅,感觉很难给第二个人看得一目了然,我也很苦恼这个事情,不知各位高手有什么高招 --------------------编程问答-------------------- LZ还应该反treeView,ListView等操作控件内子属性的也增加上。这样就完美了。偶的就是这样做的。 --------------------编程问答--------------------
只是个例子。我不打算给出什么「完美」的东西,那样会剥夺阅读的人进步的机会。对于不想思考只想伸手的人,我不愿意给他们提供任何帮助。 --------------------编程问答-------------------- --------------------编程问答-------------------- mark,最近正在学着用多线程~~ --------------------编程问答-------------------- 楼主用了反射吗?貌似很耗资源的说
我有个思路,楼主或各位大大给点意见
就是重写FORM类,写一个专门支持跨线程操作的ThreadForm,继承于Form
在这个类中,
public delegate void ThreadInvokeDelegate(string type,params object[] args);
#region 静态方法,供其他线程调用,用于访问Form
public static event ThreadInvokeDelegate OnThreadInvoke;
public static ThreadInvoke(string type,params object[] args)
{
if(OnThreadInvoke!=null)
OnThreadInvoke(type,args);
}
#endregion
在真正的form中(比如Form1),构造函数里注册这个静态事件
Form1.OnThreadInvoke+=new ThreadInvokeDelegate(Form1_OnThreadInvoke);
这样就把任意线程调用Form1.ThreadInvoke方法转到了Form1_OnThreadInvoke中处理
这里的string type作为标识,来区分Form1需要进行的不同的操作,比如刷新列表,还是写日志,还是其他什么操作
以上想法本人技术有限,不能很好的实现,希望有大哥能完善,并分享一下 --------------------编程问答-------------------- 不错.......... --------------------编程问答-------------------- .Net 4.5 的async和await异步编程,貌似可以完全无视那些begin和end开头的异步方法了。。 --------------------编程问答-------------------- --------------------编程问答-------------------- 看了一下,没看懂 --------------------编程问答-------------------- --------------------编程问答-------------------- 厉害!! --------------------编程问答-------------------- 很厉害 --------------------编程问答-------------------- 用.NET 3.5的飘过 --------------------编程问答-------------------- 学习到了,但是还是想问,多个线程同时使用一个控件,不会死锁吗 --------------------编程问答-------------------- 那就加锁呗
--------------------编程问答-------------------- 积分怎么弄啊!! --------------------编程问答-------------------- 积分怎么弄啊!! --------------------编程问答-------------------- 线程间的访问默认是不允许的,但是这个开关是可以打开的,开关打开,虽然可以跨线程访问,但会带来安全问题。
还有,在.net 4.0中,微软已经了为我们提供了ui线程和非UI线程之间的访问办法,
可以参照control.invoke,control.beginInvoke方法 --------------------编程问答-------------------- --------------------编程问答-------------------- 尽快回答是到就会受到asdad --------------------编程问答-------------------- this.Control.CheckForIllegalCrossThreadCalls = false;
夸线程访问控件,这一句代码不是就完了么。。 --------------------编程问答--------------------
就用这么一行代码的路过~~~
--------------------编程问答-------------------- 是的,就完了。 --------------------编程问答-------------------- 恩,不错,值得一看! --------------------编程问答--------------------
你运行了这里的程序了吗?它死锁了吗?
自己动手测试才是硬道理。 --------------------编程问答-------------------- --------------------编程问答-------------------- 没好好看 没环境测试啊 悲催的 装了n次系统了 --------------------编程问答-------------------- 非常感谢!
学习了! --------------------编程问答-------------------- --------------------编程问答-------------------- 内容不错 收藏了 --------------------编程问答-------------------- 各位大神,我最近在使WPF主窗口中弹出一个新窗口,但老是出错,好像也涉及到多线程,但这一块实在是不怎么懂,求各位指导一下……
http://topic.csdn.net/u/20120810/14/17b442ae-5f57-4781-80a2-75aebb5568c6.html?seed=275715377&r=79381756#r_79381756
--------------------编程问答--------------------
通过endinvoke,回调 --------------------编程问答-------------------- 上面的例了应该不能算多线程。。多线程对同一控件或变量访问是要加锁的 --------------------编程问答-------------------- 用得着这么麻烦吗?用Timer控件不行吗? --------------------编程问答-------------------- 虽然挺简单到 但是还是好东西 赞一个 --------------------编程问答-------------------- 看过野比大哥几遍文章,对于我这个新人来说,受益不少,谢谢。! --------------------编程问答-------------------- 很好很强大 值得学习啊
--------------------编程问答-------------------- 很好很强大 值得学习啊
--------------------编程问答--------------------
同意,虽然谁都写得出来,但觉得写出来没任何意义,所以谁都不高兴写。
实际是否要委托本身就看需求,多线程是为了提高效率而存在的,不是为了降低效率,到处用委托违背了多线程的存在意义。
而实际对于简单的输出显示,应该直接对其操作,不要回调,设置CheckForIllegalCrossThreadCalls为false即可,有时候不检查能大大提高效率,而即使检测也不代表就一定能正常,因为多线程操作共享资源一般需要加锁,这和是否回调操作无关。 --------------------编程问答-------------------- 讲的好啊。。。 --------------------编程问答-------------------- 学习下。楼主 总是很给力 --------------------编程问答-------------------- 都没用过Invoke. --------------------编程问答-------------------- --------------------编程问答-------------------- 不怎么用反射,没用过回调。。。
补充:.NET技术 , C#