SendOrPostCallback xxx = vg => { Text ="内部: "+vg.ToString(); };dynamic vx = new { a = SynchronizationContext.Current, b = xxx };Thread td = new Thread(x =>{dynamic tmp = x;// SynchronizationContext ds = x as SynchronizationContext;for (int i = 0; i < 500; i++){System.Threading.Thread.Sleep(10);//((SynchronizationContext)tmp.a).Post(v => { Text = v.ToString(); }, i + " " + DateTime.Now);((SynchronizationContext)tmp.a).Post(tmp.b, i + " " + DateTime.Now);}// this.Invoke((MethodInvoker)delegate { MessageBox.Show("ok"); });});td.Start(vx);
void uiexe(object cs){Text = cs.ToString();}
//ThreadPool.QueueUserWorkItem(x =>//{// for (int i = 0; i < 100; i++)// {// System.Threading.Thread.Sleep(10);// ((SynchronizationContext)x).Post(y => { Text = i + " " + DateTime.Now; }, null);// }//}, SynchronizationContext.Current);SynchronizationContext nb = SynchronizationContext.Current;ThreadPool.QueueUserWorkItem(x =>{for (int i = 0; i < 100; i++){System.Threading.Thread.Sleep(10);nb.Post(y => { Text = i + " " + DateTime.Now; }, null);}}, null);
[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);// let's check the context herevar context = SynchronizationContext.Current;if (context == null)MessageBox.Show("No context for this thread");elseMessageBox.Show("We got a context");// create a formForm1 form = new Form1();// let's check it again after creating a formcontext = SynchronizationContext.Current;if (context == null)MessageBox.Show("No context for this thread");elseMessageBox.Show("We got a context");if (context == null)MessageBox.Show("No context for this thread");Application.Run(new Form1());}
而且它使用非常方便,只需要关注下面两个方法即可:
1. Send:发送界面更新请求至主线程,阻塞当前线程直至返回。
2. Post:发送界面更新请求至主线程,不阻塞当前线程。
实际上,他们都是同一个方法,只是 send 是同步,post 是异步
这是一个很简单的例子,也许看过的人都会说:根本就没有摆脱Control 和 From 啊!
诚然如此,为了摆脱Control,我们还需要封装一下,看下面的BackgroundWorker 类:
class BackgroundWorker{public EventHandler<EventArgs> WorkerStarted;public EventHandler<ProgressEventArgs> ReportProgress;public EventHandler<EventArgs> WorkerCompleted;public SynchronizationContext Context { get; set; }public void Start(){Thread t = new Thread(() =>{Context.Post(SetStartState, null);for (int i = 0; i <= 10; i++){Thread.Sleep(new TimeSpan(0, 0, 1));Context.Post(UpdateProgress, i * 10);}Thread.Sleep(new TimeSpan(0, 0, 1));Context.Post(SetCompletedState, null);});t.Start();}private void SetStartState(object state){if (WorkerStarted != null){WorkerStarted(this, new EventArgs());}}private void SetCompletedState(object state){if (WorkerCompleted != null){WorkerCompleted(this, new EventArgs());}}private void UpdateProgress(object state){if (ReportProgress != null){ReportProgress(this, new ProgressEventArgs {Progress = Convert.ToInt32(state)});}}}
有两个特别的地方:
1. 构造的时候,需要提供SynchronizationContext 实例
2. 它的三个事件(WorkerStarted,ReportProgress, WorkerCompleted),都是在 post 方法里面触发的。这样做就可以确保事件的订阅方法脱离后台线程,进入主线程。
protected override void OnLoad(EventArgs e){_context = SynchronizationContext.Current;}private void btnWrapper_Click(object sender, EventArgs e){btnWrapper.Enabled = false;BackgroundWorker worker = new BackgroundWorker {Context = SynchronizationContext.Current};worker.WorkerStarted += (o, args) => { txtWrapper.Text = "Running background thread..."; };worker.ReportProgress += (o, args) => { txtWrapper.Text = string.Format("Progress: {0}", args.Progress); };worker.WorkerCompleted += (o, args) =>{txtWrapper.Text = "Background thread completed";btnWrapper.Enabled = true;};worker.Start();}
WebChannelFactory<JK.IXX> dd = new WebChannelFactory<JK.IXX>(new Uri("http://localhost/xxii"));// ChannelFactory<JK.IXX> dd = new ChannelFactory<JK.IXX>(bd, "http://localhost/xxii");// dd.Endpoint.Behaviors.Add(new WebHttpBehavior());// WebOperationContext.Current.IncomingRequest.Headers.Add("dddd","ssss");dd.Endpoint.Behaviors.Add(new XEndpointBehavior());//SynchronizationContext.Current.Post(// SynchronizationContextJK.IXX service = dd.CreateChannel();IClientChannel clientchanel = service as IClientChannel;//IServiceChannel using (OperationContextScope scope = new OperationContextScope(clientchanel)){var xddd = WebOperationContext.Current;xddd.OutgoingRequest.Headers.Add("ssss", "dddd" + DateTime.Now);//加不了//*****************************************************************************************//using (OperationContextScope scope = new OperationContextScope(iContextChannel))//{//MessageHeader<string> mh = new MessageHeader<string>("abcde");//MessageHeader header = mh.GetUntypedHeader("AuthKey", http://www.cjb.com/);//OperationContext.Current.OutgoingMessageHeaders.Add(header);//return func();//}//服务端: //string authKey = string.Empty;//if (OperationContext.Current != null)//{//authKey = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>("AuthKey", http://www.cjb.com);//}//*****************************************************************************************//调用方法获取消息头 string messHeader = service.getstr();MessageBox.Show(messHeader);Console.WriteLine(messHeader);Console.WriteLine("服务方法已调用");}