Statically located winforms in C# - c#

I have three forms in C#, now when I want to show form2 I hide the main one and show the form and then when done working, hide the second form and show the main form again - I am doing this with the simple hide and show functions in winforms. Now the problem is every called form is placed on a different location on the screen, while I want all of them to stay on the same place. How to do it?

Try setting the owner of the form when you call .Show()
You can also set the start position before you call show with .StartPosition = FormStartPosition.CenterParent
Or set the form.Location property after you call show
See here and here for more details

You no doubt have a bug in your code, you are creating a new instance of the form instead of calling Show() again on the hidden form object. That's a bad kind of bug, it will make your program consume a lot of machine resources, ultimately it will crash when Windows refuses to allow your process to create more windows.
To make your scheme work, you have to write code that distinguishes between a closed form and a hidden one. Best way to do that is to explicitly keep track of its lifetime with the FormClosed event. Like this:
private Form2 form2Instance;
private void button1_Click(object sender, EventArgs e) {
if (form2Instance == null) {
// Doesn't exist yet, so create and show it
form2Instance = new Form2();
form2Instance.FormClosed += delegate { form2Instance = null; };
form2Instance.Show();
}
else {
// Already exists, unhide, restore and activate it
form2Instance.WindowState = FormWindowState.Normal;
form2Instance.Visible = true;
form2Instance.BringToFront();
}
}

Related

Can't transform windows form into myform in the load method of a user control

I'm using a user control (uc1) inside a Windows form (f1) in order to Display some of the elements of my form.
There (uc1) though I Need to Access a few elements of the form (f1). Thus I had the following line i the load:
private void UC1_Load(object Sender, EventArgs e)
{
F1 parentFrom = (F1)this.parent;
}
Now this works absolutely fine on execute BUT when I try to open F1 in the designer I get the error (Translation from my mother language):
The object of the type "System.Windows.Forms.Form" can not be
transformed into the type "F1".
Thus I can't open it in the designer without ignoring this "error". My question here is thus am I doing something wrong or can I somehow avoid this error?
You can either check for null and only work with it if it's valid, which you should probably be doing anyway:
F1 parentFrom = this.parent as F1;
if(parentForm != null)
{
// Do something.
}
Or you can check LicenceManager.UsageMode to see if the control is running in design mode:
if (LicenseManager.UsageMode != LicenseUsageMode.Designtime)
{
F1 parentFrom = (F1)this.parent;
}
Or why not even a mix of both.
As a side note, it seems to defeat the point of a user control if it can only be used directly on one specific form. Perhaps you do have a valid use case, or perhaps you should think about refactoring your approach. For example, if you want something to happen on the form when the user control is updated you could use a custom event and the form can take the appropriate action when the event is fired.

Updating Form1's widgets by clicking Form2's button in Visual C# Windows Forms

I'm fairly new to Visual C# and I'm writing an GUI app with multiple forms. One form is main window, and the rest are some kind of option windows. When showing an option window, I need to load some data to it (for example a string to window's editbox), then edit it and return back to main window when closing option window. Is there any simple way I can achieve it?
I've found some solutions like, or c# event handling between two forms, but I can't really conform it to my needs. I was thinking about passing data in constructor, but how to get it back? I've found something about ShowDialog, but as I said I'm new to C# (started yesterday ^^) and don't know if I can use it.
Any ideas, please?
I found the following previous answer which outlines sending specific properties from the one form to another:
Send values from one form to another form
The using keyword will also ensure that the form is cleaned-up properly, here's a link to it's usage (pardon the pun...) : http://msdn.microsoft.com/en-us/library/vstudio/yh598w02.aspx
I've run into the same issue to be honest, and I have to say that prior to this discussion I would just pass the parent form itself to the child and alter it in that way. Such as:
ChildForm child = new ChildForm(this); //from the parent
and
public ChildForm(ParentForm parent)
{
this.parent = parent;
}
Probably not the best convention though, as you probably don't need to access that much from the parent as the child.
Thanks guys, I think I finally get it. Idle_Mind, your idea was the easiest in my point of view, so I decided to use it. If someone else has a problem like this, here's what I've coded:
In main window form: when button is clicked, a new form appears; after closing it, label1 shows the text typed in that form
private void Button1_Click(object sender, EventArgs e)
{
LoadDataForm loaddata = new LoadDataForm("initial value");
if (loaddata.ShowDialog() == DialogResult.OK)
{
label1.Text = loaddata.textBox1.Text;
}
}
In load data form: argument passed in form's constructor appears in textBox1; textBox1's Modifiers property has to be modified to "public"
public LoadDataForm(string initvalue)
{
InitializeComponent();
textBox1.Text = initvalue;
}
private void ApplyButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.OK;
}
Regards,
mopsiok

Get Data from Windows Form into C# program

I want my C# program to collect data. Then, when the OK button is clicked, I want this data to be loaded into my program -- such as into variables in Main(), or into data members of a class I have constructed, and I want the form to then go away -- not be hidden, but actually closed. Alas, read as I might in the book I have, the data collected by the form stays in the form, execution proceeds within the form, and the same form is used to display the result of the program's computations. Sheesh. All I want is to capture the form's information, close the form and proceed with my program. I would appreciate some tips on geting data from a form into Main() or into a class's data members.
Thanks,
Lucky
What you want to do is perfectly acceptable, it just isn't typical.
When you use Visual Studio to generate a WinForms project, it creates one form for you and
generates a call to Application.Run(new Form1()). For this version of the Run() method, your application will exit when the "main form" (the one passed to Run(), in this case Form1) closes.
There are three overloads (versions) of Application.Run(). For your purposes, you need to use a different overload:
Application.Run(ApplicationContext)
When you use this overload of Run(), you get to control when the application exits. In a nutshell, here's one way you could do it:
Create a class which inherits
ApplicationContext.
In its constructor:
Create your form.
Subscribe to its Closing and Closed events.
Show your form.
In your FormClosing event handler,
get the data from the form.
In your FormClosed event handler, do
whatever you want to do with the
data, and then exit the thread (or do something else).
Here's a crude example, but I will leave out the code for the form itself. Assume the form simply has one TextBox which has its Modifiers property set to Public. (This is NOT an elegant way to get data from a form, but that part is up to you).
namespace Me.MyDemo
{
static class Program
{
[STAThread]
static void Main()
{
MyApplicationContext ac = new MyApplicationContext();
Application.Run(ac);
}
class MyApplicationContext : ApplicationContext
{
string _text = "";
public MyApplicationContext()
{
Form1 f1 = new Form1();
f1.FormClosing += new FormClosingEventHandler(f1_FormClosing);
f1.FormClosed += new FormClosedEventHandler(f1_FormClosed);
Console.WriteLine("I am here. Showing form in 1 second...");
Thread.Sleep(1000);
f1.Show();
}
void f1_FormClosing(object sender, FormClosingEventArgs e)
{
_text = (sender as Form1).textBox1.Text;
}
void f1_FormClosed(object sender, FormClosedEventArgs e)
{
Console.WriteLine("You wrote: " + _text);
Console.WriteLine("I will go away in 2 seconds...");
Thread.Sleep(2000);
ExitThread();
}
}
}
}
Of course, you don't have to exit the thread. You can leave it running if there are other things for your program to do. It will just run as a windowless process. Just remember that you're responsible for eventually ending it.
For more help, look at the documentation for the System.Windows.Forms.Application class, and the ApplicationContext class.
For getting the data from your form, there are many ways to approach this. The simple way is to just give your form some public properties. A more sophisticated way would be to create a data class and use data-bound controls on your form.
You're writing in WinForms? As far as I know a Windows application has to have a window, even if it's one pixel by one pixel.
Have you seen any other Windows applications that work the way that you want yours to work? Opens a window, the window closes, but the program keeps on running? This is generally considered undesired behavior, similar to viruses and trojans.
You can create a console application or a Windows service with no GUI, of course.
What is the application doing behind the scenes after the data is entered? If it's just doing some calculations and saving to disk, uploading, or printing, leave the window open for that and then exit when it's done. Possibly include a progress bar.

FileSystemWatcher.SynchronizingObject without a form

I have an windows form application written in C# in which I use a FileSystemWatcher to monitor a folder for new files and then perform some processing on them. My application is designed to run in the system tray and therefore does not instantiate any forms at startup. The problem is that the Created event is firing on a separate thread and when I try to create an instance of a form in the Created event I get an ThreadStateException that states I need to be running in SingleThreadApartment. I think I need to set the FileSystemWatcher.SynchronizingObject property but don't know what to use since there is no main form in my application.
You will have to call Application.Run() in your Main() method to get the Windows Forms synchronziation machinery in place so that FileSystemWatcher can properly marshal the call to the main thread. The problem you'll have then is that the main form will become visible. Fix that by pasting this code into the class:
protected override void SetVisibleCore(bool value) {
if (!this.IsHandleCreated) {
this.CreateHandle();
value = false;
}
base.SetVisibleCore(value);
}
There are no restrictions on what your form looks like if you do this.
You don’t need to pass any forms to Application.Run at all. Then you can save having to mess around with form visibility. Just do this:
var InvokerForm = new Form();
var dummy = InvokerForm.Handle; // force handle creation
Application.Run();
Just one gotcha there - the form handle creation needs to be forced by accessing it once.
The simplest way to do this is to make a hidden form and pass it to Application.Run.
You can then set the SynchronizingObject property to the hidden form.
To make sure it's a hidden form, set the ControlBox and ShowInTaskbar properties to false.

Removing a Control from a Form

So I've got some serious problems with removing a Control from a Form of my application. It's kinda messed up but I can't change anything. I have a form and I have a separated user Control. The control opens an exe file and shows a progress bar while loading it's bytes. And here comes the problem. I do all of it with a BackgroundWorker and when the worker_DoWorkerCompleted method is called the original form should show a MessageBox and remove the Control.
BackGround_Loader bgLoad = new BackGround_Loader();
bgLoad.Location = new Point(this.Width/2 - bgLoad.Width/2, this.Height/2 - bgLoad.Height/2);
this.Controls.Add(bgLoad);
bgLoad.BringToFront();
bgLoad.AddReferences(this.executableFile, this.SourceReader);
bgLoad.occuredEvent();
At first I set the control's location to be in the middle of the Form itself. Then I add the control to the form, and bring it to the front. After these I send the path of the executable and a RichTextBox's reference to this. With the occuredEvent I start the BackgroundWorker itself. And here comes my problem. I should show a MessageBox in the Form when the in the bgLoad the backgroundworker gets to the DoWorkerCompleted status. Kindly I have no idea how to do it. It works just perfect however the control stays in the middle of the form.
UI actions must be performed on the main UI thread. The events that get raised from the background worker thread are (obviously) in a different thread.
You need something like the following code:
private void backgroundWorker_DoWork(object sender, AlbumInfoEventArgs e)
{
// Check with an element on the form whether this is a cross thread call
if (dataGridView.InvokeRequired)
{
dataGridView.Invoke((MethodInvoker)delegate { AddToGrid(e.AlbumInfo); });
}
else
{
AddToGrid(e.AlbumInfo);
}
}
In this case AddToGrid is my method for adding a row to a DataGridView, but in your case it will be a method that does what you need to do.
Similarly for the backgroundWorker_RunWorkerCompleted method
See this MSDN example
I could find a way to solve the problem but I don't really like it. In the addReferences method I pass the Form itself and an object of the bgLoad class. Then in the RunWorkerCompleted I check if the control is on the form and if it is then I remove it.
bgLoad.AddReferences(this, bgLoad, this.executableFile, this.SourceReader);
...
private void worker_DoWorkerCompleted(object sender, DoWorkerEventArgs e) {
if(this.MainForm.Controls.Contains(this.Control) {
this.MainForm.Controls.Remove(this.Control);
}
}
Like this it works but it's awful for me.

Categories