Wpf 从线程启动时窗口未正确关闭
我的加载窗口有问题。 我在STA模式下以新线程启动一个新窗口。我知道这很不寻常,但对我来说是必要的 问题是,关闭窗口后,GC不会释放ram,窗口仍保留在visual live树中: 我能做些什么来避免这种情况 我的代码:Wpf 从线程启动时窗口未正确关闭,wpf,multithreading,user-interface,Wpf,Multithreading,User Interface,我的加载窗口有问题。 我在STA模式下以新线程启动一个新窗口。我知道这很不寻常,但对我来说是必要的 问题是,关闭窗口后,GC不会释放ram,窗口仍保留在visual live树中: 我能做些什么来避免这种情况 我的代码: private void Button_Click(object sender, RoutedEventArgs e) { if (_window == null) { Thread thread = new Thread(ShowWindow
private void Button_Click(object sender, RoutedEventArgs e)
{
if (_window == null)
{
Thread thread = new Thread(ShowWindow);
thread.IsBackground = false;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
else
{
_window.Dispatcher.Invoke(_window.Close);
_window = null;
}
}
private void ShowWindow()
{
_window = new Window();
_window.AllowsTransparency = true;
_window.Background = new SolidColorBrush(Color.FromArgb(70,0,0,0));
_window.Height = 1200D;
_window.Width = 1920D;
_window.WindowStartupLocation = WindowStartupLocation.Manual;
_window.Left = -1920D;
_window.Top = 0D;
_window.WindowStyle = WindowStyle.None;
_window.ShowDialog();
}
这是像这个一样的喷溅屏吗 在应用程序上看到的启动屏幕不能在单独的线程上工作。它们是仍然在UI线程上运行的无模式表单(使用Form.Show而不是Form.ShowDialog打开)。任何后台工作都是在后台线程上执行的。对服务器的调用通常根本不使用线程。异步方法用于与web服务、数据库等通信 WCF服务代理始终生成异步方法。直到.NET4.0,这些方法都遵循APM模式,即
BeginMyMethod/EndMyMethod
。由于.NET 4.5.2异步方法是基于任务的,即task MyMethodAsync()
给定新的异步方法,您的代码可以如此简单:
private async void Button_Click(object sender, RoutedEventArgs e)
{
using(var progForm =new MyProgressForm())
{
progForm.Text="Running";
progForm.Show(this);
using(var client = new myServiceClient())
{
await client.MyMethodAsync();
}
progForm.Close();
}
就这样。UI不会阻止等待MyMethodAsync
返回。wait
之后的代码将仅在服务器完成后运行
可以使用该方法将APM样式的方法转换为任务。将APM样式或基于事件的接口转换为任务将在中进行更详细的讨论
使用带有暴露AMP方法的代理的Task.fromsync
,代码可能如下所示:
private async void Button_Click(object sender, RoutedEventArgs e)
{
using(var progForm =new MyProgressForm())
{
progForm.Text="Running";
progForm.Show(this);
using(var client = new myServiceClient())
{
await Task.FromAsync(client.BeginMyMethod,client.EndMyMethod,null);
}
progForm.Close();
}
我知道这不是一个很好的解决方案。。。事实上很糟糕。但就我而言,不可能用另一种方式修复。但暂时修复也没关系。 要完成此操作:我以以下方式更改了代码:
private void Button_Click(object sender, RoutedEventArgs e)
{
if (_window == null)
{
Thread thread = new Thread(ShowWindow);
thread.IsBackground = false;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
else
{
_window.Dispatcher.Invoke(_window.Close);
Window w = _window;
_window = null;
new Thread(() =>
{
Thread.Sleep(100);
w.Dispatcher.InvokeShutdown();
w = null;
}).Start();
}
}
private Window CreateWindow()
{
Window w = new Window();
w.AllowsTransparency = true;
//w.Content = Some magic Animated Circle...
w.Background = new SolidColorBrush(Color.FromArgb(70, 0, 0, 0));
w.WindowStartupLocation = WindowStartupLocation.Manual;
w.WindowStyle = WindowStyle.None;
return w;
}
public void ShowWindow()
{
Thread uiThread = new Thread(() =>
{
_window = CreateWindow();
_window.Show();
System.Windows.Threading.Dispatcher.Run();
});
uiThread.SetApartmentState(ApartmentState.STA);
uiThread.IsBackground = true;
uiThread.Start();
}
当我们的应用程序完全更改wpf时,我首先删除它:D
感谢@Panagiotis Kanavos提供的积极反馈。在99%的情况下,您的权利;)
但是在我的情况下,我不能异步执行这些方法。。。将来我们可以,但现在不行。你为什么要在不同的线程上打开窗口?绝对不需要。如果要执行后台处理,请使用任务执行,并根据需要更新表单。如果您不希望表单是模态的,请不要将其作为模态打开,因为主线程正在处理一些ui内容(我们必须同步到服务器),需要2-3秒。加载屏幕需要向用户显示客户端正在执行某些操作。不,不是。启动屏幕不能在单独的线程上工作,它们是出现在其他窗体之上的无模式窗体。在过去,(即.NET4.0之前)人们使用BackgroundWorker。现在他们使用
async/await
和任务。与服务器同步并不意味着您需要阻止UI线程。发布你的代码。需要解决的问题是您对服务器的阻塞等待您在谈论什么服务器以及如何与之通信?您现在是如何完成处理的?SOAP代理、ADO.NET、WebClient和HttpClient都有异步方法,所以您不需要阻止等待响应。任何其他通信方法都可以在后台与任务一起运行。运行在应用程序中看到的启动或进度屏幕在不同的线程上不起作用。它们在UI线程本身上工作。虽然处理是在后台线程中执行的,或者使用异步技术。这是一段很好的代码,我将尝试使用Dispatcher:)@THeJ don。这是一段难看的代码。在.NET4+中,您不需要任何这些技巧。显示SPlass如果最早支持的版本是4.5.2,那么您根本不需要它。正确的代码需要4行您是对的,这是更好的解决方案,但在我的情况下不可能。加载窗口时运行的方法会影响主窗口,因此我无法异步运行它。加载窗口不是一个飞溅的窗口,而是一个带有动画圆圈的窗口,用于显示加载进度。