0

回避策があるファンキーな問題がありますが、コードをできるだけ似たものにしたいと考えています。この問題は、null である場合とそうでない場合があるユーザー コントロールの基本クラスの特定の変数に集中しており、null であってはなりません。

基本的に、メイン フォーム ウィンドウのインスタンスを取得する単一の基本クラスを持つ多数のユーザー コントロールがあるため、ユーザー コントロールはメイン フォームのプロパティにアクセスし、メイン フォームのメソッドを呼び出すことができます。スニペットを次に示します (this.frmParent はパブリック メンバーです)。

    private void ucBase_Load( object sender, EventArgs e )
    {
        // Establish the link to the main form.
        this.frmParent = FindForm() as frmMain;
    }

次に、各ユーザー コントロールがこの基本クラスを共有します。

public partial class ucLiberty : ucBase

次に、メイン フォームで、次のようにユーザー コントロールを呼び出します。

                ucLiberty Liberty = new ucLiberty();
                IQDevicePath = Liberty.GetIQDrivePath();

何らかの理由で、ユーザー コントロールをインスタンス化すると (この場合はメイン フォームにあります)、基本クラスの frmParent 変数に null 以外の値が設定される場合とされない場合があります。

ユーザー コントロールのロード イベントが発生していないことに気付きました。コントロールの作成を強制することになっている CreateControl() というメソッドを見つけた後、load イベントが発生し始めましたが、デバッガーで実行をトレースし、frmParent を設定しようとしていた基本クラスに到達したときに、 FindForm() は常に null 以外の値を返すとは限りませんでした。

この問題が発生しない他のユーザー コントロールがありますが、それらの違いは、一部のユーザー コントロールには子コントロールがあり、一部には子コントロールがないことです。子コントロールのないものにはこの問題があります。

私の回避策は、FindForm() が失敗したユーザー コントロールを監視し、そのユーザー コントロールのロード イベントで、メイン フォームのコンストラクターへの呼び出しで値を割り当てることです。

this.frmParent = new frmMain();

ただし、load イベントを発生させるには、CreateControl() を呼び出す必要があります。また、将来のメンテナーに、さまざまな動作命令に関する明示的な知識を持たせる必要があるという考えは好きではありません。つまり、メンテナンスを簡単にするために、すべてのユーザー コントロールが同じように機能するようにしたいと考えています。

コードを分解したところ、ユーザー コントロールのロード イベントが発生する場合と発生しない場合がある理由、およびユーザー コントロールの基本クラスでの FindForm() の呼び出しが失敗する理由がわかりません。

これらの問題を解決する方法について誰かアイデアがありますか? ありがとう。

4

2 に答える 2

2

ユーザーコントロールが配置されているフォームをユーザーコントロールに認識させることにより、かなり深刻なOOPの罪を犯しています。これは、コンテナーを気にしない独立したクラスであると想定されています。イベントを使用して、コンテナーが関心を持つ可能性のあるクラスで発生したことをコンテナーに認識させることができます。 Winforms の標準コントロールのいずれか。たとえば、TextBox は、ドロップされたフォームの種類を気にしません。

それが理論であり、練習はそれほどきれいではありません。発生している問題は、OnLoad メソッド (別名 Load イベント) が別の理由で発生することです。これは、ネイティブ Windows ハンドルが作成されるときに実行されます。これは通常、フォームのウィンドウが作成されたときに発生し、Show() メソッド呼び出しによってトリガーされます。フォームの IntializeComponent() メソッドの後です。

ユーザー コントロールのコンストラクターに、Handle プロパティに値が必要なコードがある場合、Winforms は義務付けてコントロールの Windows ハンドルを作成し、Load イベントを発生させます。フォームの InitializeComponent() メソッドがその Controls.Add() メソッドを呼び出す機会を得る前に、早すぎました。Parent プロパティはまだフォームを参照していません。FindForm() の Kaboom。

デバッガーで簡単に診断できます。ユーザー コントロールの OnLoad メソッドにブレークポイントを設定します。スタック トレースは、ハンドルの作成をトリガーしたステートメントに直接移動します。

于 2011-09-05T22:41:28.797 に答える
0

メインフォームのインスタンスはいくつありますか? 1 つしかない場合 (今後も 1 つしかない場合)、シングルトンとしてアクセスできるようにすることができます。

public class frmMain : Form
{
     private static frmMain s_Singleton;

     public static frmMain Singleton
     {
          get
          {
              if (s_Singleton == null) s_Singleton = new frmMain();
              return s_Singleton;
          }

     }
}

そのため、コンストラクターを直接呼び出す代わりに、参照のために frmMain.Singleton を呼び出します (フォームが最初に構築される可能性が最も高い Program.cs でも (特に!))。さらに、メイン フォームへのグローバルにアクセス可能な参照がありfrmMain.Singleton、ユーザー コントロールを呼び出すことで利用できます。

あなたの ucBase_Load がロードされない理由については、具体的なユーザー コントロールでもイベントを処理し、ベース ハンドラーの起動を何らかの形で停止させているというのが私の根拠のない推測です。その場合は、base.OnLoad()具体的なユーザー コントロールのイベント ハンドラーを追加します。

FindForm が機能しない理由については、ユーザー コントロールのコンストラクターが終了する前にメソッドが呼び出されることが原因である可能性があります。これはありそうにないようですが、コードを見ずに確実に言うのは難しいです. これが問題になる理由は、コントロールの親などがコンストラクターで設定されているためです。しかし、Load イベントで処理しているので、ありそうにありません。ロジックを OnParentChanged イベントに移動することで、この理論を検証できます。

ところで、あなたの回避策は非常に汚いように見えます。メイン フォームへの参照が得られず、新しいメイン フォームインスタンスが作成されます (これは表示されません)。

于 2011-09-05T22:42:14.770 に答える