Silverlight 跨线程访问无效(Socket例)

Silverlight 跨线程访问无效(Socket例),第1张

概述Silverlight 的许多请求基本都是异步的,用WCF也好,WEBCLIENT也好,都会进行异步请求,并提供一个事件用于执行回调。在使用WCF和WEBCLIENT与服务器通信的时候通常我们都不会遇到什么麻烦,因为WCF的类方法和WEBCLIENT都是在主线程上执行和委托事件的,理所当然,回调事件也是在主线程上运行,所以一马平川的就使用了。但是当我们用到Socket或者HttpWebReques

Silverlight 的许多请求基本都是异步的,用WCF也好,WEBCLIENT也好,都会进行异步请求,并提供一个事件用于执行回调。在使用WCF和WEBCLIENT与服务器通信的时候通常我们都不会遇到什么麻烦,因为WCF的类方法和WEBCLIENT都是在主线程上执行和委托事件的,理所当然,回调事件也是在主线程上运行,所以一马平川的就使用了。但是当我们用到Socket或者httpWebRequest(httpWebRequest我自己本身没用但是看别人在用的时候遇到相同的问题)的时候回调事件中如果试图修改UI之类的时候就会出现“跨线程访问无效的”错误异常。

 

为什么呢?以Socket来说,异步的回调事件并不是在Socket对象上定义的,而是在其socketasynceventargs 对象上定义的,要实现异步,Silverlight当然会自己创建一个子线程去运行这个异步事件,所以,虽然在主线程上定义了Socket和socketasynceventargs,但是Socket执行异步方法后,将socketasynceventargs委托给了异步子线程,所以在socketasynceventargs上定义的事件回调也是子线程的,这样的话,子线程的回调函数当然就不允许去 *** 作主线程上的对象了,因此Socket的参数回调事件上修改UI等,会引发 “跨线程访问无效的”异常。

 

如何解决呢?

 

Silverlight提供了一个同步上下文的类 SynchronizationContext 类(System.Treading命名空间下) ,该类提供在各种同步模型中传播同步上下文的基本功能。

 

也就是说,你可以使用该类,不同线程上方法调度到某一指定线程上。

 

下面用Socket为例:

Xaml:很简单,就是一个按钮和一个文本框,按钮有一个Click事件,绑定到OnSend方法

 

<UserControl x:Class="SilverlightTest.socket1"

    xmlns="http://schemas.microsoft.com/clIEnt/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    WIDth="400" Height="300">

    <GrID x:name="LayoutRoot" Background="White" ShowGrIDlines="True">

        <GrID.RowDeFinitions >

            <RowDeFinition />

            <RowDeFinition />

        </GrID.RowDeFinitions>

 

        <TextBox x:name="txtToSend" GrID.Row="0"/>

        <button GrID.Row="1" Click="OnSend" Content="Send" margin="20" />

    </GrID>

</UserControl>

 

代码部分:

 

using System;

using System.Collections.Generic;

using System.linq;

using System.Net;

using System.windows;

using System.windows.Controls;

using System.windows.documents;

using System.windows.input;

using System.windows.Media;

using System.windows.Media.Animation;

using System.windows.Shapes;

using System.Net.sockets;

using System.Threading;

using System.Text;

 

 

 

namespace SilverlightTest

{

    public partial class Socket1 : UserControl

    {

        public Socket1()

        {

            InitializeComponent();

        }

 

        System.Net.sockets.Socket socket;

        SynchronizationContext syn;

 

        //发送信息按钮的单击事件

        voID OnSend(object sender,EventArgs args)

        {

 

            syn = SynchronizationContext.Current;

           

           

            socket = new System.Net.sockets.Socket(AddressFamily.InterNetwork,SocketType.Stream,

                 ProtocolType.Tcp);

 

            socketasynceventargs socketArgs = new socketasynceventargs()

            {

                RemoteEndPoint = new DnsEndPoint(

                   Application.Current.Host.source.DnsSafeHost,4502)

            };

            socketArgs.Completed += OnoperationCompleted;

            socketArgs.UserToken = socket;

            socket.ConnectAsync(socketArgs);

 

           

        }

 

        //回调函数

        voID OnoperationCompleted(object sender,socketasynceventargs e)

        {

 

            syn.Post(GetText,"OK");

 

 

        }

 

 

 

        voID GetText(object str)

        {

            txtToSend.Text = str.ToString();

        }

 

 

 

 

    }

}

 

 

 为了集中说明问题,省略很很多部分,该代码的功能只是创建一个Socket和其参数,参数绑定一个完成回调事件,然后执行连接,连接好之后,引发回调OnoperationCompleted。

如果,我们在回调函数上直接写上txtToSend.Text="XXX",一定会引发跨线程的异常,因此,我们用之前在主线程上定义的SynchronizationContext 的实例syn的Post方法,将回调子线程的 *** 作调度到主线程上的GetText方法上,并传递个参数"OK",这样在回调函数将 *** 作调度到GetText方法,然后GetText方法中就可以进行修改UI上的属性了。

在前面定义 SynchronizationContext的时候,我们将它实例化为SynchronizationContext.Current,即当前线程,定义并实例化SynchronizationContext的时候是在主线程上进行的,因此 Current指的上下文或线程 就是主线程,所以在后来的回调函数中,调度GetText就是调度到主线程上,主线程可以修改UI所以GetText可以修改UI。

大概的原理和方法就是如此,文中提到的一些思路为个人理解,如果与实际有差,还请见谅。

总结

以上是内存溢出为你收集整理的Silverlight 跨线程访问无效(Socket例)全部内容,希望文章能够帮你解决Silverlight 跨线程访问无效(Socket例)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1050902.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-25
下一篇2022-05-25

发表评论

登录后才能评论

评论列表(0条)

    保存