3

他のいくつかの質問をチェックアウトしましたが、明らかに最善の解決策は、そもそもこの問題を引き起こす動作を防ぐことですが、問題は非常に断続的であり、再現性が非常に低いです。

私は基本的にメインフォームとサブフォームを持っています。サブフォームは、メインフォームのメニューやボタンから次のように表示されます。


private void myToolStripMenuItem_Click(object sender, EventArgs e)
{
    try
    {
        xDataForm.Show();
        xDataForm.Activate();
    }
    catch (ObjectDisposedException)
    {
        MessageBox.Show("ERROR 10103");
        ErrorLogging newLogger = new ErrorLogging("10103");
        Thread errorThread = new Thread(ErrorLogging.writeErrorToLog);
        errorThread.Start();
    }
}

サブフォームは実際にはメインフォームにあります(良くも悪くも。実際にこれを変更したいのですが、そうするにはかなりの時間がかかります):


public partial class FormMainScreen : Form
{
    Form xDataForm = new xData();
    ...(lots more here)

    public FormMainScreen(int pCount, string pName)
 {
        InitializeComponent();
        ...
 }
    ...
}

サブフォームの Dispose 関数は、「閉じる」ボタンと「X」ボタンが実際にフォームを非表示にするように変更されているため、毎回再作成する必要はありません。メイン画面が閉じると、「フラグ」が 2 に設定されるため、他のフォームは実際に閉じても問題ないことを認識します。


protected override void Dispose(bool disposing)
{
    if (FormMainScreen.isExiting == 2) 
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }
    else
    {
        if (xData.ActiveForm != null)
        {
            xData.ActiveForm.Hide();
        }
    }
}

問題は、なぜこれが何度も何度も問題なく機能するのかということですが、文字通り、約 1/1000 の確率で例外が発生するというか、なぜ私のフォームが破棄されるのでしょうか?

ガベージ コレクタが混乱している疑いがありました。これは、ガベージ コレクタが何時間も実行されていると発生頻度がわずかに高くなるためです。

4

2 に答える 2

3

問題はありませんが、これは非常に昔に解決された問題に対する非常に複雑な解決策のようです。

Dispose() メソッドでは、他の使い捨てオブジェクトを破棄する以外のことを行うべきではありません (破棄フラグが true の場合のみ)。そのため、デザイナーが生成するメソッドは変更しません。

したがって、なぜこれが起こっているのかという質問に対する即時の答えは、ガベージ コレクターが Dispose メソッドを呼び出すタイミングにほぼ確実に関連しています。

代わりに、おそらく MDI ( multiple document interface ) 親フォームの使用を検討する必要があり、「サブフォーム」は MDI 子と呼ばれます。その後、そのように子で FormClosing イベントを処理できます。

(MDI に反対する場合は、フォームOwnersを使用して基本的に同じことができることに注意してください。)

// MDI child
private void Form_FormClosing(object sender, FormClosingEventArgs e) {
    if (e.CloseReason == CloseReason.UserClosing) {
        e.Cancel = true;
        Hide();
    }
}

コードで閉じている、親フォームが閉じている、Windows がシャットダウンしているなど、さまざまな理由でフォームが閉じている場合、閉じはキャンセルされません。ユーザーが子フォームを直接閉じたためにウィンドウが閉じられている場合にのみ、それを非表示にします。

MDI 親の内部に MDI 子を表示するには、次の操作を実行できます。

MyParentForm parentForm = new MyParentForm();
parentForm.IsMdiContainer = true;
parentForm.Show();

MyChildForm childForm = new MyChildForm();
childForm.MdiParent = parentForm;
childForm.Show();
于 2010-04-19T22:13:27.797 に答える
2
try 
{
    // Validate form not disposed before using. Initialize as needed. 
    if  (xDataForm == null || xDataForm.IsDisposed)
    {
        xDataForm = new MyDataFormName();
    }
    xDataForm.Show(); 
    xDataForm.Activate(); 
} 
于 2010-04-20T01:03:10.680 に答える