2014-12-10 77 views
0

我一直在试图实现多类线程GUI管理。由于我希望不同的线程在不同的.cs文件中的多个类中传播,以根据需要更新UI。NullReferenceException @ Dispatcher和其他GUI问题

我已经搜索了stackoverflow和其他来源,发现大多数人使用Dispatcher.Invoke或类似的东西。所以,我决定开始测试......那么下面

是在一个名为wThread.cs类线程,

public class wThread 
{ 
    public EventHandler SignalLabelUpdate; 
    public Dispatcher uiUpdate; 

    public wThread() 
    { 
     uiUpdate = Program.myForm.dispat; 
     //the uiUpdate seems to be null for some reason... If i am doing it wrong how do i get the dispatcher? 
     Thread myThread = new Thread(run); 
     myThread.Start(); 
    } 
    Action myDelegate = new Action(updateLabel); 
    // is there a way i can pass a string into the above so updatelabel will work? 

    public void updateLabel(String text) 
    { 
     if (SignalLabelUpdate != null) 
      SignalLabelUpdate(this, new TextChangedEvent(text)); 
    } 

    public void run() 
    { 
     while (uiUpdate == null) 
      Thread.Sleep(500); 
     for (int i = 0; i < 1000; i++) 
     { 
      //I hope that the line below would work 
      uiUpdate.BeginInvoke(new Action(delegate() { Program.myForm.label1.Text = "count at " + i; })); 
      // was also hoping i can do the below commented code 
      // uiUpdate.Invoke(myDelegate) 
      Thread.Sleep(1000); 
     } 
    } 
} 

下面是我Form1.cs的是从Visual Studio 2012的预加载代码,

public partial class Form1 : Form 
{ 
    public Dispatcher dispat; 
    public Form1() 
    { 
     dispat = Dispatcher.CurrentDispatcher; 
     InitializeComponent(); 
     wThread worker = new wThread(); 
    } 
} 

我的大部分问题在上述意见,但这里有他们列出:

  1. 的由于某种原因,uiUpdate似乎为空...如果我做错了,我该如何获得调度程序? (wThread.cs问题)

    uiUpdate = Program.myForm.dispat' 
    
  2. 有没有办法可以传递一个字符串到上述所以updatelabel是否行得通呢?

    Action myDelegate = new Action(updateLabel); 
    
  3. 我希望下面的行会工作

    uiUpdate.BeginInvoke(new Action(delegate() { Program.myForm.label1.Text = "count at " + i; })); 
    
  4. 也希望我可以做下面的注释代码

    uiUpdate.Invoke(myDelegate) 
    

编辑:让我感动的wThread构造函数wThread worker =新的wThread()out of form1初始化区域...并且它修复了我的空指针。相反,我将wThread构造函数移动到构造窗体的静态主void中,就像Application.Run(myForm);

不幸的是,wThread不会启动,直到我关闭用户界面..什么是最好的事情要做到这一点?在Application.Run启动我的Form并使用该线程启动我的真实线程之前创建另一个线程?

+2

你使用的是什么UI技术?我看到调度员和表格? WinForms或WPF? – bic 2014-12-10 21:48:09

+0

在后台线程上实现工作的最简单方法是使用MVVM(假设你在WPF中):http://stackoverflow.com/a/2034333/1561465 – 2014-12-10 21:49:40

回答

0

@ 1:在Form1的构造函数中,在dispat = Dispatcher.CurrentDispatcher;处放置一个断点并检查值是多少。它可能只是Dispatcher.CurrentDispatcher为空,你必须得到它,也就是稍后,不是正确的在ctor

@ 2是的。使用Func<string>代替操作。 InvokeBeginInvoke需要一个代表,以及一组构成调用委托参数的params object[]。当然,传递的参数数组必须与委托签名完全匹配,所以在使用Func<string>时,只需使用一个对象[]:一个字符串。

@ 3 - 是的,只要i是一个简单的本地变量,可以通过委托关闭来捕获,就可以工作。如果它是foreach迭代器或一些非本地成员,它可能有问题,但是,不同的故事。

@ 4 - 是的,它会工作,只记得通过Func<string> params。

+1

这不仅仅是一个答案,而是一个答案,不如使用BeginInvoke上的任务更好,因为在http://stackoverflow.com/questions/22686467/use-task-run-instead-of-delegate-begininvoke – tradetree 2014-12-10 22:51:35

+0

@tradetree - 几乎任何事情都会更好,Rx,Task ,即使是旧的BackgroundWorker也足够了,并且可以节省一些打字的时间。但是,我得到的印象是,OP特意询问了这套工具。最近,很容易找到有关任务的文章/教程,甚至有关通过BGW隐式使用线程的文章仍然存在,当它们询问winforms和线程时,它们从谷歌中弹出。因此,这一次,我只打算回答具体问题。 – quetzalcoatl 2014-12-10 23:03:49

+0

嘿,还必须注意的是,在某些地方,任务和它们的整个底层框架实际上比仅仅“将该代码反弹到该调度器/线程”+某些锁定或线程同步更加复杂和难以完全理解:)但是,那不是地点/时间。我的观点:背景为初学者,高级任务,BeginInvoke为绝望又名“真的没有时间”/“不要忘记”/“我写和不在,再见”。 – quetzalcoatl 2014-12-10 23:07:27