2008年4月3日星期四

Invoke 的一点笔记

一直对Invoke这个方法不是很熟悉,今天在调查了一下,大体搞明白了,
Invoke是跨线程用的一个方法。
例如
有ThreadA, ThreadB两个线程,ThreadA中作了画面处理,中途遇到了大的计算,将计算放到ThreadB中,但是在ThreadB中做了一半,需要更新ThreadA中的某个属性,然后继续ThreadB的操作。
这种情况下,由于是ThreadA,ThreadB分离开的,谁都不能直接操作另一个Thread中的具体属性,
只好求助Invoke了。
Invoke,可以翻译成触发或者激活,那么Invoker就是触发器啦,触发什么呢,就是让另一个方法执行起来,所以经常用到的就是MethodInvoker 。
上面的情况,用代码来说明就是:
// Form1.cs
private void button1_Click(object sender, EventArgs e)
{
this.SetEnabledOfControls(false);
Thread threadB= new Thread(
delegate()
{
// 5秒代表假设这个ThreadB处理第一步计算可能要花5秒钟
Thread.Sleep(5000);
// 修改ThreadA(就是主线程Form线程)中的某个属性
this.SetEnabledOfControls(true);
// 修改完ThreadA的属性后,还要进行下一步计算,可能是花了1秒
Thread.Sleep(1000);
});
// 启动ThreadB
threadB.Start();
}
///
/// ThreadA中的处理,设定Enabled属性
///

private void SetEnabledOfControls(bool value)
{
// 这步判断,目的是确定执行这个方法的时候,下面要用的Controls是有根的,
// 也就是说,这个方法归根结底是只应该在ThreadA主线程中被执行的,不管在哪里激活他,
// 执行的时候,应该是在主线程内部执行。如果是其他的线程的话,就不能再执行了。
if (!this.IsHandleCreated))
{ return; }

// 这句稍微复杂,
// 其实隐藏了一个delegate声明,同时将这个隐藏的delegate关联上了一个方法体
// 执行的时候,只需要通知(也就是激活)这个delegate去执行,就可以了。
MethodInvoker mtdDelegate = (MethodInvoker)delegate()
{
// 这里面就是方法体,没有方法名,方法直接通过delegate转换,
// 就成了一个Delegate实例了。

// 设定Controls的Enabled属性为value
foreach(Control ctr in Controls)
{
ctr.Enabled = value;
}
};

// 判断这个方法是ThreadA直接调用的,还是从ThreadB内部通过Delegate委托调用的。
// 委托调用的场合,InvokeRequired属性会返回true,判断调用元不是本线程
if (this.InvokeRequired)
{
// 这种场合需要使用Invoke激活,让这个delegate去执行它内部的逻辑。
this.Invoke(mtdDelegate);
}
else
{
// 既然激活元就是当前的主线程ThreadA,
// 就让这个delegate自发激活,直接执行就可以了。
mtdDelegate.Invoke();
}
}
下面是抄来的。

public static class ControlUtil
{
public static object SafelyOperated(Control context, Delegate process)
{
return ControlUtil.SafelyOperated(context, process, null);
}

public static object SafelyOperated(Control context, Delegate process, params object[] args)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (process == null)
{
throw new ArgumentNullException("process");
}

if (!(context.IsHandleCreated))
{
return null;
}
if (context.InvokeRequired)
{
return context.Invoke(process, args);
}
else
{
return process.DynamicInvoke(args);
}
}
}
private void SetEnabledOfControls(bool value)
{
MethodInvoker process =
(MethodInvoker)delegate()
{
// 具体处理
};
ControlUtil.SafelyOperated(this, process);
}

没有评论: