Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/17.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
如何在自己的线程中打开WPF窗口,然后关闭它?_Wpf_Vb.net_Multithreading_Window - Fatal编程技术网

如何在自己的线程中打开WPF窗口,然后关闭它?

如何在自己的线程中打开WPF窗口,然后关闭它?,wpf,vb.net,multithreading,window,Wpf,Vb.net,Multithreading,Window,我试图给一些用户娱乐,并显示一个“请等待”窗口,与字幕,在加载一个单独的复杂窗口。我试图通过在新线程中加载窗口来实现这一点,如下所示: Public Function ShowPleaseWait() As System.Threading.Thread Dim PleaseWait As New System.Threading.Thread(AddressOf LoadPleaseWait) PleaseWait.SetApartmentState(

我试图给一些用户娱乐,并显示一个“请等待”窗口,与字幕,在加载一个单独的复杂窗口。我试图通过在新线程中加载窗口来实现这一点,如下所示:


    Public Function ShowPleaseWait() As System.Threading.Thread
        Dim PleaseWait As New System.Threading.Thread(AddressOf LoadPleaseWait)
        PleaseWait.SetApartmentState(System.Threading.ApartmentState.STA)
        PleaseWait.IsBackground = True
        PleaseWait.Start()

        Return PleaseWait
    End Function

    Public Sub LoadPleaseWait()
        Dim window As New windowPleaseWait
        Try
            window.Show()
            System.Windows.Threading.Dispatcher.Run()
        Catch e As System.Threading.ThreadAbortException
            window.Close()
            window = Nothing
        End Try
    End Sub 
在调用代码中,它调用
ShowPleaseWait
,并保存线程供以后使用。。要关闭窗口,它会在保存的线程上调用
Thread.Abort
。这反过来将导致它进入
捕捉
。我已经尝试过很多不同的方法,不管有没有陷阱

这是第一次叫它的时候,效果非常好。但是,其他调用将在
window.Show()
处失败,例外情况是:
调用线程无法访问此对象,因为其他线程拥有它。


这让我很困惑,因为窗口是在调用
window.Show
的上方一行创建的,并且是本地的。它是如何被其他线程拥有的?如何修复此问题?

必须在UI线程上执行UI操作。这意味着,如果要从后台线程操作UI内容,则需要在执行UI操作之前将正在执行的代码/函数封送回UI线程

我建议您改变您的方法-在后台线程上执行“单独的复杂”咕噜工作,并将该代码从管理窗口的代码中移开。使用MVVM之类的模式或Prism之类的框架将有助于实现这种方法

您的流程应该是这样的:


    Public Function ShowPleaseWait() As System.Threading.Thread
        Dim PleaseWait As New System.Threading.Thread(AddressOf LoadPleaseWait)
        PleaseWait.SetApartmentState(System.Threading.ApartmentState.STA)
        PleaseWait.IsBackground = True
        PleaseWait.Start()

        Return PleaseWait
    End Function

    Public Sub LoadPleaseWait()
        Dim window As New windowPleaseWait
        Try
            window.Show()
            System.Windows.Threading.Dispatcher.Run()
        Catch e As System.Threading.ThreadAbortException
            window.Close()
            window = Nothing
        End Try
    End Sub 
  • 在空状态下加载主窗口

  • 开始您的数据加载UI体验(在您的情况下,“请稍候”动画)

  • 启动一个后台线程

  • 使用该后台线程获取和/或操作数据

  • 后台线程完成后,填充ViewModel,或将代码执行封送回UI线程以填充UI


再一次,看看使用MVVM或类似工具,这将有助于区分这些工作的各个部分是在哪里完成的(即,后台线程可以在模型中执行,并且永远不会靠近视图)。

我已经粘贴了您在此处显示的代码,无法重现该问题。(它有一个问题,但并没有引起您描述的问题。)不幸的是,当我尝试您发布的代码时,我可以调用ShowPleaseWait任意多次,我没有看到异常

肯定发生了两件事中的一件。可能,您已经修改了代码,简化了原始示例,以便在此处发布一些合理较小的内容,因此,您也可能已经删除了该问题。(如果我不得不冒险猜测的话,那就是你的暗淡窗口作为新窗口,它最初是一个类成员而不是本地成员,因此你每次都使用相同的窗口对象。这是我唯一能解释你描述的症状的东西。)

或者,我在与您不同的上下文中使用代码

为了研究最后一个问题,我将解释我正在做什么来尝试您的代码,这样您就可以看到是否有任何明显不同于您正在运行它的上下文的内容。我创建了一个新的WPF应用程序,并将您的方法粘贴到MainWindow.xaml.vb codebehind中。然后,我在窗口中添加了一个按钮,并在单击处理程序中调用了您的方法,因此:

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button2.Click
    ShowPleaseWait().Join()
End Sub
我在返回的线程上调用Join有两个原因。首先,我想阻止主UI线程,以验证辅助窗口是否真的在单独的线程上运行(实际上是这样)。第二,我想验证线程是否真的关闭了——通过线程中止来关闭它是一种非常非正统的方式。(正确的做法是关闭您在该线程上隐式创建的dispatcher,这将使对dispatcher.Run()的调用能够干净地退出。这就是我在开始时提到的问题。)

为了使我的示例与您的示例类似,我通过调用Thread.Abort关闭子窗口,尽管这不是一个好主意-我在该子窗口上的按钮的单击处理程序中执行此操作。(我突然想到,只有在从主线程调用该子线程的Abort时,问题才可能发生。因此,我还添加了几个按钮,让我这样做。没有任何更改-我仍然可以显示窗口,然后销毁线程,但我想销毁的次数不超过您描述的错误次数。)


因此,要么是您使用此代码的上下文导致其失败,要么是您在此处发布的代码意外删除了此问题。不管怎样,恐怕都需要更多的信息。

我甚至没有在您的代码中发现任何问题。 将这些方法放在主模块中

Public Function ShowPleaseWait() As System.Threading.Thread
    Dim PleaseWait As New System.Threading.Thread(AddressOf LoadPleaseWait)
    PleaseWait.SetApartmentState(System.Threading.ApartmentState.STA)
    PleaseWait.IsBackground = True
    PleaseWait.Start()

    Return PleaseWait
End Function

Public Sub LoadPleaseWait()
    Dim window As New windowPleaseWait
    Try
        window.Show()
        System.Windows.Threading.Dispatcher.Run()
    Catch e As System.Threading.ThreadAbortException
        window.Close()
        window = Nothing
    End Try
End Sub
现在,在需要显示窗口的任何地方调用该函数,如下所示

Dim myThreadWindow as System.Threading.Thread 
myThreadWindow  = ShowPleaseWait()
中止线程

myThreadWindow.Abort 

这是有道理的,但不能回答问题。为什么第一次能用,而不是第二次?一个男人走进他的机械师说:“我的安全带摩擦了我的脖子。”。机修工说,“驾驶摩托车。”——不幸的是,虽然这不是一项真正复杂的工作,但却加载了一个很长的列表视图。这只需要大约10秒钟,但我希望,作为一个事后思考,插播一些用户娱乐。它确实很好看,当它工作的时候。我希望我只需要添加一些小的东西来修复它。@John,我无法回答为什么它能一次又一次地工作,但我支持这样的评论:列表的生成/检索应该是在后台线程上发生的事情,而不是UI的显示。能够增加额外的功能总是很好的,但我认为最初的设计选择在某种程度上限制了你的选择——是时候进行一次小的重构了?slugster,恐怕你犯了一个典型的错误,认为只有一个UI线程。事实上,WPF应用程序可以自由创建任意数量的UI线程。在这种情况下,它可以