2010-05-08 59 views
0

嗯,问题是我有很多这样的代码传递给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(); 
} 

编辑:

OK,我怎么能做出这样的BeginInvoke使用匿名委托:

this.BeginInvoke(new DownloadProgressDelegate(DownloadProgress), new object[] { sender, e }); 

回答

0

你可以尝试T4 ...但我不知道这是否会适合你的情况很好。

0

一个卑微的想法是创建一个程序来处理基于请求类型枚举和使用switch语句所有的BeginInvoke情况。那么至少你只需要检查一次InvokeRequired。请注意,您应该使用if/else而不是返回来控制流。

0

当然,一种办法可以把静态类中的通用代码,并获得它一样,例如:

Utility.DownloadSpeedUpdate(frm, sender, e); 
1

我个人更喜欢把实际行动在Action,然后检查是否this需要一个调用 - 这也有利于不需要声明如此多的delegate s用于您的BeginInvoke s。换句话说,

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(); 
    } 
} 

烦人,非通用Action不引入到.NET 3.5,所以你需要修改的东西一点在我给的例子 - 可能使用MethodInvoker - 如果你使用的是早期版本。

0

.net(在某种意义上)有一个相当差的UI框架,积极鼓励你的问题,混合业务逻辑和用户界面。

您可能能够取得一些进展与仿制药,委托和基类/静态辅助方法。

然而,理想情况下,你需要在层上.NET之上的UI管理器,可以帮助你用这个正常。这将允许您将UI与其执行的命令分开(即,您可以将UI事件(如按键,菜单选项,按钮点击等)动态绑定到底层命令对象,而不是直接处理UI事件)。 UI事件处理程序只需查找绑定到事件的命令,然后调用集中的“execute Command X”方法,这将处理所有对UI线程的编组等。

除了清理解决这个问题,这使得您可以轻松地将键绑定和脚本/自动化等功能添加到您的应用中,并使界面无限扩展和维护。

这不是巧合,这是WCF中使用的核心命令分派方法 - 如果你不使用WCF,那么不幸的是你要实现一个等价的。实施一个基本的指挥调度系统需要一点点工作,但除非你的申请是微不足道的,否则你会很高兴你做到了。

0

下面是一个示例,如果您有许多需要InvokeRequired检查的函数,将为您节省大量编码。你应该注意几件重要的事情:

  • 我使用EventHandler<DownloaderProgressArgs>而不是为每个函数创建新的委托。
  • GetInvokeRequiredDelegate函数包装所有这些函数的代码。
  • 此代码可以移动到一个静态类中,让您在多种形式中共享此类代码,但这需要更多的工作和不同的结构。就像它在这里,函数只是知道你正在处理哪个表单,因为函数存在于表单中。

这是我建立测试GetInvokeRequiredDelegate <Ť>()的所有代码:

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; 
    }