嗯,问题是我为每个传递给GUI的事件都有很多这样的代码,我该如何缩短呢?我想,宏不会做这项工作。是否有更通用的方法来做“模板”这样的事情?
private delegate void DownloadProgressDelegate(object sender, DownloaderProgressArgs e);
void DownloadProgress(object sender, DownloaderProgressArgs e) {
if (this.InvokeRequired) {
this.BeginInvoke(new DownloadProgressDelegate(DownloadProgress), new object[] { sender, e });
return;
}
label2.Text = d.speedOutput.ToString();
}
编辑:
好的,我怎么能在BeginInvoke中使用匿名委托来实现这个目的:
this.BeginInvoke(new DownloadProgressDelegate(DownloadProgress), new object[] { sender, e });
答案 0 :(得分:1)
我个人更喜欢将实际操作放在Action
中,然后检查this
是否需要调用 - 这样做的好处是不需要声明这么多delegate
个与BeginInvoke
一起使用。换句话说,
void DownloadProgress(object sender, DownloaderProgressArgs e)
{
Action updateLabel = () => label2.Text = d.speedOutput.ToString();
if (this.InvokeRequired)
{
this.BeginInvoke(updateLabel);
}
else
{
updateLabel();
}
}
void DownloadSpeed(object sender, DownloaderProgressArgs e) {
Action updateSpeed = () =>
{
string speed = "";
speed = (e.DownloadSpeed / 1024).ToString() + "kb/s";
label3.Text = speed;
};
if (this.InvokeRequired)
{
this.BeginInvoke(updateSpeed);
}
else
{
updateSpeed();
}
}
这种方法非常适合在Control
上使用Action
的扩展方法,并通过InvokeRequired
检查来运行它。
至少,扩展方法应该类似于:
public static void MaybeInvoke(this Control c, Action action)
{
if (c.InvokeRequired)
{
this.BeginInvoke(action);
}
else
{
action();
}
}
令人讨厌的是,在.NET 3.5之前没有引入非泛型Action
,所以你需要在我给出的示例中稍微修改一下 - 可能使用MethodInvoker
- 如果你我正在使用早期版本。
答案 1 :(得分:0)
你可以试试T4 ...但我不知道它是否适合你的情况。
答案 2 :(得分:0)
一个简单的想法是创建一个例程,根据请求类型枚举和使用switch语句处理所有BeginInvoke案例。那么至少你只需要检查一次InvokeRequired。请注意,您应该使用if / else而不是return来控制流程。
答案 3 :(得分:0)
嗯,一种方法可能是将通用代码放在静态类中,并像访问它一样访问它:
Utility.DownloadSpeedUpdate(frm, sender, e);
答案 4 :(得分:0)
.net(在某种意义上)是一个相当差的UI框架,它积极地鼓励你所遇到的问题,以及业务逻辑和UI的混合。
您可以使用泛型,委托和基类/静态助手方法取得一些进展。
但是,理想情况下,您需要在.net之上层叠UI管理器,以便正确地帮助您解决此问题。这将允许您将UI与其执行的命令分开(即,您可以动态地将UI事件(如按键,菜单选项,按钮单击等)绑定到基础命令对象,而不是直接处理UI事件。 UI事件处理程序只是查找绑定到事件的命令,然后调用集中的“执行命令X”方法,这将处理UI线程的所有编组等。
除了清理整个混乱之外,这还可以让您轻松地将关键绑定和脚本/自动化等内容添加到您的应用程序中,并使UI更具可扩展性和可维护性。
这是WCF中使用的核心命令调度方法并非巧合 - 如果您没有使用WCF,那么很遗憾,您需要实现等效的。实现一个基本的命令调度系统需要一些工作,但除非你的应用程序是微不足道的,否则你会很高兴你做到了。
答案 5 :(得分:0)
如果您有许多需要InvokeRequired检查的函数,这里有一个示例可以为您节省大量代码。你应该注意到一些重要的事情:
EventHandler<DownloaderProgressArgs>
而不是为每个函数创建新的委托。这是我设置用于测试GetInvokeRequiredDelegate&lt; T&gt;()的所有代码:
public partial class Form1 : Form
{
public event EventHandler<DownloaderProgressArgs> OnDownloadProgress;
public event EventHandler<DownloaderProgressArgs> OnDownloadSpeed;
public Form1()
{
InitializeComponent();
OnDownloadProgress += GetInvokeRequiredDelegate<DownloaderProgressArgs>(DownloadProgress);
OnDownloadSpeed += GetInvokeRequiredDelegate<DownloaderProgressArgs>(DownloadSpeed);
new System.Threading.Thread(Test).Start();
}
public void Test()
{
OnDownloadProgress(this, new DownloaderProgressArgs() { DownloadSpeed = 1000, speedOutput = 5 });
OnDownloadSpeed(this, new DownloaderProgressArgs() { DownloadSpeed = 2000, speedOutput = 10 });
}
EventHandler<T> GetInvokeRequiredDelegate<T>(Action<object, T> action) where T : EventArgs
{
return ((o, e) =>
{
if (this.InvokeRequired)
{
this.BeginInvoke(action, new object[] { o, e});
} else
{
action(o, e);
}
});
}
void DownloadProgress(object sender, DownloaderProgressArgs d)
{
label2.Text = d.speedOutput.ToString();
}
void DownloadSpeed(object sender, DownloaderProgressArgs e)
{
string speed = "";
speed = (e.DownloadSpeed / 1024).ToString() + "kb/s";
label3.Text = speed;
}
}
public class DownloaderProgressArgs : EventArgs {
public int DownloadSpeed;
public int speedOutput;
}