繁体   English   中英

关闭另一个线程拥有的窗口

[英]Closing a window owned by a different thread

我是新手。 我在WPF应用程序中使用后台线程与数据库和消息通信进行对话。

视图模型之一应打开一个单独的窗口。 由于这应该作为UI线程运行,所以我在做:

    private void OnSelection(SelectionType obj)
    {
        Thread thread = new Thread(ShowRegionWindow);
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    }
    private void ShowRegionWindow()
    {
        var rWindow = new RegionWindow();
        rWindow .Show();
        rWindow .Closed += (s, e) => System.Windows.Threading.Dispatcher.ExitAllFrames();
        System.Windows.Threading.Dispatcher.Run();
    }

现在,我需要在另一个消息上关闭此窗口。 我怎么做?

在进一步介绍之前,您说过您是线程技术的新手,我想强调一下,您的应用程序可能没有充分的理由在不同线程上打开窗口。 您正在使用MVVM是件好事,但您可能做得不好。 理想情况下,所有视图和视图模型都应位于主UI线程上。 与视图模型进行交互之前,模型层中的所有工作线程都需要调用UI调度程序。 例如,您可能在工作线程上有一个update事件,请在视图模型上调用处理程序以更新UI。 UI调度程序应该在该事件被调用之前或之后立即被调用。 (不过要清楚一点,该模型不应该知道视图模型。)

实际上,您似乎正在UI事件处理程序中创建一个新的Window,这意味着您可能应该这样做:

private void OnSelection(SelectionType obj)
{
    var rWindow = new RegionWindow();
    rWindow.Show();
}

但是,也许您完全有理由按照自己的方式进行操作。 如果是这样,从调用线程关闭新窗口的一种方法是传递事件。 您可以执行以下操作:

private event Action CloseRegionWindows = delegate { }; // won't have to check for null

private void OnSelection(SelectionType obj)
{
    Thread thread = new Thread(() => ShowRegionWindow(ref CloseRegionWindows));
    ...
}

private void ShowRegionWindow(ref Action CloseRegionWindows)
{
    var rWindow = new RegionWindow();
    rWindow.Show();
    CloseRegionWindows += () => rWindow.Dispatcher.BeginInvoke(new ThreadStart(() => rWindow.Close()));
    ...
}

然后在某处引发该事件:

private void OnClick(object sender, RoutedEventArgs args)
{
    CloseRegionWindows();
}

再次阅读您的一些评论后,我认为我对该场景有了更好的理解。 这是您需要做的。

首先,请确保您的一个ViewModels具有对需要打开和关闭窗口的Model的引用。 一种实现方法是构造函数依赖注入。

public ViewModel(Model model) // or IModel
{
    ...

接下来,您需要捕获该ViewModel中的UI调度程序。 最好的地方可能也是ViewModel构造函数。

private Dispatcher dispatcher;

public ViewModel(Model model)
{
    dispatcher = Dispatcher.CurrentDispatcher;
    ...

现在在您的模型中创建两个事件; 一个打开,另一个关闭窗口。

class Model
{
    internal event Action OpenWindow = delegate { };
    internal event Action CloseWindow = delegate { };
    ...

并在您的ViewModel构造函数中订阅它们。

public ViewModel(Model model)
{
    dispatcher = Dispatcher.CurrentDispatcher;
    model.OpenWindow += OnWindowOpen;
    model.CloseWindow += OnWindowClose;
    ...
}

现在,使用ViewModel类中的UI Dispatcher打开和关闭窗口;

private Window window;

private void OnWindowOpen()
{
    // still on background thread here

    dispatcher.BeginInvoke(new ThreadStart(() =>
    {
        // now we're on the UI thread

        window = new Window();
        window.Show();
    }
}

private void OnWindowClose()
{
    dispatcher.BeginInvoke(new ThreadStart(() =>
    {
        window.Close();
    }
}

最后,就像引发任何事件一样,从模型的后台线程引发OpenWindow和CloseWindow事件。 您的模型可能看起来像这样:

class Model
{
    private Thread worker;

    internal event Action OpenWindow = delegate { };
    internal event Action CloseWindow = delegate { };

    public Model()
    {
        worker = new Thread(Work);
        worker.Start();
    }

    private void Work()
    {
        while(true)
        {
            if (/*whatever*/) OpenWindow();
            else if (/*whatever*/) CloseWindow();
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM