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 here var context = SynchronizationContext.Current; if (context == null) MessageBox.Show("No context for this thread"); else MessageBox.Show("We got a context"); // create a form Form1 form = new Form1(); // let's check it again after creating a form context = SynchronizationContext.Current; if (context == null) MessageBox.Show("No context for this thread"); else MessageBox.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( // SynchronizationContext JK.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("服务方法已调用"); }