通过同步上下文方式更新winform中的控件信息

SynchronizationContext 类是一个基类,可提供不带同步的自由线程上下文。 此类实现的同步模型的目的是使公共语言运行库内部的异步/同步操作能够针对不同的异步模型采取正确的行为。此模型还简化了托管应用程序为在不同的同步环境下正常工作而必须遵循的一些要求。同步模型的提供程序可以扩展此类并为这些方法提供自己的实现。(来自MSDN)
简而言之就是允许一个线程和另外一个线程进行通讯,SynchronizationContext在通讯中充当传输者的角色。另外这里有个地方需要清楚的,不是每个线程都附加SynchronizationContext这个对象,只有UI线程是一直拥有的。

 

Console, WinForm和WPF中的SynchronizationContext

Console程序中没有SynchronizationContext的概念。这也很好理解。因为Console没有UI控件,所以也不需要SynchronizationContext来进行同步。SynchronizationContext.Currnet总是为null。
在WinForm中,如果我们只创建了一个Window,SynchronizationContext.Currnet为一个类型为System.Windows.Forms.WindowsFormsSynchronizationContext的

System.Windows.Forms.WindowsFormsSynchronizationContext。但是如果你接下来用Application.Run()来显示这个窗口,SynchronizationContext.Currnet又变成了System.Threading.SynchronizationContext类型。不过有一点可以保证,在WinForm程序中SynchronizationContext.Currnet一定不为空。


在WPF中,不管你怎么创建Window,也不管你怎么用Applicaitono.Run()函数来启动Window,SynchronizationContext.Currnet总是为空。我们必须显示初始化:SynchronizationContext.SetSynchronizationContext(new System.Windows.Threading.DispatcherSynchronizationContext());

 

winform通过上下文更新控件内容

 

        SynchronizationContext sc = SynchronizationContext.Current;       
 
        #region SynchronizationContext
        //https://www.bbsmax.com/A/ZOJPX24eJv/ 理解SynchronizationContext,如何在Winform里面跨线程访问UI控件
        /// <summary>
        /// This method is executed on the main UI thread.
        /// </summary>
        private void UpdateUI(object state)
        {
            string msg = state as string;
            SendLogMessage(msg);
            return;
            Invoke(new MethodInvoker(delegate ()
            {
                if (RtbMsg != null)
                {
                    RtbMsg.AppendText(msg + "\r\n");
                    RtbMsg.ScrollToCaret();
                }
            }));
        }
        /// <summary>
        /// 交给UI线程去排队显示消息
        /// </summary>
        /// <param name="message"></param>
        private void SendLogMessage(string message)
        {
            sc.Post(LogMessageBack, message);
        }
        /// <summary>
        /// UI线程回调方法,访问控件刷新显示
        /// </summary>
        /// <param name="message">消息内容</param>
        private void LogMessageBack(object message)
        {
            RtbMsg.AppendText(message.ToString() + Environment.NewLine);
            RtbMsg.ScrollToCaret();
        }
        #endregion SynchronizationContext

 

  

 

 

 

        protected internal static System.AsyncCallback SyncCallback(System.AsyncCallback callback)
		{
			System.Threading.SynchronizationContext sc = System.Threading.SynchronizationContext.Current;
			if (sc == null)
			{
				return callback;
			}
			return delegate(System.IAsyncResult asyncResult)
			{
				sc.Post(delegate(object result)
				{
					callback((System.IAsyncResult)result);
				}, asyncResult);
			};
		}
		protected void DataAction(Action action)
		{
			try
			{
				action();
			}
			catch (System.Exception ex)
			{
				OperateLog.OpExcpLog(string.Format("[{0}][{1}]功能操作执行异常,异常原因:{2}", action.Method.GetType().FullName, action.Method.Name, ex.Message));
				System.Windows.Forms.MessageBox.Show(EESException.getException(ex).Message, "异常警告", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Hand);
			}
		}
		protected void BeginAction(MethodDelegate action, object obj, params object[] args)
		{
			EForm.AsyncRequest asyncRequest = new EForm.AsyncRequest(action, obj, args, System.Threading.SynchronizationContext.Current);
			this.inAsyncAction = null;
			this.OnBeginAction(asyncRequest);
			System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.OnWaitCallback), asyncRequest);
		}
		protected void BeginAction(object proxy, string command, params object[] args)
		{
			MethodDelegate action = FastInvoke.CreateMethodDelegate(proxy.GetType().GetMethod(command));
			this.BeginAction(action, proxy, args);
		}
		protected void BeginActionWithToolTip(MethodDelegate action, object obj, string toolTip, params object[] args)
		{
			EForm.AsyncRequest asyncRequest = new EForm.AsyncRequest(action, obj, args, System.Threading.SynchronizationContext.Current, toolTip);
			this.inAsyncAction = null;
			this.OnBeginAction(asyncRequest);
			System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.OnWaitCallback), asyncRequest);
		}
		protected void BeginActionWithToolTip(object proxy, string command, string toolTip, params object[] args)
		{
			MethodDelegate action = FastInvoke.CreateMethodDelegate(proxy.GetType().GetMethod(command));
			this.BeginAction(action, proxy, new object[]
			{
				toolTip,
				args
			});
		}
		protected virtual void OnBeginAction(EForm.AsyncRequest context)
		{
			if (this.waitingForm.Visible)
			{
				throw new EESException("后台正在执行,请稍候……");
			}
			this.waitingForm.Message = context.ToolTip;
			this.waitingForm.Show();
		}
		protected virtual void OnEndAction(EForm.AsyncResponse context)
		{
			this.waitingForm.Visible = false;
		}
		private void OnWaitCallback(object state)
		{
			EForm.AsyncRequest asyncRequest = (EForm.AsyncRequest)state;
			object result = null;
			System.Exception exception = null;
			try
			{
				result = asyncRequest.Method(asyncRequest.Obj, asyncRequest.Args);
			}
			catch (System.Exception ex)
			{
				exception = ex;
			}
			EForm.AsyncResponse state2 = new EForm.AsyncResponse(asyncRequest.Method, result, asyncRequest.Args, exception);
			System.Threading.SynchronizationContext context = asyncRequest.Context;
			if (context != null)
			{
				context.Post(new System.Threading.SendOrPostCallback(this.OnSendOrPostCallback), state2);
			}
		}
		private void OnSendOrPostCallback(object state)
		{
			EForm.AsyncResponse asyncResponse = (EForm.AsyncResponse)state;
			this.OnEndAction(asyncResponse);
			if (asyncResponse.Exception != null)
			{
				System.Windows.Forms.MessageBox.Show(EESException.getException(asyncResponse.Exception).Message);
				return;
			}
			this.OnActionComplete(asyncResponse);
		}
		protected virtual void OnActionComplete(EForm.AsyncResponse context)
		{
		}

  这是摘录的项目里面基类窗体关于SynchronizationContext的封装,子类只要使用各种BeginAction就行了,然后在OnActionComplete里面处理访问UI控件的操作.

 

posted @ 2019-05-23 08:00  Charltsing  阅读(654)  评论(0编辑  收藏  举报