Làm cách nào để tôi thực thi mã SAU một biểu mẫu đã được tải?


126

Trong .NET, Windows Forms có một sự kiện kích hoạt trước khi Form được tải (Form.Load), nhưng không có sự kiện tương ứng nào được kích hoạt SAU khi biểu mẫu được tải. Tôi muốn thực thi một số logic sau khi biểu mẫu đã được tải.

Bất cứ ai có thể tư vấn về một giải pháp?


Mặc dù câu hỏi này có câu trả lời rất hay nhưng có lẽ đáng để đề cập đến điều này: docs.microsoft.com/en-us/dotnet/framework/winforms/ Kẻ
Rishav

Câu trả lời:


192

Bạn có thể sử dụng sự kiện "Hiển thị": MSDN - Form.Shown

"Sự kiện Hiển thị chỉ được nêu lên lần đầu tiên khi một biểu mẫu được hiển thị; sau đó thu nhỏ, tối đa hóa, khôi phục, ẩn, hiển thị hoặc vô hiệu hóa và sơn lại sẽ không làm tăng sự kiện này."


10
Đối với tôi có vẻ như trình xử lý hiển thị được thực thi KHI biểu mẫu đang tải ... tôi có sai không?
ckonig

3
Cũ nhưng vàng ... Vâng, bạn đã sai. GUI không thể chạy các tác vụ song song, điều quan trọng là phải làm gì đó KHI thực hiện một thao tác khác.
Dennis Ziolkowski

2
Nếu trong trình xử lý sự kiện Load có một mã gọi Application.DoEvents (), thì sự kiện Shown sẽ kích hoạt trước khi trình xử lý sự kiện Load kết thúc việc thực thi của chúng. Điều này là do sự kiện Shown trên thực tế được đặt trong hàng đợi tin nhắn bằng Form.BeginInvoke (ShownEvent) và DoEvents () buộc nó kích hoạt trước khi Load kết thúc.
Artemix

1
Nó không đủ làm việc với tôi, trong C #. Tôi đã phải thêm Shown += Form1_Shown;như đề xuất trong một chủ đề khác
ocramot

11
bạn nên thêm This.Refresh (); bên trong sự kiện Hiển thị trước tiên trước logic của bạn và nó sẽ giữ và làm mới biểu mẫu để được tải đầy đủ trước khi logic của bạn bắt đầu chạy
Aylian Craspa

49

Đôi khi tôi sử dụng (trong Tải)

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

hoặc là

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

(thay đổi "this" thành biến biểu mẫu của bạn nếu bạn đang xử lý sự kiện trên một thể hiện khác với "this").

Điều này đẩy lệnh gọi vào vòng lặp biểu mẫu windows, vì vậy nó được xử lý khi biểu mẫu đang xử lý hàng đợi tin nhắn.

[cập nhật theo yêu cầu]

Các phương thức Control.Invoke / Control.BeginInvoke được thiết kế để sử dụng với luồng và là một cơ chế để đẩy công việc lên luồng UI. Thông thường, điều này được sử dụng bởi các luồng công nhân, v.v. Control.Invoke thực hiện một cuộc gọi đồng bộ, trong đó Control.BeginInvoke thực hiện một cuộc gọi không đồng bộ.

Thông thường, chúng sẽ được sử dụng như:

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;
  });
}

Nó thực hiện điều này bằng cách đẩy một tin nhắn lên hàng đợi tin nhắn windows; luồng UI (tại một số điểm) hủy xếp hàng tin nhắn, xử lý ủy nhiệm và báo hiệu cho nhân viên rằng nó đã hoàn thành ... cho đến nay rất tốt ;-p

ĐỒNG Ý; Vậy điều gì xảy ra nếu chúng ta sử dụng Control.Invoke / Control.BeginInvoke trên luồng UI? Nó đối phó ... nếu bạn gọi Control.Invoke, đủ khả năng để biết rằng việc chặn trên hàng đợi tin nhắn sẽ gây ra bế tắc ngay lập tức - vì vậy nếu bạn đã ở trên luồng UI, nó chỉ cần chạy mã ngay lập tức ... không giúp chúng tôi ...

Nhưng Control.BeginInvoke hoạt động khác: nó luôn đẩy công việc lên hàng đợi, ngay cả khi chúng ta đã có trên luồng UI. Điều này thực hiện một cách thực sự đơn giản để nói "trong một khoảnh khắc", nhưng không có sự bất tiện của bộ hẹn giờ, v.v. (dù sao vẫn sẽ phải làm điều tương tự!).


1
Không hoàn toàn hiểu điều đó. Bạn có thể giải thích thêm một chút không?
Torbjørn

Xin chào, có thể tạo biểu mẫu phản hồi trong khi quá trình hoàn tất được gọi trong BeginInvoke ??
huMpty duMpty

WPF tương đương với cái gì?
mrid

6

Lần đầu tiên, nó sẽ không bắt đầu "Sau khi tải",
nó sẽ chỉ đăng ký để bắt đầu tải TIẾP THEO.

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

Tôi đã có cùng một vấn đề, và giải quyết nó như sau:

Thật ra tôi muốn hiển thị Tin nhắn và đóng nó tự động sau 2 giây. Vì vậy, tôi đã phải tạo (đơn giản) một cách đơn giản và một nhãn hiển thị thông báo, dừng tin nhắn trong 1500 ms để người dùng đọc nó. Và đóng hình thức tự động tạo. Sự kiện hiển thị xảy ra Sau sự kiện tải. Mã là

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

2

Bạn cũng có thể thử đặt mã của mình vào sự kiện Kích hoạt của biểu mẫu, nếu bạn muốn nó xảy ra, ngay khi biểu mẫu được kích hoạt. Bạn sẽ cần phải đưa vào kiểm tra "đã thực hiện" boolean mặc dù nếu nó chỉ được cho là chạy trên lần kích hoạt đầu tiên.


1

Đây là một câu hỏi cũ và phụ thuộc nhiều hơn vào khi bạn cần bắt đầu thói quen của mình. Vì không ai muốn một ngoại lệ tham chiếu null, tốt nhất là luôn kiểm tra null trước sau đó sử dụng khi cần thiết; điều đó một mình có thể giúp bạn tiết kiệm rất nhiều đau buồn.

Lý do phổ biến nhất cho loại câu hỏi này là khi một thùng chứa hoặc loại điều khiển tùy chỉnh cố gắng truy cập các thuộc tính được khởi tạo bên ngoài một lớp tùy chỉnh nơi các thuộc tính đó chưa được khởi tạo, do đó có khả năng khiến các giá trị null xuất hiện và thậm chí có thể gây ra ngoại lệ tham chiếu null trên các loại đối tượng. Điều đó có nghĩa là lớp của bạn đang chạy trước khi nó được khởi tạo hoàn toàn - trước khi bạn hoàn thành việc thiết lập các thuộc tính của mình, v.v. Một lý do có thể khác cho loại câu hỏi này là khi nào thực hiện đồ họa tùy chỉnh.

Để trả lời tốt nhất câu hỏi về thời điểm bắt đầu thực thi mã sau sự kiện tải biểu mẫu là theo dõi thông báo WM_Paint hoặc móc trực tiếp vào chính sự kiện vẽ. Tại sao? Sự kiện sơn chỉ kích hoạt khi tất cả các mô-đun đã được tải đầy đủ đối với sự kiện tải biểu mẫu của bạn. Lưu ý: This.visible == true không phải lúc nào cũng đúng khi nó được đặt thành true nên nó hoàn toàn không được sử dụng cho mục đích này ngoại trừ việc ẩn một biểu mẫu.

Sau đây là một ví dụ đầy đủ về cách bắt đầu thực thi mã của bạn sau sự kiện tải biểu mẫu. Bạn không nên buộc vòng lặp thông báo sơn một cách không cần thiết để chúng tôi sẽ tạo một sự kiện sẽ bắt đầu thực thi mã của bạn bên ngoài vòng lặp đó.

using System.Windows.Forms;

không gian tên 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

}

}


Điều này có vẻ dài vô cùng, và nó có bất kỳ lợi thế nào so với việc chỉ bắt sự kiện Shown không?
Steve Smith

0

Tôi biết đây là một bài viết cũ. Nhưng đây là cách tôi đã thực hiện nó:

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

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

-9

Bạn có thể đóng biểu mẫu của mình sau khi thực hiện ..

//YourForm.ActiveForm.C Đóng ();

    LoadingForm.ActiveForm.Close();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.