使用ShowDialog()从STA线程显示窗口

时间:2015-01-22 11:27:47

标签: c# wpf windows mvvm showdialog

我需要从dll项目打开一个窗口(在后台运行或在调用时触发)。为此,我需要从标记为[STAThread]的方法打开一个窗口来创建窗口的实例。

我使用MVVM模式将ViewModel绑定到View,并将视图作为usercontrol添加到MainWindow。

在视图上有一个按钮绑定到一个关闭'关闭的命令。窗户。 ViewModel中的命令调用CloseCommand(),然后调用window.Close()方法。

代码段:

    MethodShowingTheWindow() {
        var idVM = new IDWindowViewModel();
        ShowForm<MainWindow>(idVM); // Works fine, Close Command closes the window.
        ShowForm<MainWindow>(idVM); // hits the ShowDialog() line, then just jumps to the while loop 
        ShowForm<MainWindow>(idVM);        // waiting for the thread to finish. Never displays the window.
        ShowForm<MainWindow>(idVM);

    }

    [STAThread]
    public void ShowForm<T>(IViewModel vm) {
        Thread th = new Thread(new ThreadStart(delegate {
            var window = new MainWindow();
            window.DataContext = vm;

            vm.CloseAction = new Action(() => window.Close()); // Does this when the Close Action is called from the viewmodel (Close the window).

            try {
                window.ShowDialog();
            } catch (Exception ex) {
                throw ex;
            }
        }));

        th.ApartmentState = ApartmentState.STA;
        th.Start();

        while (th.IsAlive) {
            //Wait for thread to finish
        }
    }

我需要知道的是为什么窗口不会出现在第二个ShowWindow(idVM)调用中?我能想到的是窗口未正确关闭/处置。我尝试将以下内容添加到CloseAction操作:

...
vm.CloseAction = new Action(() => {
    if (window is IDisposable) (window as IDisposable).Dispose();
    window.Close();
});

但是(窗口是IDisposable)== false?

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

这是我针对您的方案的实现。使用Dispatcher以避免STA例外:

async Task MethodShowingTheWindow() 
{
    var idVM = new IDWindowViewModel();
    await ShowForm<MainWindow>(idVM); // Works fine, Close Command closes the window.
    await ShowForm<MainWindow>(idVM); // hits the ShowDialog() line, then just jumps to the while loop 
    await ShowForm<MainWindow>(idVM);        // waiting for the thread to finish. Never displays the window.
    await ShowForm<MainWindow>(idVM);
}

public await Task ShowForm<T>(IViewModel vm) 
{
    Dispatcher.InvokeAsync(() =>
    {
        var window = new MainWindow();
        window.DataContext = vm;
        System.Windows.Application.Current.Dispatcher.Invoke(() =>
        {
            vm.CloseAction = new Action(() => window.Close());
        });
        window.ShowDialog();
    });
}