关闭时保持对话框表单不卸载
Posted
技术标签:
【中文标题】关闭时保持对话框表单不卸载【英文标题】:Keep dialog form from unloading when closed 【发布时间】:2022-01-12 01:08:25 【问题描述】:我有一个包含超过 3000 个项目的列表框的对话框窗口,最初加载需要很长时间。为了加载这个对话框,我创建了一个实例var dlg = new frmDlg();
,然后当我需要这个对话框时,我用dlg.ShowDialog(this);
打开它虽然这减少了需要初始化列表框的时间,但仍然需要很长时间才能显示对话框关闭后从内存中卸载对话框,需要重新加载可视元素。有什么办法可以防止这种情况发生吗?使用普通表单,我只会隐藏窗口而不是关闭它,但这似乎不适用于对话框窗口。
【问题讨论】:
拦截 FormClosing 事件。设置e.Cancel = true;
和this.Hide()
。即使它是一个对话框,这也会隐藏它。
加载时间过长 - 从 DB 调用 3000 个项目?您可以做什么,加载您的项目列表,然后将其传递到对话框中,然后设置列表框datasource
BOB,正如我在问题中提到的,我尝试隐藏窗口而不是关闭它,但这不起作用。 ShowDialog 返回时,表单仍会卸载。
TS,加载时间长的是列表框本身。初始化列表框中的项目后,我永远不会更改它们。问题是当对话框关闭时,.NET 从内存中卸载列表框的可视部分,然后在再次调用 ShowDialog 时将其从列表框对象重新加载到可视内存中。
【参考方案1】:
将以下成员添加到frmDlg
:
private bool keepHandle;
protected override void OnFormClosing(FormClosingEventArgs e)
keepHandle = e.CloseReason == CloseReason.UserClosing;
base.OnFormClosing(e);
protected override void DestroyHandle()
if (!keepHandle)
base.DestroyHandle();
这应该防止对话框的句柄在用户关闭对话框时被破坏。
【讨论】:
这不起作用。此对话框仍然需要很长时间才能“加载”第二次。 @Adam 你如何填充列表框?可能这对您不起作用,因为您每次都在重新加载列表? Dmitry,没有调用表单的ctor,而是调用了Form_Load和Form_Shown。这是因为表单没有被删除(GC),只有Handle被销毁。 @Dmitry 我的初始化逻辑在ctor中。 @Dmitry 我有一个 List表格1:
public partial class Form1 : Form
private Form2 reusable = null;
public Form1()
InitializeComponent();
private void button1_Click(object sender, EventArgs e)
if (reusable == null) reusable = new Form2();
reusable.ShowDialog(this);
switch (reusable.DialogResult)
case DialogResult.OK: MessageBox.Show("Ok clicked."); break;
case DialogResult.Cancel: MessageBox.Show("Cancel clicked."); break;
case DialogResult.None: MessageBox.Show("Form Closed."); break;
表格2:
public partial class Form2 : Form
private DialogResult dialogResult = DialogResult.None;
public new DialogResult DialogResult
get => this.dialogResult;
set => this.dialogResult = value;
public Form2()
InitializeComponent();
private void Form2_Shown(object sender, EventArgs e)
this.dialogResult = DialogResult.None;
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
e.Cancel = true;
this.Hide();
private void button1_Click(object sender, EventArgs e)
this.dialogResult = DialogResult.OK;
this.Close();
private void button2_Click(object sender, EventArgs e)
this.dialogResult = DialogResult.Cancel;
this.Close();
^ 几个注意事项:您不能再使用 ShowDialog 结果的结果,您需要创建自己的 DialogResult 属性,或者只是使用完全不同/新的属性来表示您的对话框是如何隐藏的。
您也不能再在任何按钮上使用 Button.DialogResult 属性,您需要实现自己的按钮单击事件来处理设置对话框结果。
这都是因为调用 ShowDialog 结果时 .net 框架中发生的事情。
此外,Dmitry 关于使用 e.CloseReason 的示例也是有效的 - 您可能希望允许关闭应用程序等内容。这样,您还可以处理 FormClosed 事件并在应用程序关闭之前执行您需要执行的任何快速清理。
【讨论】:
关于这一切的另一个警告:您可以为 WPF Windows 执行类似的操作,但是,您绝对应该使用 DialogResult 属性以外的其他内容。这是因为如果您尝试执行以下任何操作,WPF Windows 会引发异常:1) 尝试在未通过 ShowDialog() 显示的任何窗口上设置 DialogResult,2) 尝试再次设置 DialogResult。跨度> B.O.B.,我试着复制你的代码,但是当 ShowDialog 返回时,表单的句柄仍然被破坏。 @Adam 我刚刚进行了测试,并且每次确实都在改变句柄。实际上听起来您可能需要为您的列表框打开虚拟化.... @Adam docs.microsoft.com/en-us/dotnet/api/… @Adam 基本上,创建控件是一项昂贵的操作。成本高昂的部分是列表框中的控件。虚拟化基本上采用父控件(列表框)的尺寸,并计算出它可以显示的子项的最大数量,可能会添加一个缓冲区数量,然后只有每个创建那么多子控件。然后当用户滚动父控件时,子控件只是被移动,并被重复使用,并且它们的内容被活动控件替换。以上是关于关闭时保持对话框表单不卸载的主要内容,如果未能解决你的问题,请参考以下文章