从类库项目启动WPF窗口

8
我正在创建一种类似于“加载屏幕”的东西,将在类库中显示,在进行一些繁重的处理之前显示,然后在处理完成后隐藏。我的问题是,无论我做什么,繁重的处理似乎都会阻塞UI线程。我不得不设置带有[STAThread]属性的方法,以便窗口实际上被创建。然后我使用以下方式显示窗口:
bw = new BusyWindow();
bw.Show();

然后,当处理完成时,只需使用bw.Hide()隐藏它。我已经为处理创建了一个任务,所以它应该在单独的线程上运行...除非STAThread完全搞砸了它?

更多代码:

var taskStart = Task.Factory.StartNew(() => ShowBusyWindow());
var taskProcess = taskStart.ContinueWith((antecedent) => GetInternal());
var taskEnd = taskProcess.ContinueWith((antecedent) => HideBusyWindow());

return taskProcess.Result;

并显示繁忙窗口

public void ShowBusyWindow()
        {
            bw = new BusyWindow();
            bw.Show();
        }

并且隐藏繁忙窗口:

public void HideBusyWindow()
        {
            bw.Close();
        }

我还应该提到,我正在尝试将这个库暴露给COM,以便可以从一些VB6代码中运行它。我不知道这是否会对任何事情产生影响...?


3
请提供更多的代码,特别是您创建任务并开始处理的部分。 - PVitt
我已经添加了更多的信息。 - Harry
1
我想指出,让类库创建自己的UI元素可能是危险的。最好的做法是在类库开始“重度处理”之前,只需引发某种通知,这样使用该库的任何客户端都可以决定是否显示“加载”屏幕。 - Dan J
可以,但我希望这个加载界面是在WPF中实现的,有办法吗? - Harry
1个回答

6

好的,所以一个 WPF 窗口可以通过以下方法从类库或任何其他线程中调用:

thread = new Thread(() =>
        {
            bw = new BusyWindow();
            bw.Show();
            bw.Closed += (s, e) => bw.Dispatcher.InvokeShutdown(); 
            Dispatcher.Run();
        });
        thread.SetApartmentState(ApartmentState.STA);
        //thread.IsBackground = true;
        thread.Start();

对于这个任务,你实际上不需要IsBackground。唯一需要它的情况是如果线程Dispatcher在窗口关闭时没有关闭,那么它会创建一个“幽灵线程”。

显然,公寓状态必须设置为STA,以便可以实际创建Window。根据this网站的说法,单线程WPF窗口可用于非常UI密集的窗口(许多图表等)。

要关闭窗口,我只需调用thread.Abort()。我认为这不是最干净的方法,但它适用于我所需的情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接