I need some help on a thing that I can't resolve.
I've a Windows Form with a DataGridView who is populated with a large amount of data.
This data is stored in a SQL Server Database and retrieved by a simple piece of ADO.NET code.
I'm already using the BackGroundWorker class to perform this kind of operation but the form still freezes for 1-2 second.
Is there a way to delay the showing of the form? Like a show form only when all data in loaded? I've tried to make it not visible or to use Hide() and Show() method but still not have any results.
I've found a easy work-around.
Change the modifiers of the BackGroundWorker to public.
Create the instance of the form, run Form.CreateControl() and call the BackGroundWorker.RunWorkerAsync() method.
In the DoWork event I put: data retrieving and population of the controls (DataGridView, combobox and textbox).
In the RunWorkerCompleted just the Form.Show() method.
That's all. Is this a nice solution?
Remove InitializeComponent(); from constructor of your form and call this method when data has loaded
Related
I have 2 forms. In form one I enter information and the second one works as a helper to get codes for the first one(using it with ShowDialog() method). Since the information retrieved in the second form comes from a database that is being remotely accessed sometimes it takes a few seconds so what i did is to move the lengthy method that loads the information into the DataGridView to a BackgroundWorker, the code in the DoWork is:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
this.Invoke((MethodInvoker)delegate
{
//Method to retrieve records
});
}
and start it in the form's Shown() method. Now, my problem is, that the first time an instance of the form is created it works perfect but from the first time on it shows up like this:
How can I fix this issue?
First of all read the documentation about types you use:
You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events.Source
Because of the this.Invoke(... you basically do all the fetching from database on the UI thread, and that's why your form isn't redrawn.
In order to fix this issue:
Remove this.Invoke and any other code that accesses UI controls from the DoWork event handler. In that handler you only want to fetch the records from database, and NOT update any UI.
Move your UI updating code to the RunWorkerCompleted event handler.
Last but not least, you may want to start your data loading not on the form's Shown event but rather Form.Load, because it precedes the Shown and is raised before the form is displayed.
I've tried overriding the OnLoad event, but the form is getting drawn before this method finishes. I am calling the base.OnLoad method. But, the form is partially getting drawn (artifacts are seen) during the event. I notice this because I'm hitting the database and it is taking some time. In the event, I'm getting some data and binding it to the form's controls. Please don't tell me to use a separate thread. For simplicity, I would rather just show a busy cursor while the data is being loaded.
UPDATE:
Ok, I think you guys/gals have convinced me. I'll use a separate thread. I wasn't aware of the BackgroundWorker and it was very easy to implement. Now my form is loading quickly. And then, all of a sudden my combo boxes are populated. But, I'd like prevent the user from clicking on the combos before they're populated. What is the best way/standard way of doing this using Winforms? Is there a way to turn off input events in the form until the background worker is finished?
I would recommend that you cover the form with a Loading label before you start loading.
You should be able to solve the problem by placing your loading in the constructor code before the call to IntializeComponent(). At this point, the controls on the form have not yet been created (because this is what InitializeComponent does).
However, the form is also not yet visible in this phase. If you want to show a blank form, then I think a possible solution (I haven't tried that, but I think it should work) would be to call this.Show() (to display the form) and Application.DoEvents() to let WinForms process events and display the form.
You could try doing your expensive operations in the form's constructor, so that when it's time to show the form, it already has the data it needs to render. Also look into SuspendLayout/ResumeLayout methods.
But none of these solutions will be as graceful as using a different thread to perform expensive operations.
I am not sure if this will help or not, but the Move event is called before Load.
The Shown event is good for this. Your form will be completely displayed, then the Shown event is fired. This will give the user a clean screen without partially drawn fields while you load your data.
In your Shown event handler, turn on the hourglass, do your work and then turn off the hourglass.
The ComboBox has a BeginUpdate() and EndUpdate() that can be called when adding large amounts of data or slow data to the control. SuspendLayout() and 'ResumeLayout()` on the form may also help with your redraw issues.
You can also disable the control, if all you want is to prevent the user from clicking it. If you disable the form itself, all contained controls will also be disabled.
If you're using background threads, you'll have to make sure you call these from the main UI thread before starting the thread, and again from the main UI thread when the background worker is complete.
I have a C# windows forms application. The way I currently have it set up, when Form1_Load() runs it checks for recovered unsaved data and if it finds some it prompts the user if they want to open that data. When the program runs it works alright but the message box is shown right away and the main program form (Form1) does not show until after the user clicks yes or no. I would like the Form1 to pop up first and then the message box prompt.
Now to get around this problem before I have created a timer in my Form, started the timer in the Form1_Load() method, and then performed the check and user prompt in the first Timer Tick Event. This technique solves the problem but is seems like there might be a better way.
Do you guys have any better ideas?
Edit: I think I have also used a background worker to do something similar. It just seems kinda goofy to go through all the trouble of invoking the method to back to the form thread and all that crap just to have it delayed a couple milliseconds!
I would use Form1_Shown()
Use the Shown event. It seems to suit what you need, and will only display the first time the form is shown.
Form f1 = new Form();
f1.Shown += new EventHandler(f1_Shown);
public void f1_Shown(object sender, EventArgs e)
{
// Show dialog in here
}
Try the "Shown" event:
Form.Show Event
Using a Windows.Forms.Timer is a good, stable, well-known, and easily understood technique for doing what you want. I would avoid any other timer objects.
The form's Shown event works well.
Overload / override the Show method. (My preferred technique for greater control.) In this method, I would do the checking needed. When ready, I would call the base.Show method, then do any other processing, such as message boxes, prompts, logging, or whatever.
i have a prioblem with a callback because my Form1 open Form2 and send data to Form2 after this return information to another form...please help
i can send object from form1 to form2, but the result of the form2 method must be returned by callback to another form(example form 3).
i hope that you understood my question..
The fact that you have multiple forms operating on the same data means that a better option is to encapsulate that data in a set of "model" classes that can handle both handing out information to your forms and persisting any changes to storage as necessary.
The advantage of this is when you have multiple forms that need to deal with the same data, you can publish callbacks on the model objects for change notification. Each form subscribes to the events in the model that it cares about and it means any number of forms can manipulate your model and all the forms can maintain current state by reacting to notifications.
When does this way you don't care about which forms are manipulating the data and you don't need to pass anything more than the model class when launching a new form. Likewise, when a form requests a save, all the forms can update the state so they don't show the pending change.
When passing data between multiple forms, its often useful to store a refernceto the other forms as private variables within forms, populated only by the constructor of the form.
However, be aware that this can give you memory problems, partuicularly with events still being wired up to forms held in memory on other forms.
You could probably have your Form3 listen on the FormClosed event from Form2, then have some code to ask for the return data from Form2. Alternatively, you could create and event, FormClosedWithReturnValue(object sender, SomeArgsThatContainsReturnData data) in Form2 and have Form3 listen on that event. Hope that helps.
New to C# and .NET.
In a windows application I place a form to query a user for some input. The user fills out the form and presses 'ok'.
What is the "correct" or "appropriate" method of retrieving that data from the form? Do forms have a return statement? Do I send a message?
Thanks in advance.
you can have the parent form subscribe to events from the child form and still do the same thing or put the form results into an event arg statement
you should listen to the click event of the button and you will get a call back and you can simply read the properties from the form objects (txtBox.Text, etc . . )
After they press OK, the form will close, but (as long as the form variable is still in scope), its members will still contain all of the data. Save the input to a member variable and access it from your main program using an accessor. If the form is not modal, your main program can subscribe to the form closing event and get the information then.