【发布时间】:2010-06-21 19:30:21
【问题描述】:
在我的 C# 应用程序中,我有一个可以从菜单命令打开的选项对话框。
我想确保选项对话框只有一个实例(用户不能在给定时间打开多个选项窗口)而不使其成为模态。
此外,如果用户已经打开了这个窗口,并且他在菜单项中单击以再次打开它,则应用程序只会使已经可见的表单成为最顶部的窗口。
谁能指点我如何完成这些任务?
非常感谢。
【问题讨论】:
标签: c# winforms modal-dialog
在我的 C# 应用程序中,我有一个可以从菜单命令打开的选项对话框。
我想确保选项对话框只有一个实例(用户不能在给定时间打开多个选项窗口)而不使其成为模态。
此外,如果用户已经打开了这个窗口,并且他在菜单项中单击以再次打开它,则应用程序只会使已经可见的表单成为最顶部的窗口。
谁能指点我如何完成这些任务?
非常感谢。
【问题讨论】:
标签: c# winforms modal-dialog
嗯,最简单的方法是有一个静态字段来存储对单个实例或 null 的引用,然后有一个方法来检索它或创建一个新的。
请注意,这与将其设置为单例不同 - 因为我假设如果表单已关闭,您下次需要创建一个新实例。 (替代方案 - 隐藏并重用它 - 显示在 STO 的答案中。)您可能想要这样的东西:
public class OptionsDialog : Form
{
private static OptionsDialog openForm = null;
// No need for locking - you'll be doing all this on the UI thread...
public static OptionsDialog GetInstance()
{
if (openForm == null)
{
openForm = new OptionsDialog();
openForm.FormClosed += delegate { openForm = null; };
}
return openForm;
}
}
当然,您可能还想让该方法执行“将其置于最前面”的步骤。
【讨论】:
您需要阻止表单关闭。如果不这样做,表单将被丢弃并变得无法使用。您可以通过实现 FormClosing 事件来做到这一点:
protected override void OnFormClosing(FormClosingEventArgs e) {
if (e.CloseReason == CloseReason.UserClosing) {
this.Hide();
e.Cancel = true;
}
}
要使其成为单例,只需在主表单类中跟踪表单的生命周期:
frmOptions options;
private void btnShowOptions_Click(object sender, EventArgs e) {
if (options == null) {
options = new frmOptions();
// To make absolutely sure:
options.FormClosed += (o, ea) => options = null;
}
else {
options.WindowState = FormWindowState.Normal;
}
options.Show();
}
【讨论】:
(o, ea) => 我知道您将表单设置回null,但我不明白这种语法
您将需要此表单作为属性
Form1 myForm = null;
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
myForm = null;
}
private void ShowForm()
{
if (myForm != null)
{
myForm.BringToFront();
}
else
{
myForm = new Form1;
myForm.Show();
}
}
【讨论】:
你可以使用这样的代码:
private MyDialogForm _FormInstance;
public void ShowOptions()
{
if (_FormInstance == null)
{
_FormInstance = new MyDialogForm();
_FormInstance.FormClosing += (s,e) =>
{
e.Cancel = true;
_FormInstance.Hide();
}
}
_FormInstance.Show();
}
【讨论】:
我假设您至少有两种形式。一种形式,称为 frmMain,允许您打开 frmOptions。在 frmMain 中,添加一个 frmOptions 类型的变量,如下所示:
public partial class frmMain : Form
{
private frmOptions optionsInstance = null;
...
在打开“选项”对话框的例程中,添加以下内容:
if (optionsInstance == null || !optionsInstance.Visible)
{
optionsInstance = new frmOptions();
optionsInstance.Show();
}
当 frmOptions 关闭时,optionsInstance 不会为空,这就是为什么在实例化 frmOptions 实例之前检查它是否可见的原因。
如果这对您不起作用,您可以尝试使用互斥锁,但这可能有点矫枉过正。
【讨论】:
基于Jon Skeet's answer,我使用以下代码将表单显示为模式对话框。
if (this.aboutForm == null)
{
this.aboutForm = new AboutForm();
this.aboutForm.FormClosed += (sender2, e2) => { this.aboutForm = null; };
this.aboutForm.ShowDialog(this);
}
else
{
this.aboutForm.Focus();
}
我必须这样做,因为我有一个菜单项可以在主窗体的菜单和通知图标的上下文菜单中显示关于窗体。如果我使用主窗体的菜单打开 About 窗体,我仍然可以使用通知图标的上下文菜单项打开另一个实例。
【讨论】:
Main_Frm _main_Frm = null;
private void Show_bt_Click(object sender, EventArgs e)
{
if (_main_Frm != null)
{
_main_Frm .BringToFront();
}
else
{
_main_Frm = new Comission_Frm();
_main_Frm .Show();
}
//This condition used when you closed the form the form will disposed and when you reopen.
if (_main_Frm .IsDisposed)
{
_main_Frm = new _Main_Frm ();
_main_Frm .Show();
}
}
【讨论】:
这可能会有所帮助! 注意:以下代码取自以下文章: https://www.dotnetcurry.com/ShowArticle.aspx?ID=150
static class Program
{
///<summary>
/// The main entry point for the application.
///</summary>
[STAThread]
static void Main()
{
bool instanceCountOne = false;
using (Mutex mtex = new Mutex(true, "MyRunningApp", out instanceCountOne))
{
if (instanceCountOne)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
mtex.ReleaseMutex();
}
else
{
MessageBox.Show("An application instance is already running");
}
}
}
}
【讨论】: