C# completely loading a WinForm without showing it (VS2010) - c#

Working with DevExpress 2012 vol 2.10
C# on top of VS 2010
First question seems to have been unclear...
So lets clear it a bit (or try to at least)!
We are building a MainForm with a Ribbon containing many buttons. Every button in the Ribbon is disabled until their respective state is "ready to enable".
"ready to enable" depends on one thing : The WinForm_Popup associated with the button has been completely built, including data retrieval and DevExpress.ExpressApp.ListView construction.
Retrieving data from database takes less than 0.1 second
Calling the WinForm_Popup.Show() takles over 15 seconds
We tried to put this in a Thread or a Task, with no success: It crashes on WinForm_Popup.Show() with an exception related to the DragDrop Event.
What I know by now, is Show() method takes long, but I don't have a clue what happens in this method, but constructing the DevExpress.ExpressApp.ListView, which should be taken away from Show (or do it in a Task or Thred maybe).
Or, in other words, having the WinForm_Popup UI completely built as when it's shown but doing this asynchronously (like in a separate Task, for example).
Any idea, advice, help, link, suggestion, tip... Any "thing" ?

Make a new form and make it empty. In the program.cs file change your main form to the new form. Then make the new form constructor be like this:
public newForm()
{
this.Hide();
Thread backTh = new Thread(() =>
{
MainForm mf = new MainForm();
mf.Show();
});
backTh.Start();
}

I would go for the opposite approach, one that is usually used in slow loading systems like a web browser. Why don't you load the form fast, then use a thread to populate your slow loading grid view?
That way, you can have like a spinning hourglass (or something less 1995) that will tell your users that the data is loading.

Related

How do I transition between forms C# Winforms?

This may seem like a rather obvious and extremely newcomer question (and it is), but I've merely been attempting to transition between multiple forms in C# Winforms and somehow managed to encounter numerous complications:
To begin, I used the obvious:
frm_hub hub = new frm_hub();
hub.Show();
However, each time this code run, a new instance of frm_hub was created and using hub.Close(); would not work because it was not closing the same new instance of frm_hub
Is a way to close the same instance of a form from a different form - say with a global variable? Or is there some way to integrate a Close(); so the entire program continues to function and new form displays?
As a possible solution to the above issue, I tried to store the same form as a variable:
frm_hub hub = new frm_hub();
private void OpenForm()
{
hub.Show()
}
However the runtime error: 'System.StackOverflowException: 'Exception of type 'System.StackOverflowException' was thrown.' was showing when I attempted to use this same tactic of storing the form as a variable in the two forms.
Why is this error occurring? And is there any way I can overcome it?
Finally, during some reading to counter this issue I discovered the use of controls and panels, and in this way, I could create an interface that opens different the different forms in a panel
However, my attempt of this required the use of anchors to get the form to display remotely true to the Designer appearance
If I do not require the form to be resizable, how can use panels to display a different form and at that in a way that displays the design elements how I have them positioned
Apologies again for my beginner understanding and use of terminology, feel free to seek clarification for crucial details I probably haven't included haha,
Thank you!
I used the following, not sure it's best practice. I used a button ShowFrmHubButton and disabled it when the window is already shown.
In my example the second form is modal, and you can't use the first window as long as the second is displayed.
ShowFrmHubButton.IsEnabled = false;
var frmHubWindow = new frm_hub ()
{
Owner = this
};
frmHubWindow.ShowDialog();
ShowFrmHubButton.IsEnabled = true;
Then, when you close\cancel the second form use this.Close();

C# Open a form from another form (too much processing memory)

I have been looking for some time on ways to open a second form from another already shown form.
This is some piece of code that works:
frmSecond second = new frmSecond();
this.Hide();
second.ShowDialog();
this.Close();
What it does basically is to Hide() the currently opened form, then it opens another form (the ShowDialog() method). It will only Close() the currently hidden form when the form you have just created is closed.
The problem here is: this way of doing it creates an immense thread of forms. If I need to go from frmSecond to frmThird, it will maintain the first form and the frmSecond being executed in the background, while only showing the frmThird.
Then, as the frmThird is open, if I need to get back to the first form, I would use some code like:
frmFirst first = new frmFirst();
this.Hide();
first.ShowDialog();
this.Close();
And it would create another frmFirst! Then we would have three forms being executed in the background (the first frmFirst, frmSecond, and frmThird).
This method works, but uses an increasingly amount of processing memory, which may be prejudicial for any kind of project.
Is there any alternative or add up to correct this problem?
If anything is unclear, please don't bother in letting me know.
Thank you.
If you want to get access to already created forms try using the static Application.OpenForms property. It contains a list of all of the forms currently open in your application. Documentation is here.
As an example, if you always want to keep frmFirst open and then navigate back to it when you close one of your other forms you can do this:
frmFirst existing = Application.OpenForms.OfType<frmFirst>().FirstOrDefault();
if (existing != null)
existing.Show();
You would need to remove your this.Close() calls for this to work.
To free the memory you need to dispose the form using the Dispose method when it is no longer needed.
Seems like you have a desing error here
Then, as the frmThird is open, if I need to get back to the first
form, I would use some code like:
frmFirst first = new frmFirst();
this.Hide();
first.ShowDialog();
this.Close();
This will leave the original created frmFirst in memory, not visible, doing nothing but eating memory.
If you know you want to get back to frmFirst that was created before, why not just do this :
frmFirst.Show();
and save you lots of memory.
You have 2 choices actually
Hide forms and reactivate them when needed
Close and dispose forms, and recreate them when needed
What you are doing is creating each form over and over again, without getting rid of the prior created forms. Hence you need lots of memory for hidden forms...

Cross thread operation error showing a form during a form.show

I have a tricky problem here that I have not been able to solve and neither have the people I asked on msdn forums.
I am using a third part product (signal lab from mitov.com) which is a set of .net components.
I have created a windows form app that works fine if it is run.
I now want to show this form from another form when this other form loads (or shows, or activates...).
I already have examples of this working with another form: Here is the typical code:
I am loading a form (SecondForm) from the main program...
private void SecondForm_Load(object sender, EventArgs e)
{
Form _macros = new Macros(this); //this works perfectly fine
_macros.show(this);
//this is where I have no success
Form _spectrum = new SpectrumScope;
_spectrum.Show();
}
I get various errors from no form displayed and then an exception about not instantiating the _spectrum, to an error about cross threaded operation not being allowed, to a blue screen with a message about clocks not being synchronized between processors.
If I place a button on "Second Form" and add the show form code to the click event, it works fine.
If I try to use form.activated, or form shown instead of form.load there is not difference.
If I add a time to form Shown, which then does a button.performClick, there is no difference.
Obviously the form which contains many components (and many threads behind the scene) does not like the fact that it is not being opened by the user.
I'm fairly new to C# and I'm pretty sure this is threading related.
Thank you for any help.
Try the blow code in your form load method, that should let .Net manage the threading for you.
this.Invoke(new MethodInvoker(() => (new SpectrumScope).Show()));
Well, the problem is fixed. However, I don't really know why the issue exists.
In the spectrum form I reference static variables in the secondform. Now, I use them as follows:
string newFrequency = secondForm.frequency;
This works. However, some of these variables need to have this done:
string newBandWidth = secondForm.bandwidth.substring(2,4);
This is the command that fails. I am told I need the "new" keywork.
I changed my code provide the the string without the need to get the substring and now it all works ok.
Anybody have any ideas?

Form load interface

In my form_load I have a mysql connection that loads data in a datagrid, when starting my application it will first try to load the mysql database and after its done it will load the form/interface with all the controls.
This leaves the user the impression nothing is happening, how can I first load the form/interface with all the controls and then my mysql database?
I would say, 3 approaches
1 - Separate Splash screen
2 - On-Form "splash screen" - first thing you do on form.load, is Me.Show(), then show a message, something like "Please wait while data is loaded". Progress can be shown to users as well using Application.DoEvents which will refresh your screen.
3 - Background worker thread. Using it, you can actually give user progress updates. That will leave your form completely responsive. http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx
Move your code to Shown event or OnShown overridden method. this will allow your form shown to user before it loads grid.
You should move your "Database calls" to worker threads as well.
protected override void OnShown(EventArgs e)
{
//Delegate the DB calls to worker threads here
//everything will be smooth then..
base.OnShown(e);
}
There are two ways to approach this situation. You need to pick the approach that best suits your needs.
Approach 1: Create a splash screen. A splash screen is a small window that opens up and usually had product info and a message like "Initializing...". You can see this in a lot of applications, such as Microsoft Office. You can see how to make one by looking at this article.
Approach 2: You will need to make your load data happen in a separate thread then your UI. You will need to load your data in the separate thread and bind it to a list of some sort temporarily, then after its done, bind the list to your Datagrid
Use other thread for loading data from mysql. It's loading form first, but not displaying it until code has finished work.
new Thread(new ThreadStart(LoadDataMethodHere)).Start();
You can use Form Shown event.
Alternatively you can use a different thread to connect to database and show data or use a timer.

Delay loading of combobox when form loads

I've got a Windows Forms (C#) project with multiple comboboxes/listboxes etc that are populated when the form loads.
The problem is that the loading of the comboboxes/listboxes is slow, and since the loading is done when the form is trying to display the entire form isn't shown until all the controls have been populated. This can in some circumstances be 20+ seconds.
Had there been a Form_finished_loaded type of event I could have put my code in there, but I can't find an event that is fired after the form is done drawing the basic controls.
I have one requirement though - the loading has to be done in the main thread (since I get the items from a non-threading friendly COM-application).
I have found one potential solution, but perhaps there is a better way?
I can create a System.Timer.Timer when creating the form, and have the first Tick be called about 1 second later, and then populate the lists from that tick. That gives the form enough time to be displayed before it starts filling the lists.
Does anyone have any other tips on how to delay the loading of the controls?
There is the Shown event that "occurs whenever the form is first displayed.". Also you may want to use the BeginUpdate and EndUpdate functions to make the populating of your combobox faster.
It has that certain smell of workaround, but this approach should fulfil your needs:
private bool _hasInitialized = false;
private void Form1_Shown(object sender, EventArgs e)
{
if (!_hasInitialized)
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.Sleep(200); // brief sleep to allow the main thread
// to paint the form nicely
this.Invoke((Action)delegate { LoadData(); });
});
}
}
private void LoadData()
{
// do the data loading
_hasInitialized = true;
}
What it does is that it reacts when the form is shown, checks if it has already been initialized before, and if not it spawns a thread that will wait for a brief moment before calling the LoadData method on the main thread. This will allow for the form to get painted properly. The samething could perhaps be achieve by simply calling this.Refresh() but I like the idea of letting the system decide how to do the work.
I would still try to push the data loading onto a worker thread, invoking back on the main thread for populating the UI (if it is at all possible with the COM component).
Can you get your data from a web service that calls the COM component?
That way, you can display empty controls on a Locked form at the start, make Asynchronous calls to get the data, and on return populate the respective combos, and once all of them are loaded, you can unlock the form for the user to use.
You could listen for the VisibleChanged event and the first time it's value is true you put your initialization code.
Isn't FormShown the event you're looking for?
When you say that you cannot use a background thread because of COM what do you mean? I am using many COM components within my apps and running them on background threads.
If you create a new thread as an STAThread you can probably load the ComboBox/ListBox on a Non-UI thread. IIRC the ThreadPool allocates worker threads as MTAThread so you'll need to actually create a thread manually instead of using ThreadPool.QueueUserWorkItem.

Categories

Resources