フォームが読み込まれた後にコードを実行するにはどうすればよいですか?


126

.NETでは、Windowsフォームにはフォームがロードされる前に発生するイベント(Form.Load)がありますが、フォームがロードされた後に発生する対応するイベントはありません。フォームが読み込まれた後、いくつかのロジックを実行したいと思います。

誰かが解決策についてアドバイスできますか?


:この質問は非常に良い答えを持っていますが、それは価値がこれを言及するかもしれないdocs.microsoft.com/en-us/dotnet/framework/winforms/...
Rishav

回答:


192

"Shown"イベントを使用できます:MSDN-Form.Shown

「Shownイベントは、フォームが初めて表示されたときにのみ発生します。その後、最小化、最大化、復元、非表示、表示、または無効化して再描画しても、このイベントは発生しません。」


10
私には、フォームが読み込まれている間、表示されたハンドラが実行されているようです...私は間違っていますか?
ckonig 2013

3
古くて金...はい、あなたは間違っています。GUIは並列タスクを実行できません。別の実行が行われている間に何かを行うために重要なことは何ですか。
Dennis Ziolkowski、2013年

2
LoadイベントハンドラーにApplication.DoEvents()を呼び出すコードがある場合、Shownイベントは、Loadイベントハンドラーの実行が完了する前に発生します。これは、Shownイベントが実際にはForm.BeginInvoke(ShownEvent)を使用してメッセージキューに入れられ、DoEvents()がLoadの終了前に強制的に発生させるためです。
Artemix 2014年

1
C#では、私にとっては十分ではありませんでした。別のスレッドでShown += Form1_Shown;提案されているように追加しなければなり
ませんでした

11
これを追加する必要があります。Shownイベント内で最初にロジックの前にあり、ロジックを実行する前にフォームを完全にロードして保持および更新します
Aylian Craspa

49

私は時々(ロードで)使用します

this.BeginInvoke((MethodInvoker) delegate {
  // some code
});

または

this.BeginInvoke((MethodInvoker) this.SomeMethod);

(「this」以外のインスタンスでイベントを処理する場合は、「this」をフォーム変数に変更します)。

これにより、呼び出しがwindows-formsループにプッシュされるため、フォームがメッセージキューを処理しているときに処理されます。

[リクエストに応じて更新]

Control.Invoke / Control.BeginInvokeメソッドは、スレッドで使用することを目的としており、UIスレッドに作業をプッシュするメカニズムです。通常、これはワーカースレッドなどで使用されます。Control.Invokeは同期呼び出しを実行しますが、Control.BeginInvokeは非同期呼び出しを実行します。

通常、これらは次のように使用されます。

SomeCodeOrEventHandlerOnAWorkerThread()
{
  // this code running on a worker thread...
  string newText = ExpensiveMethod(); // perhaps a DB/web call

  // now ask the UI thread to update itself
  this.Invoke((MethodInvoker) delegate {
      // this code runs on the UI thread!
      this.Text = newText;
  });
}

これは、メッセージをWindowsメッセージキューにプッシュすることによって行われます。UIスレッドは(ある時点で)メッセージをデキューし、デリゲートを処理し、完了したことをワーカーに通知します。

OK; では、UIスレッドでControl.Invoke / Control.BeginInvokeを使用するとどうなりますか?それは対処します... Control.Invokeを呼び出した場合、メッセージキューでのブロックが即時のデッドロックを引き起こすことを知るのは十分に賢明です。助けにならない...

ただし、Control.BeginInvokeの動作は異なります。UI スレッド上にある場合でも、常にキューに作業プッシュされます。これは、「すぐに」という簡単な言い方をしますが、タイマーなどの不便さはありません(とにかく同じことをしなければなりません!)。


1
それを完全に理解していませんでした。もう少し説明してもらえますか?
Torbjørn

こんにちはマーク、BeginInvokeで呼び出されるプロセスの完了中にフォームを応答可能にすることは可能ですか?
huMpty duMpty 2012

WPFでそれと同等のものは何ですか?
mrid

6

初回は「AfterLoading」を開始しませんが、
それを登録するだけで次のロードを開始します。

private void Main_Load(object sender, System.EventArgs e)
{
    //Register it to Start in Load 
    //Starting from the Next time.
    this.Activated += AfterLoading;
}

private void AfterLoading(object sender, EventArgs e)
{
    this.Activated -= AfterLoading;
    //Write your code here.
}

5

私は同じ問題を抱えており、それを次のように解決しました:

メッセージを表示して、2秒後に自動的に閉じたいのですが。そのため、(動的に)単純なフォームとメッセージを表示する1つのラベルを生成し、1500ミリ秒間メッセージを停止して、ユーザーがそれを読む必要がありました。そして、動的に作成されたフォームを閉じます。表示されたイベントは、ロードイベントの後に発生します。だからコードは

Form MessageForm = new Form();
MessageForm.Shown += (s, e1) => { 
    Thread t = new Thread(() => Thread.Sleep(1500)); 
    t.Start(); 
    t.Join(); 
    MessageForm.Close(); 
};

2

フォームがアクティブ化されたときに発生したい場合は、コードをフォームのActivatedイベントに配置することもできます。最初のアクティブ化でのみ実行されることになっている場合は、ブール値の「実行された」チェックを入れる必要があります。


1

これは古い質問であり、いつルーチンを開始する必要があるかによります。null参照例外は必要ないため、最初にnullを確認してから、必要に応じて使用することが常に最善です。それだけであなたは多くの悲しみを救うでしょう。

このタイプの質問の最も一般的な理由は、コンテナーまたはカスタムコントロールタイプが、カスタムクラスの外部で初期化されたプロパティにアクセスしようとするときです。オブジェクトタイプ。これは、クラスが完全に初期化される前、つまりプロパティの設定が完了する前などに実行されていることを意味します。このタイプの質問のもう1つの考えられる理由は、カスタムグラフィックを実行するタイミングです。

form loadイベントに続くコードの実行をいつ開始するかに関する質問に最もよく答えるには、WM_Paintメッセージを監視するか、paintイベント自体に直接フックします。どうして?paintイベントは、フォームの読み込みイベントに関してすべてのモジュールが完全に読み込まれたときにのみ発生します。注:this.visible == trueは、trueに設定されていると常にtrueになるとは限らないため、フォームを非表示にすることを除いて、この目的にはまったく使用されません。

以下は、フォームロードイベントに続いてコードの実行を開始する方法の完全な例です。ペイントメッセージループを不必要に拘束しないことをお勧めします。これにより、ループの外側でコードの実行を開始するイベントを作成します。

using System.Windows.Forms;

名前空間MyProgramStartingPlaceExample {

/// <summary>
/// Main UI form object
/// </summary>
public class Form1 : Form
{

    /// <summary>
    /// Main form load event handler
    /// </summary>
    public Form1()
    {
        // Initialize ONLY. Setup your controls and form parameters here. Custom controls should wait for "FormReady" before starting up too.
        this.Text = "My Program title before form loaded";
        // Size need to see text. lol
        this.Width = 420;

        // Setup the sub or fucntion that will handle your "start up" routine
        this.StartUpEvent += StartUPRoutine;

        // Optional: Custom control simulation startup sequence:
        // Define your class or control in variable. ie. var MyControlClass new CustomControl;
        // Setup your parameters only. ie. CustomControl.size = new size(420, 966); Do not validate during initialization wait until "FormReady" is set to avoid possible null values etc. 
        // Inside your control or class have a property and assign it as bool FormReady - do not validate anything until it is true and you'll be good! 
    }

    /// <summary>
    /// The main entry point for the application which sets security permissions when set.
    /// </summary>
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }


    #region "WM_Paint event hooking with StartUpEvent"            
    //
    // Create a delegate for our "StartUpEvent"
    public delegate void StartUpHandler();
    //
    // Create our event handle "StartUpEvent"
    public event StartUpHandler StartUpEvent;
    //
    // Our FormReady will only be set once just he way we intendded
    // Since it is a global variable we can poll it else where as well to determine if we should begin code execution !!
    bool FormReady;
    //
    // The WM_Paint message handler: Used mostly to paint nice things to controls and screen
    protected override void OnPaint(PaintEventArgs e)
    {
        // Check if Form is ready for our code ?
        if (FormReady == false) // Place a break point here to see the initialized version of the title on the form window
        {
            // We only want this to occur once for our purpose here.
            FormReady = true;
            //
            // Fire the start up event which then will call our "StartUPRoutine" below.
            StartUpEvent();
        }
        //
        // Always call base methods unless overriding the entire fucntion
        base.OnPaint(e);
    }
    #endregion


    #region "Your StartUp event Entry point"
    //
    // Begin executuing your code here to validate properties etc. and to run your program. Enjoy!
    // Entry point is just following the very first WM_Paint message - an ideal starting place following form load
    void StartUPRoutine()
    {
        // Replace the initialized text with the following
        this.Text = "Your Code has executed after the form's load event";
        //
        // Anyway this is the momment when the form is fully loaded and ready to go - you can also use these methods for your classes to synchronize excecution using easy modifications yet here is a good starting point. 
        // Option: Set FormReady to your controls manulaly ie. CustomControl.FormReady = true; or subscribe to the StartUpEvent event inside your class and use that as your entry point for validating and unleashing its code.
        //
        // Many options: The rest is up to you!
    }
    #endregion

}

}


これは信じられないほど長い時間のように思われます、そしてそれは単にShownイベントをキャッチすることよりも何か利点がありますか?
Steve Smith

0

私はこれが古い記事であることを知っています。しかし、ここに私がそれをした方法があります:

    public Form1(string myFile)
    {
        InitializeComponent();
        this.Show();
        if (myFile != null)
        {
            OpenFile(myFile);
        }
    }

    private void OpenFile(string myFile = null)
    {
            MessageBox.Show(myFile);
    }

-9

実行後、フォームを閉じることができます。

//YourForm.ActiveForm.Close();

    LoadingForm.ActiveForm.Close();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.