在多线程期间检索Windows窗体属性

时间:2017-02-20 22:55:01

标签: .net vb.net multithreading winforms

我对VB.NET有些熟悉,但对于多线程来说却是一个新手。

我有一种情况,我已经开始一个与主进程分开的新线程,并且使用我创建的新线程并显示一个新表单。新表单的Load()过程中的一个方法是设置表单的位置,具体取决于主窗体(Form1)的位置。

然而,我发现,当我从这个帖子中引用Form1的属性时,它们没有被准确检索。特别是,当Location.X和Location.Y属性实际上是更大的整数时,它们显示为0。

var str = ['abc.de', 'wok.pl', 'qwdok.com'];

console.log(str.map(v => /\w+\.(de|com)$/g.test(v) ? v + ' is valid' : v + ' is invalid'));

我发现最奇怪的部分是当我在这个SetLocation()方法中设置一个断点,并且程序因调试而中断时,X和Y变量将首先在值显示中注册为0:

x and y zero values

但是,当我正在调试时,如果我在处于暂停状态的IDE中访问有关Form1的信息,而不恢复应用程序,然后返回查看X和Y值,则属性最终将显示为实际价值。

x and y actual values

在调试断点中加载表单属性是否正常?这种现象是VB.NET中多线程的一个已知方面吗?为了让我的新线程能够访问这些信息,我是否必须通过更复杂的线程通信方法?

谢谢!

1 个答案:

答案 0 :(得分:3)

这很难解释,但我会尽力而为。

在您的用法中,Form1是Form Class类型,而不是表单本身。

这是VB.NET中常见且持续的混淆。

  My.Forms

仅列出您在项目中定义的表单设计...... 不是主动形式自己。

如果您的项目以Form1开头,VB.NET会创建该表单的 INSTANCE 拥有自己的身份和内存分配。

当您打开引用初始表单的新表单时,需要将该身份传递给第二个表单。

最好的办法是,恕我直言增强Form2的构造函数。跟随。

Public Sub New(owner_Form As Form1)
    Owner = owner_Form
    ' This call is required by the designer.
    InitializeComponent()

End Sub

然后在您的SetLocation代码中使用以下

    parentx = Owner.Location.X
    parenty = Owner.Location.Y
    parentw = Owner.Width
    parenth = Owner.Height

NOW:您的示例代码未指明线程在哪里启动新表单。

如果线程代码是Form1类的一部分,您只需在线程代码中执行以下操作。

Dim Form2 as New Form2(me)

如果它比那更深,你需要将Me传递给层次结构。

如果您的应用程序不是太复杂,替代方法是使用其他一些全局或共享类引用来识别主要表单。

示例:

在全局模块中添加

Public Main_Form as Form1

Form1_Load 中添加

Main_Form = Me

然后在您的SetLocation代码中使用以下

    parentx = Main_Form.Location.X
    parenty = Main_Form.Location.Y
    parentw = Main_Form.Width
    parenth = Main_Form.Height

为何如此复杂

您必须强迫自己记住的是,在执行期间,您的程序可以创建任意数量的Form1或任何其他形式。 每个人都有自己的身份。

My.Forms仅列出原型。

交叉线程的UI引用

正如Enigmativity所提到的,从非UI-Thread引用UI可能是一个危险的地方,并且充满了会让你感到沮丧的问题。我确实同意通过另一个线程使用UI正在非常薄的冰上运行,但是如果完全理解模型,有时候这种引用是可以接受的。只读用法,例如当前示例就是一个例子。

然而,这个“答案”将是相同的,无论第二个表单是从新线程开始还是从初始表单生成为普通的Form.Show()

PS:您还可以简化我们的代码

Me.Location = <whatever method you choose>.Location
Me.Size = <whatever method you choose>.Size