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

标签 .net vb.net multithreading winforms

我对 VB.NET 有点熟悉,但对多线程非常陌生。

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

但是,我发现当我从这个线程中引用 Form1 的属性时,它们并没有被准确地检索到。特别是,Location.X 和 Location.Y 属性显示为 0,而实际上它们是更重要的整数。

Private Sub SetLocation()

    Dim parentx, parenty, parentw, parenth As Integer
    Dim parentForm As Form = My.Forms.Form1

    parentx = parentForm.Location.X
    parenty = parentForm.Location.Y

    parentw = parentForm.Width
    parenth = parentForm.Height

    Me.Location = New Point(parentx + (parentw / 2), parenty + (parenth / 2))

End Sub

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

x and y zero values

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

x and y actual values

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

谢谢!

最佳答案

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

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

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

  My.Forms

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

如果您的项目从 Form1 开始,VB.NET 会创建一个 实例 的那种形式有它自己的身份和内存分配。

当您打开一个引用初始表单的新表单时,你需要传递那个身份引用第二种形式。

最好的方法是,恕我直言,增加 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

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

如果线程代码是 Form1 类的一部分,您只需在线程代码中执行以下操作。
Dim Form2 as New Form2(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 只列出原型(prototype)。

跨线程 UI 引用

正如 Enigmativity 所提到的,从非 UI 线程引用 UI 可能是一个危险的地方,并且充满了会让你发疯的问题。我确实同意通过另一个线程使用 UI 是如履薄冰,但是在某些情况下,如果模型被完全理解,这样的引用是可以接受的。像当前示例这样的只读用法就是一个很好的例子。

但是,无论第二个表单是从新线程启动还是简单地从初始表单生成为普通 Form.Show(),这个“答案”都是相同的

PS:您还可以简化我们的代码
Me.Location = <whatever method you choose>.Location
Me.Size = <whatever method you choose>.Size

关于.net - 在多线程期间检索 Windows 窗体属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42355676/

相关文章:

c# - 高频计时.NET

.net - 使用 ClassInterfaceType.AutoDual 真的是个坏主意,即使使用 VB6?

vb.net - 我如何定位在运行时创建的图片框之一?网络

vb.net - 添加新数据后如何刷新我的 datagridview

asp.net - VB.NET SQL 限制提交尝试次数

C# - 在 XX 秒后停止线程

java - 包含同步块(synchronized block)的实例是否必须是单例?

c# - 为什么在重写的 Object.Equals 方法中抛出 NullReferenceException?

.net - Html.EditorFor(...) 如何知道循环的索引和项目?

c# - 线程已退出,Windows 窗体中的代码为 0