Winforms Controlling Forms - c#

How can i control all my forms from main ()
Form1 frm1 = new Form1();
Form1 frm2 = new Form1();
Form1 frm3 = new Form1();
Application.Run(frm1); // This way form-control goes to the frm1.
// In frm1 i have to write
frm1.Clicked += ()=>frm2.Show;
// I want the form-controlling style more explicitly
// I dont want to use Application.Run()
frm1.Show();
frm1.Clicked += frm2.Show();
form.ShowDialog () helps much but the execution stack can overflow.
Form.Show and Form.Hide methods runs when an application class has been set.
In Application.Run (Form) way there's always a main form. and i dont want this one. Any other approach you use in this problem

Your problem is, that you have four forms. All of them should exist side by side, but because you made Form1 to the master you got some problems.
To solve this you need another FormMaster above all four of them. This one will be started from Application.Run(). Now this form can be Visible = false, but in its constructor you can create all your four forms and decide how they will be glued together, which one will be shown first and under which circumstances your whole application will be closed.

The usual way is to use event handlers.

All I can understand is that you have several WinForms and you want some main Form to control them? Well, if I understanding/assumption is correct, then about controlling like following?
public partial class Form3 : Form
{
private void Form3_Load(object sender, EventArgs e)
{
Demo();
}
MyMainForm main = new MyMainForm(); //Your actual form
private void Demo()
{
main.Click += new EventHandler(main_Click);
main.ShowDialog();
}
void main_Click(object sender, EventArgs e)
{
MyNotificationForm notify = new MyNotificationForm();//Your notification form
notify.Name = "notify";
notify.Click += new EventHandler(notify_Click);
notify.ShowDialog(main);
}
void notify_Click(object sender, EventArgs e)
{
MyWarningForm warning = new MyWarningForm();//Your warning form
warning.Click += new EventHandler(warning_Click);
warning.ShowDialog(main.ActiveMdiChild);
}
void warning_Click(object sender, EventArgs e)
{
((Form)sender).Close(); //Click on form would close this.
}
}
Following is how I'd implement the classes.
public class CBaseForm : Form
{ public CBaseForm() { this.Text = "Main App"; } }
public class MyWarningForm : CBaseForm
{ public MyWarningForm() { Label lbl = new Label(); lbl.Text = "Warning Form"; this.Controls.Add(lbl); } }
public class MyNotificationForm : CBaseForm
{ public MyNotificationForm() { Label lbl = new Label(); lbl.Text = "Notification Form"; this.Controls.Add(lbl); } }
public class MyMainForm : CBaseForm
{ public MyMainForm() { Label lbl = new Label(); lbl.Text = "Controller Form"; this.Controls.Add(lbl); } }
And you MainForm would start conventionally
Application.Run(new Form3());
Let me know if I dragged your question to 180 degrees!

Related

Label Text proprety would not change

So I am trying to show the progress of my application from Form2 to Form1, using a huge Label(located on Form1), but the Text proprety of the Label doesn't change using my code.
There is a download process on executed via Form2 and when it finishes I want a label on Form1 to be updated to notify the user of a completion.
Here is the code:
in Form1:
public string LabelText
{
get
{
return this.label1.Text;
}
set
{
this.label1.Text = value;
this.Refresh();
}
}
in Form2:
private void DLClient(string link, string saveloc)
{
webClient = new WebClient();
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
webClient.DownloadDataCompleted += new DownloadDataCompletedEventHandler(webClient_DownloadDataCompleted);
webClient.DownloadDataAsync(new Uri(link));
}
private void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
}
private void webClient_DownloadDataCompleted(Object sender, DownloadDataCompletedEventArgs e)
{
byte[] downloadedBytes = e.Result;
Stream file = File.Open(saveloc, FileMode.Create);
file.Write(downloadedBytes, 0, downloadedBytes.Length);
file.Close();
webClient.Dispose();
(new Form1()).LabelText = "Desired Text";//the changing code
Close();
I don't think there is a use for the calling code of Form2 within Form1 to be posted because it's pretty much working 100%.
Pass Form2 THE instance of Form1, like in form2's class constructor.
Don't instantiate a new (invisible) Form1, like you're doing here:
(new Form1()).LabelText
The solution:
private Form form1;
public Form2(Form theForm1) {
form1 = theForm1;
}
...
((Form1)form1).LabelText = "It works";
The calling code:
Form2 frm2 = new Form2(this);
"this" is the Form1 instance.
While setting the label text, you are initializing new instance of Form1, so the desired text is actually being set in new Form1 and not in the Form that is already open. These are two different instances and do not know each other.
Ideally I would do this by creating an event for this say, DownloadCompleted or something like this; raise the event in Form2 and handle this event in Form1.
Another quick option would be to have an instance of Form1 in Form2, then you can assign this property just before showing up the Form2. Something like this -
var objForm2 = new Form2();
objForm2.objForm1 = this;
objForm2.ShowDialog();
...and then in Form2 -
objForm1 .LabelText = "Desired Text";//the changing code

LinkLabel doesn't open

I'm creating LinkLabel in Form2 and Form3 with the same code. Form2 and Form3 are separate classes so the names don't interferer. They are both created, but in the Form 3 links open, in the Form2 nothing happens.
This is the code for Form2
public partial class Form2 : Form
{
public void createFormEntry(List<string> videoId)
{
LinkLabel link = new LinkLabel();
link.Name = "link";
link.AutoSize = true;
link.Location = new Point(76, 8);
link.Text = "www.example.com";
link.LinkClicked += new LinkLabelLinkClickedEventHandler(link_LinkClicked);
this.Controls.Add(link);
}
private void link_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
System.Diagnostics.Process.Start("http://www.example.com");
}
}
And this is for the Form3
public partial class Form3 : Form
{
private void createFormEntry(Feed<Video> videoFeed)
{
LinkLabel link = new LinkLabel();
link.Name = "link";
link.AutoSize = true;
link.Location = new Point(76, 8);
link.Text = "www.example.com";
link.LinkClicked += new LinkLabelLinkClickedEventHandler(link_LinkClicked);
this.Controls.Add(link);
}
private void link_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
System.Diagnostics.Process.Start("http://www.example.com");
}
}
They are in different classes. Form2 opens before Form3.
What could be wrong?
EDIT: now when I added more code, I see in Form2 createFormEntry is public and in Form3 it is set as private.
Could that be a reason?
Your trying to open a link without telling the program how or what to open that link in. You should tell it to search it in a program or something!

Bring already opened winform application to front without API?

Hi,
Say that we got a WinForm application(app1) running in the background, now another application(app2)(the topmost active application) trigger a startProcess with the app1.
Now I need app1 to use the existing instance and bring it to topmost application(not only within the app1 application).
I have found this : http://sanity-free.org/143/csharp_dotnet_single_instance_application.html
Is it true that its not possible to do this without API? I have looked att bringToFront, Activate and Focus but all these does seem to only effect within a application and not between applications?
I don't know what you mean "without API" or why that matters.
However the simplest way is via WindowsFormsApplicationBase. It gives you all you need, with just a few lines of code.
You need to add a reference to the Microsoft.VisualBasic assembly - but it can be used through C#.
Make this class:
public class SingleInstanceApplication : WindowsFormsApplicationBase
{
private SingleInstanceApplication()
{
IsSingleInstance = true;
}
public static void Run(Form form)
{
var app = new SingleInstanceApplication
{
MainForm = form
};
app.StartupNextInstance += (s, e) => e.BringToForeground = true;
app.Run(Environment.GetCommandLineArgs());
}
}
And in your Program.cs, change the run line to use it:
//Application.Run(new Form1());
SingleInstanceApplication.Run(new Form1());
You really need some sort of communications between 2 apps. In article link to you posted communications is through WinApi messages. Also you can do that through sockets or through files and FileWatchers.
UPD1:
Code to simulate minimize with timer simulation message from another app and maximize on that message:
public partial class Form1 : Form
{
private Timer _timer = null;
public Form1()
{
InitializeComponent();
this.Load += OnFormLoad;
}
private void OnFormLoad(object sender, EventArgs e)
{
Button btn = new Button();
btn.Text = "Hide and top most on timer";
btn.Width = 200;
btn.Click += OnButtonClick;
this.Controls.Add(btn);
}
private void OnButtonClick(object sender, EventArgs e)
{
//minimize app to task bar
WindowState = FormWindowState.Minimized;
//timer to simulate message from another app
_timer = new Timer();
//time after wich form will be maximize
_timer.Interval = 2000;
_timer.Tick += new EventHandler(OnTimerTick);
_timer.Start();
}
private void OnTimerTick(object sender, EventArgs e)
{
_timer.Stop();
//message from another app came - we should
WindowState = FormWindowState.Normal;
TopMost = true;
}
}

Problem with ShowDialog when ShowInTaskbar is false

Here is a small code that will illustrate my problem:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
timer1.Interval = 3000;
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
using (Form form = new Form())
{
form.ShowInTaskbar = false;
form.ShowDialog();
}
}
}
If I press button1 (which calls button1_Click) and then click on another application in the taskbar so that it comes to the top, and then after 5 secs I go back to my application, the created form won't be visible and I won't have a way to bring it back to the top, while my Form1 will be unresponsive because of having an invisible dialog on top.
What's a workaround for this?
Make your main form an owner of your modal box.
Form form = new Form();
form.Owner = this;
form.ShowInTaskbar = false;
form.ShowDialog();

Adding Form Closing Event In Code To Specific Object Instance?

Pretty simple what I want to do, just want to be able to run some code after a form is closed.
Form1 f = new Form1();
f.Show();
f.formClosing ... <- I just want to run code from this context once this form has been closed
{
Form1 f = new Form1();
f.FormClosed += new FormClosedEventHandler(f_FormClosed);
f.Show();
}
void f_FormClosed(object sender, FormClosedEventArgs e)
{
// Do stuff here
}
You can handle the Form.FormClosing event.
this.FormClosing += new FormClosingEventHandler(myForm_FormClosing);
void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
//your code here
}
Form.FormClosing occurs before the form is closed. If you cancel this event, the form remains opened.
The right event to handle is Form.FormClosed :
form.FormClosed +=
new Form.FormClosedEventHandler( Place the name of the handler method here ... );
Modern inline:
FormClosed += (s, a) => { /* your code here */ };
Recently I register my FORM exit handler this way (using .NET 4.8)
public partial class Form1:Form {
public Form1() {
this.FormClosed += Form1_Closing;
}
private void Form1_Closing(object sender, EventArgs e) {
//Doing something while exit
}
}

Categories

Resources