【发布时间】:2010-09-18 03:19:01
【问题描述】:
在 .NET 中,Windows 窗体有一个在窗体加载之前触发的事件 (Form.Load),但在窗体加载之后没有相应的事件触发。我想在表单加载后执行一些逻辑。
谁能提供解决方案的建议?
【问题讨论】:
-
虽然这个问题有很好的答案,但可能值得一提:docs.microsoft.com/en-us/dotnet/framework/winforms/…
在 .NET 中,Windows 窗体有一个在窗体加载之前触发的事件 (Form.Load),但在窗体加载之后没有相应的事件触发。我想在表单加载后执行一些逻辑。
谁能提供解决方案的建议?
【问题讨论】:
您可以使用“显示”事件:MSDN - Form.Shown
“Shown 事件仅在第一次显示表单时引发;随后最小化、最大化、恢复、隐藏、显示或无效化和重新绘制不会引发此事件。”
【讨论】:
Shown += Form1_Shown;
我有时使用(在加载中)
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 线程(在某些时候)使消息出队,处理委托,并向工作人员发出它已完成的信号……到目前为止一切顺利;-p
好的;那么如果我们在 UI 线程上使用 Control.Invoke / Control.BeginInvoke 会发生什么?它可以应付...如果您调用 Control.Invoke,那么很明智地知道消息队列上的阻塞会导致立即死锁-因此,如果您已经在 UI 线程上,它只会立即运行代码...这样对我们没有帮助...
但 Control.BeginInvoke 的工作方式不同:它总是将工作推送到队列中,即使我们已经在 UI 线程上。这是一种非常简单的说“一会儿”的方式,但没有计时器等带来的不便(无论如何,它仍然必须做同样的事情!)。
【讨论】:
第一次它不会启动“AfterLoading”,
它只会注册它以启动 NEXT Load。
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.
}
【讨论】:
我遇到了同样的问题,解决方法如下:
实际上我想显示消息并在 2 秒后自动关闭它。为此,我必须生成(动态)简单的表单和一个显示消息的标签,停止消息 1500 毫秒,以便用户阅读它。并关闭动态创建的表单。显示的事件发生在加载事件之后。所以代码是
Form MessageForm = new Form();
MessageForm.Shown += (s, e1) => {
Thread t = new Thread(() => Thread.Sleep(1500));
t.Start();
t.Join();
MessageForm.Close();
};
【讨论】:
如果您希望它在表单被激活时发生,您也可以尝试将代码放入表单的 Activated 事件中。您需要输入一个布尔值“已执行”检查,但它是否应该只在第一次激活时运行。
【讨论】:
这是一个老问题,更多地取决于您何时需要开始您的例程。由于没有人想要空引用异常,因此最好先检查空值,然后根据需要使用;仅此一项就可以为您节省很多痛苦。
此类问题的最常见原因是,当容器或自定义控件类型尝试访问在自定义类之外初始化的属性时,这些属性尚未初始化,从而可能导致填充空值,甚至可能导致对象类型的空引用异常。这意味着您的类在完全初始化之前正在运行 - 在您完成设置属性等之前。此类问题的另一个可能原因是何时执行自定义图形。
为了最好地回答表单加载事件之后何时开始执行代码的问题是监视 WM_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
}
}
【讨论】:
我知道这是一篇旧帖子。但这是我的做法:
public Form1(string myFile)
{
InitializeComponent();
this.Show();
if (myFile != null)
{
OpenFile(myFile);
}
}
private void OpenFile(string myFile = null)
{
MessageBox.Show(myFile);
}
【讨论】:
以下是在之前的正确答案中添加的一些细节,尤其是 Matthias Schappling 的答案。
在 Form1_Load 中添加一个事件处理程序,如下所示:
private void Form1_Load(object sender, EventArgs e)
{
this.Shown += new EventHandler(Form1_Shown);
}
接下来,添加将对代码执行某些操作的方法
private void Form1_Shown(Object sender, EventArgs e)
{
draw_on_my_form_or_some_other_action();
}
【讨论】:
您可以在执行一些操作后关闭您的表单..
//YourForm.ActiveForm.Close();
LoadingForm.ActiveForm.Close();
【讨论】: