コンストラクターの実行中にフォームを閉じることはできますか(または単にこの段階でフォームの表示を停止することはできますか)?
私は次のコードを持っています:
public partial class MyForm : Form
{
public MyForm()
{
if (MyFunc())
{
this.Close();
}
}
}
ここでは、Main()でObjectDisposedExceptionをスローします。
static void Main()
{
...
// Following line errors
Application.Run(new MyForm());
}
MyFormの結果を次のように確認してみました。
static void Main()
{
...
MyForm frm = new MyForm();
if (frm != null)
{
// Following line errors
Application.Run(frm);
}
}
しかし、それは役に立たないようです。誰か私にこれを回避する方法を教えてもらえますか?フォームがまだ存在するかどうかを確認する方法でしょうか?
まだ作成されていないフォームでClose
を呼び出すため、フォームのコンストラクターからDispose
を呼び出すことはできません。構築後にフォームを閉じるには、フォームが初めて表示される前にフォームを閉じる Load
event に匿名イベントハンドラーを割り当てます。
public partial class MyForm : Form
{
public MyForm()
{
if (ShouldClose())
{
Load += (s, e) => Close();
return;
}
// ...
}
// ...
}
フラグを設定してコンストラクタで閉じ、Shown
イベントで閉じるだけです。もちろん、その場合は、コードを移動して、そもそもコードを閉じる必要があるかどうかを判断するのが理にかなっています。
次はうまくいきます:
public partial class MyForm : Form
{
public MyForm()
{
if (MyFunc())
{
this.Shown += new EventHandler(MyForm_CloseOnStart);
}
}
private void MyForm_CloseOnStart(object sender, EventArgs e)
{
this.Close();
}
}
フォームでClose()を呼び出すと、内部的にフォームが破棄され、管理対象リソースが解放されます。これを行うと:
Application.Run(new MyForm());
ObjectDisposedExceptionが発生する可能性があります。プロパティを介してフォームの可視性を設定する必要があります:
Application.Run(new MyForm() { Visible = false });
コンストラクタでClose()の呼び出しを削除するか、プロパティの割り当てもそこに移動してください。
MyFuncを静的にできますか?そして、次のようなことをします:
static void Main()
{
...
if (MyForm.MyFunc())
{
Application.Run(new MyForm());
}
}
これにより、フォームを作成するかどうかを同じように制御できますか?
'Load'イベントにハンドラーを追加すると、ダイアログがまったく表示されないため、より良いことがわかりました。 'Shown'イベントを使用すると、ダイアログが開いたり閉じたりするのが一時的にわかり、混乱する可能性があります。
public partial class MyForm : Form
{
public MyForm()
{
if (MyFunc())
{
this.Load += MyForm_CloseOnStart;
}
}
private void MyForm_CloseOnStart(object sender, EventArgs e)
{
this.Close();
}
}
Environment.Exit(...)
は私のために働いています(ウィンドウのちらつきなし):
public partial class MyForm : Form
{
public MyForm()
{
if (weShouldClose)
{
Environment.Exit(0);
}
}
}
コンストラクタでフォームを閉じるのは賢明ではないと思います。これを行うと、フォームのユーザーはShowDialogを実行するかどうかがわかりません。
次のコードは非常に通常の使用法です。
_// in the parent form:
public void ShowMyForm()
{
MyForm form = new MyForm();
form.propertyA = ...;
from.propertyB = ...;
DialogResult dlgResult = form.ShowDialog(this);
ProcessDialogResult(dlgResult);
}
_
コンストラクタでフォームを表示するかどうかを決定した場合は、作成後にコードを追加して、ShowDialogを呼び出すかどうか、およびダイアログの結果を処理するかどうかを決定する必要があります。
さらに、プロパティを変更しても、フォームを表示するかどうかに影響がないことを確信していますか?また、将来の変更後?
作成中、フォームはまだ表示/開かれていません。ですから、Close()
は期待どおりに動作しません。
きちんとした方法は、Form_Loadのコンストラクターで実行したいチェックを実行することです。 form-loadのイベントハンドラーを追加し、イベントハンドラーでチェックを行います。プロパティDialogResultを使用して、フォームを表示しないことを決定したことを示します。
_private void FormMain_Load (object sender, EventArgs e)
{
if (FormShouldNotLoad())
{
this.DialogResult = System.Windows.Forms.DialogResult.Abort;
Close();
// Warning, this does not work, see below, (but we're almost there!)
}
}
_
コードのユーザーは、ダイアログの結果を確認できます。
_// in the parent form:
public void ShowMyForm()
{
MyForm form = new MyForm();
form.propertyA = ...;
from.propertyB = ...;
DialogResult dlgResult = form.ShowDialog(this);
switch (dlgResult)
{
case System.Windows.Forms.DialogResult.Abort:
ProcessFormNotLoaded();
break;
case System.Windows.Forms.DialogResult.OK:
ProcessFormOk();
break;
// etc.
}
}
_
ただし、Close()
はLoadが完了した後にのみ正しく呼び出せるため、form-loadのイベントハンドラーでClose()を呼び出しても機能しません。
したがって、Close()
を呼び出す代わりに、Close [)関数をBeginInvoke
する必要があります。これにより、ロードが完了した後にClose
関数が呼び出されます。
_private void FormMain_Load (object sender, EventArgs e)
{
if (FormShouldNotLoad())
{
this.DialogResult = System.Windows.Forms.DialogResult.Abort;
// invoke the Close function after Load completed
this.BeginInvoke(new MethodInvoker( () => this.CancelLoading())
}
}
_
ウィンドウを絶対に見ないようにしたい場合
(一瞬開いて消えるちらつきのウィンドウはありません):
_public new void Show()
{
if (MyFunc())
base.Show();
else
; // dispose or whatever
}
_
Show(...)
には2つのオーバーロードがあり、ShowDialog(...)
にも2つあります。Application.Run()
から開いたメインフォームでは機能しません。しかし、とにかく誰がそうするでしょうか?ただし、Application.Run()
を使用せずにメインフォームを開く方法もあります。