我对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:
但是,当我正在调试时,如果我在处于暂停状态的IDE中访问有关Form1的信息,而不恢复应用程序,然后返回查看X和Y值,则属性最终将显示为实际价值。
在调试断点中加载表单属性是否正常?这种现象是VB.NET中多线程的一个已知方面吗?为了让我的新线程能够访问这些信息,我是否必须通过更复杂的线程通信方法?
谢谢!
答案 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