2011-12-27 129 views
-1

我正在处理以下处理线程和线程优先级的程序。C#空引用异常

我已经构建了一个窗体窗体,其中包含一个富文本框(DisplayTextBox)和两个按钮(用于运行应用程序的StartButton和用于关闭应用程序的ExitButton)。

在窗体中,我创建了几个线程并且一个接一个地运行它们。每个线程使用的方法都可以在Threading类中找到。有问题的方法是PrintOnScreen()。

在此方法中,我将线程名称以及其优先级附加到StringBuilder类型的字符串。然后我想在DisplayTextBox(它在Form.cs中)中显示str的内容。

但是,我得到一个“NullReferenceException未处理:对象引用未设置为对象的实例”错误。错误总结如下:

DisplayTextBox.Text = Convert.ToString(str);

你能帮我解决这个错误吗?谢谢。

编辑

感谢所有您的帮助。为了解决这个问题,我将PrintOnScreen方法复制到Form.cs类并放弃了Threading.cs。

我后来使用了Anand给出的代码并将它放在t2.Join()之下。现在它像一个魅力。

+0

你知道哪个对象为null吗?这个问题只有两个可能的答案,第一个会是** DisplayTextBox **第二个会是** str **当然,我没有看到您在表单上传递对DisplayTextBox的引用。线程继承Form1并不意味着它具有对Form1上控件的引用。 – 2011-12-27 12:21:24

+0

即使您确实修复了代码并将引用传递给了** DisplayTextBox **,也必须调用更改文本,因为您无法修改除主UI线程之外的单独线程中的控件。 – 2011-12-27 12:23:50

+0

您应该真的考虑同步对从多个线程访问的数据的访问。例如,你是用两个线程写入同一个StringBuilder实例并迭代Threads-collection。 – Jan 2011-12-27 12:26:51

回答

3

问题发生在窗体的构造函数中。您再次声明DisplayText作为本地成员,以便表单的字段未初始化。像这样改变你的构造函数:

private void Form1_Load(object sender, EventArgs e) 
{ 
    DescTextBox.Visible = false; 
    DisplayTextBox = new RichTextBox(); 
    DisplayTextBox.Location = new Point(15, 31); 
    DisplayTextBox.Height = 258; 
    DisplayTextBox.Width = 303; 
    panel1.Controls.Add(DisplayTextBox); 
} 

它应该像你期望的那样工作。

编辑︰但要小心你会得到的问题,当你想从后台工作线程更改UI元素。在这些情况下,您将不得不使用调用模式。

1

您不能与除主应用程序线程以外的任何其他线程的控件进行通信。你需要为此使用dispather。看看这里:http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx

编辑
@Fischermaen - 嘿,没有注意到这一点,但它仍然不会因为线,在那里他写失败的工作。他仍然需要使用调度设置从非主线程控制

EDIT 2个
相关主题的Text属性:
How to update the GUI from another thread in C#?
In WinForms, why can't you update UI controls from other threads?

+0

感谢关于调度员的建议。我会尝试一下,让它知道它是否有效。感谢大家:) – Joe 2011-12-27 12:33:36

1

我简单的控制台应用程序尝试这个它运行良好。 问题出在DisplayTextBox上。如果你想与任何控件进行交互,那么你必须使用UI线程或Dispatcher。 使用在你的线程类下面的代码中,而是

DisplayTextBox.Text = Convert.ToString(str); 

使用这一个

Dispatcher.Invoke(DispatcherPriority.Normal, 
        new Action(
      delegate() 
      { 
       DisplayTextBox.Text = Convert.ToString(str); 
      } 
     )); 
+0

没错。在控制台应用程序中,它工作正常。它给我的问题是,当我尝试将其转换为Windows应用程序。 – Joe 2011-12-27 12:32:34

+0

尝试上面的代码。它应该工作正常。 – Anand 2011-12-27 12:33:50

+0

我粘贴了代码,它给了我错误 - 名称'Dispatcher'在当前上下文中不存在。 – Joe 2011-12-27 12:40:07

0

庵。 从这里看不到,但是你遇到困难的部分原因是代码中缺少封装和糟糕的生命周期管理。

在PrintOnScreen方法中实例化str,给它一个更好的名字,没有appranrent需要成为成员变量,根本不需要公开。

代替具有空隙的结果,它已经返回字符串结果

例如

SomeTextBox = PrintOnScreen(); // (GetThreadDetails might be a better name...) 

作为提示不要混合表示和逻辑。让你的用户界面控制彻底在任何拥有它们。

,不要做

public SomeType SomeName; 

使其属性,并给它getter和一个setter,即使是短期形式

公共SOMETYPE SomeName {获得;设置;}

其他代码位可以做一些真正愚蠢像

Form1.SomeType = (SomeOtherType)someVar; // with appaling consequences. 

没有什么应该有一个以上的所有人,任何其他路径引向绝路。 PS:str.ToString()是比Convert.ToString(str)更好的选择;

0

嗯,这对我来说不是很清楚你想要达到什么目的,然而问题是当你试图访问控制时,基本形式Threading类继承自未被加载(窗口句柄仍然不存在)这也是你在Form1本身上什么也看不到的原因,因为你的线程输出为隐藏的形式,这是不显示的。

我认为你正在尝试解决由SOReader引发的线程访问问题。这不是这样做的正确方法。