在實際開發應用中,非UI線程操作UI是普遍存在的,在.net下一般是通過Control.Invoke的方法來進行操作,但到處都是Control.Invoke代碼維護可是一件麻煩的事情。以下通過接口和隊列來規范非UI線程操UI的實現。
既然要規范處理那接口是個不錯的選擇,以下定義一個簡單的執行接口
public interface IInvokeItem
{
void Execute();
}
以下是擴展一個簡單的操作類封裝
class ControlInvoke<CONTROL,DATA> : IInvokeItem
{
public ControlInvoke(CONTROL control, DATA data, Action<CONTROL, DATA> action)
{
mControl = control;
mData = data;
mAction = action;
}
private CONTROL mControl;
private DATA mData;
private Action<CONTROL, DATA> mAction;
public void Execute()
{
mAction(mControl, mData);
}
}
規則定好了,那接下來要做的事情就是寫一個簡單的隊列處理。
public class Dispatch
{
static Dispatch()
{
Instance = new Dispatch();
}
public void Add<CONTROL, DATA>(CONTROL control, DATA data, Action<CONTROL, DATA> action)
{
ControlInvoke<CONTROL, DATA> item = new ControlInvoke<CONTROL, DATA>(control, data, action);
Add(item);
}
private Queue<IInvokeItem> mQueues = new Queue<IInvokeItem>();
public static Dispatch Instance
{
get;
set;
}
public void Add(IInvokeItem item)
{
lock (this)
{
mQueues.Enqueue(item);
}
}
public void Execite()
{
lock (this)
{
while (mQueues.Count > 0)
{
mQueues.Dequeue().Execute();
}
}
}
}
一個簡單的調用規則就完成,接下來就是如果在winform下面用了;首先可以在界面定義一個timer,可以指定時間內執行Dispatch的工作。
private void timer1_Tick(object sender, EventArgs e)
{
ThreadInvoke.Dispatch.Instance.Execite();
}
當需要在線程中操作UI只需要向ThreadInvoke.Dispatch添加item即可,對於它的執行是完全不用關心的。以下是起一個線程不停地向一個文本框添加一個GUID值
private void cmdTest_Click(object sender, EventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(OnTest);
}
private void OnTest(object state)
{
while (true)
{
ThreadInvoke.Dispatch.Instance.Add<RichTextBox, Guid>(
richTextBox1, Guid.NewGuid(), (c, d) => {
richTextBox1.AppendText(d.ToString("N"));
richTextBox1.AppendText("\r\n");
});
System.Threading.Thread.Sleep(10);
}
}
這樣一個不使用Control.Invoke來實現非UI線程操作UI的方法就完成了.至於靈活性來說那就看你如何發揮IInvokeItem了:)
