[英]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.