在.NET中,Windows窗体有一个在加载窗体之前触发的事件(Form.Load),但是在加载窗体后没有触发相应的事件。我希望在表单加载后执行一些逻辑。
有人可以就解决方案提出建议吗?
答案 0 :(得分:169)
您可以使用“已显示”事件:MSDN - Form.Shown
“所显示的事件仅在第一次显示表单时引发;随后最小化,最大化,恢复,隐藏,显示或无效以及重新绘制将不会引发此事件。”
答案 1 :(得分:44)
我有时会使用(在加载中)
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线程上。这是一种非常简单的方式“在片刻”,但没有计时器等的不便(无论如何仍然必须做同样的事情!)。
答案 2 :(得分:6)
我遇到了同样的问题,并解决了如下问题:
实际上我想显示消息并在2秒后自动关闭它。为此我必须生成(动态)简单表单和一个标签显示消息,停止消息1500毫秒,以便用户阅读它。并关闭动态创建的表单。显示的事件发生在加载事件之后。所以代码是
Form MessageForm = new Form();
MessageForm.Shown += (s, e1) => {
Thread t = new Thread(() => Thread.Sleep(1500));
t.Start();
t.Join();
MessageForm.Close();
};
答案 3 :(得分:2)
您也可以尝试将代码放在表单的Activated事件中,如果您希望它发生,只需在激活表单时。如果它只应该在第一次激活时运行,你需要输入一个布尔“已执行”检查。
答案 4 :(得分:1)
这是一个古老的问题,更多地取决于你何时需要开始你的日常工作。由于没有人想要一个空引用异常,所以最好首先检查null然后根据需要使用;只有这一点可以为你带来很多悲伤。
此类问题的最常见原因是容器或自定义控件类型尝试访问在自定义类之外初始化的属性,其中这些属性尚未初始化,从而可能导致填充空值,甚至可能导致对象类型的null引用异常。这意味着您的类在完全初始化之前正在运行 - 在您完成属性设置之前等等。此类问题的另一个可能原因是何时执行自定义图形。
为了最好地回答关于何时开始在表单加载事件之后执行代码的问题,要监视WM_Paint消息或直接挂钩到paint事件本身。为什么?只有当所有模块完全加载到表单加载事件时,才会触发paint事件。注意:当设置为true时,This.visible == 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
}
}
答案 5 :(得分:0)
我知道这是旧帖子。但是,这是我的操作方式:
public Form1(string myFile)
{
InitializeComponent();
this.Show();
if (myFile != null)
{
OpenFile(myFile);
}
}
private void OpenFile(string myFile = null)
{
MessageBox.Show(myFile);
}
答案 6 :(得分:0)
以下是添加到之前正确答案中的一些细节,尤其是 Matthias Schippling 的答案。
在 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();
}
答案 7 :(得分:-9)
您可以在执行一段时间后关闭表单。
// YourForm.ActiveForm.Close();
LoadingForm.ActiveForm.Close();