Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 在多线程处理期间检索Windows窗体属性_.net_Vb.net_Multithreading_Winforms - Fatal编程技术网

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

.net 在多线程处理期间检索Windows窗体属性,.net,vb.net,multithreading,winforms,.net,Vb.net,Multithreading,Winforms,我对VB.NET有点熟悉,但对多线程非常陌生 在这种情况下,我启动了一个与主进程分离的新线程,并使用该新线程创建并显示了一个新表单。新表单的Load()过程中的一个方法是根据主表单(Form1)的位置设置表单的位置 然而,我发现,当我从这个线程中引用Form1的属性时,它们并没有被准确地检索到。特别是,Location.X和Location.Y属性显示为0,而实际上它们是更大的整数 Private Sub SetLocation() Dim parentx, parenty, pare

我对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:

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

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


谢谢大家!

这很难解释,但我会尽力的

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

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

  My.Forms
仅列出您在项目中定义的表单设计不是活动表单本身。

  My.Forms
如果您的项目以Form1开始,VB.NET将创建该表单的实例,该实例具有自己的标识和内存分配。

打开引用初始表单的新表单时,需要通过引用将该标识传递给第二个表单

IMHO最好的方法是扩充Form2的构造函数。
如下所示

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

End Sub
然后在设置位置代码中使用以下命令

    parentx = Owner.Location.X
    parenty = Owner.Location.Y
    parentw = Owner.Width
    parenth = Owner.Height
    parentx = Main_Form.Location.X
    parenty = Main_Form.Location.Y
    parentw = Main_Form.Width
    parenth = Main_Form.Height
现在:示例代码没有指明启动新表单的线程的位置

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

Dim Form2 as New Form2(me)
如果它比这更深,您需要通过层次结构向下传递Me

如果应用程序不太复杂,另一种方法是使用其他一些全局或共享类引用来标识主窗体

例如:

在全局模块中添加

Public Main_Form as Form1
并在表格1中加载添加

Main_Form = Me
然后在设置位置代码中使用以下命令

    parentx = Owner.Location.X
    parenty = Owner.Location.Y
    parentw = Owner.Width
    parenth = Owner.Height
    parentx = Main_Form.Location.X
    parenty = Main_Form.Location.Y
    parentw = Main_Form.Width
    parenth = Main_Form.Height
为什么这么复杂

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

  My.Forms
My.Forms仅列出原型

跨线程UI引用

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

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

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

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

My.Forms.Form1不是您想象的那样。这是表单模型,而不是实例。您需要在某个地方声明Form1或将其转发给线程。您说,“我已经启动了一个与主进程分离的新线程,并使用该新线程创建并显示了一个新表单”,但这很糟糕。您应该只使用主线程来创建UI元素。仅在处理非UI数据时使用线程。@Enigmativity当数据加载到另一个线程时,我使用一个线程来显示加载屏幕。我知道它在技术上是一个UI元素,但这不是线程的用途之一吗?@Trevor My SetLocation()方法在我从主进程加载此表单时起作用,甚至使用My.Forms.Form1访问表单的属性。你能解释一下为什么它会从主进程而不是从线程工作吗?@Marisha-不,你不应该对UI做任何事情,除非它在主UI线程上。很难把它做好。如果你正在加载数据,你可以在另一个线程上完成。为什么还要让你的UI多线程呢?非常感谢你的回复。我想我理解传递Form1的对象引用的结构,而不仅仅是访问Form1的类,所以如果需要的话,我想我有工具来实现它。不过,我确实希望尽可能彻底地了解它是如何工作的,但我仍然不太明白在调试中断期间看到了什么(在调试中断期间,值最初为0,然后在同一暂停期间不久发生了更改)。为什么会发生这种情况,为什么我停留在主进程线程上时不会发生这种情况?谁知道。。IDE有时会做一些奇怪的事情。我从来没有真正弄清楚起始表单的真正定义。谢谢你的洞察力!嘿@Trevor,我还有一个相关问题,你能帮我吗?我已将加载屏幕放在主线程上,但无法将其居中。结果表明,表单的Location.X和Location.Y值是屏幕坐标,表单