专注收集记录技术开发学习笔记、技术难点、解决方案
网站信息搜索 >> 请输入关键词:
您当前的位置: 首页 > .NET分析设计

议论帖 对象以及多线程中访问窗体中的控件的一种实现方式

发布时间:2011-06-23 20:18:09 文章来源:www.iduyao.cn 采编人员:星星草
讨论帖 对象以及多线程中访问窗体中的控件的一种实现方式
这是一篇讨论帖,欢迎各种意见。

今天看到了这篇帖子【C#多线程安全访问控件,System.OutOfMemoryException异常】http://bbs.csdn.net/topics/390833628
还有前几天也看到了一篇帖子,说的都是在线程中访问主线程的窗体上的控件的事情。关于这个事情,很想说一些话。
正巧今天又看到了【什么是面向对象的思想 】http://bbs.csdn.net/topics/390835308
想了想,还是把这两个事情放在一起讨论一下吧。

在一个窗体程序里面,出现了一个处理,它拖慢了窗体的反应速度,因此就用new Thread来加个线程,把那个处理扔到新线程里面去执行了。这个New Thread真是很方便啊,基本不用改原来的代码就造个新线程出来,高兴啊。可惜高兴不久就会发现在自己生成的新线程里面无法按照主线程的方式去访问窗体上的控件,这下苦逼了。找解决方法吧,什么Invoke,BeginInvoke,Delegate一堆一堆地就冒出来露脸了。

想一想,为什么一定要在新线程里面去访问主线程中的控件呢?这不需要吧。
这种时候,还是放松一下,换个思路吧。把设计稍微改一下,利用对象和事件来满足我们吧。

让我们这样修改一下,把那些放在新线程中的处理代码挪到另一个类里面去,在那个类里面定义好事件,属性啥的,还有什么委托啥的都随便了,甚至极端一点的把原来的大部分代码都挪到新类里面。
之后就是在主线程中生成那个类的实例,通过响应实例的各种事件来决定如何操作控件。
然后这些类啊,实例啊,对象啊,事件啊这些东东,就是所谓的面向对象了,不知道你可认同这个说法?

下面这段代码仅仅演示【在新线程中对主线程窗体上的TextBox1赋值】这个功能是如何通过我介绍的实现方式来实现的,其中很多功能例如线程销毁等都没有加入,请不要直接作为成熟的代码来使用。

Public Class Form1
'这就是那个新写的类,为了看起来方便就放在这里了。
    Public Class OtherThread
'定义好一个事件,来跟别的类打交道
        Public Event TextChanged(ByVal vstrText As String)
'今后生成的实例就用这个名字来区别一下
        Private _name As String = ""
'建立一个新线程,其实也就是本来在主窗体代码中的生成新线程的处理。
        Public Sub DoSomethingInNewThread()
            Dim p As New Threading.Thread(AddressOf DoSomething)
            p.Start() '需要找个时机销毁它
        End Sub
        
'这个函数用来模拟那个拖慢主线程窗体的处理
        Public Sub DoSomething()
            For i As Integer = 0 To 10
                Threading.Thread.Sleep(100)
                'TextBox1.AppendText(_name & i) '当这个函数还在主线程里面时候,这样就可以操作窗体上的控件了。可惜放在新线程里面就不行了。
                RaiseEvent TextChanged(_name & i) '现在放到新的类里面了,就更看不到控件了,所需要做的就是:我发出了一个事件,别的类愿意怎么处理就怎么处理吧。
            Next
        End Sub

        Public Sub New(ByVal vstrName As String)
            _name = vstrName
        End Sub
    End Class

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'生成两个新类的实例
        Dim a As New OtherThread("a")
        Dim b As New OtherThread("b")
'用来捕获实例发出的事件
        AddHandler a.TextChanged, AddressOf OtherThread_TextChanged
        AddHandler b.TextChanged, AddressOf OtherThread_TextChanged
'这个调用是用来演示DoSomething()里面的处理会拖慢窗体。
        a.DoSomething()
        b.DoSomething()
'DoSomethingInNewThread()里面用了新线程,就不会拖慢窗体了。
        a.DoSomethingInNewThread()
        b.DoSomethingInNewThread()
'DoSomethingInNewThread()里面是新线程,执行到这里的时候,实例a和实例b里面的新线程还在运行中,因此不能在这里RemoveHandler ,
        'RemoveHandler a.TextChanged, AddressOf OtherThread_TextChanged
        'RemoveHandler b.TextChanged, AddressOf OtherThread_TextChanged
    End Sub

    Private Sub OtherThread_TextChanged(ByVal vstrText As String)
'让OtherThread这个类负责处理繁重的工作,主线程就负责显示好了。
        TextBox1.AppendText(vstrText & vbCrLf)
    End Sub
End Class

到此为止,将本来的【在新线程中赋值给主线程窗体控件】这一做法改成了【在新类中建立新线程->发出事件->主线程捕获事件->赋值给控件】的做法。还算简单明了吧。
如果还有【在新线程中取得主线程窗体控件的值】的需求的话,那么就在主线程中把控件值传递给新类的实例吧。

------解决思路----------------------
表面上 OtherThread_TextChanged 是在主线程执行的,实际上由于 RaiseEvent TextChanged(_name & i)  是在后台线程的,所以最终执行 OtherThread_TextChanged 的时候还是在后台线程。

可以放个断点看看。
友情提示:
信息收集于互联网,如果您发现错误或造成侵权,请及时通知本站更正或删除,具体联系方式见页面底部联系我们,谢谢。

其他相似内容:

热门推荐: