Can we add the some functions to a winform at runtime? - c#

I have a main parent winform in which I have implemented some features and that have a number of child windows. Now I want the functionality I have implemented to run also on the child windows.
For instance, in the parent window I am moving an image on the selection of a checkbox. Now, if this checkbox is checked then the image should also move on the all other child windows.
Note: The image moving on the parent window should disapper and should only show on the opend dialogue or child window.
Please suggest if it is possible.

Try using events.
Create an event for the parent form called ImageMoved.
The child forms should subscribe to this event, and when you move the image, you raise the event, then the child forms will know to do their thing.
Lots of different ways to do this. Simple example:
public partial class Form1 : Form {
public event EventHandler ImageMoved;
private void OnImageMoved() {
if (ImageMoved != null)
ImageMoved(this, new EventArgs());
}
private void button1_Click(object sender, EventArgs e) {
OnImageMoved();
}
private void button2_Click(object sender, EventArgs e) {
Form2 f2 = new Form2(this);
f2.Show();
}
}
Then your child forms could look something like this:
public partial class Form2 : Form {
public Form2(Form1 parentForm) {
InitializeComponent();
parentForm.ImageMoved += new EventHandler(parentForm_ImageMoved);
}
void parentForm_ImageMoved(object sender, EventArgs e) {
MessageBox.Show("Image moved");
}
}
You could also create your own EventArgs class if you want to pass more information, such as which image, etc.

Related

c# execute a method from Form in the MainForm [duplicate]

I am working with windowsFrom in c#. I am trying to call mainfrom method in one of the from in user control.
I have mainfrom like this
namespace Project
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
public void TempCommand()
{
StartTemp();
}
}
}
I have the button click in the user control. When i click that button then it will open another form. I have the code like this in the user control.
private TempCalib _tempCalib = new TempCalib();
private void calibBtn_Click(object sender, EventArgs e)
{
_tempCalib.Show();
}
it will open another from and i have one button in that from. I need to call mainfrom method when i click "Ok" button in this from.
namespace Project
{
public partial class TempCalib : Form
{
public TempCalib()
{
InitializeComponent();
}
private void OkButton_Click(object sender, EventArgs e)
{
// I need to call the mainfrom "TempCommand" method here.
this.Hide();
}
}
}
Can anyone help me how to do this.
Thanks.
Quick answer
Just add a reference to the primary form in your secondary form:
public partial class TempCalib : Form
{
private MainForm _main
public TempCalib(MainForm main) : this()
{
_main = main;
}
/// Other stuffs
}
Then assign value when you construct your secondary form:
private TempCalib _tempCalib;
private void calibBtn_Click(object sender, EventArgs e)
{
if (_tempCalib == null)
_tempCalib = new TempCalib(this);
_tempCalib.Show();
}
If calibBtn_Click isn't inside MainForm (but it's inside a UserControl on it) then you can replace _tempCalib initialization with:
_tempCalib = new TempCalib((MainWindow)FindForm());
You'll be then able to call the primary form:
private void OkButton_Click(object sender, EventArgs e)
{
_main.TempCommand();
this.Hide();
}
Notes: this is just one option, you may create a property to hold MainForm reference (so secondary form can be reused and it'll be more designer friendly) moreover TempCalib is not an UserControl but a Form (pretty raw but for an UserControl you may just check its parent Form and cast it to proper type).
Improvements
Such kind of references are often an alert. Usually UI components shouldn't not be so coupled and a public Form's method to perform something very often is the signal that you have too much logic in your Form. How to improve this?
1. DECOUPLE CONTROLS. Well a first step may be to decouple them a little bit, just add an event in TempCalib and make MainForm its receiver:
public partial class TempCalib : Form
{
public event EventHandler SomethingMustBeDone;
private void OkButton_Click(object sender, EventArgs e)
{
OnSomethingMustBeDone(EventArgs.Empty); / TO DO
this.Hide();
}
}
Then in MainForm:
private TempCalib _tempCalib;
private void calibBtn_Click(object sender, EventArgs e)
{
if (_tempCalib == null)
{
_tempCalib = new TempCalib();
_tempCalib.SomethingMustBeDone += _tempCalib_SomethingMustBeDone;
// In _tempCalib_SomethingMustBeDone you'll invoke proper member
// and possibly hide _tempCalib (remove it from OkButton_Click)
}
_tempCalib.Show();
}
2. DECOUPLE LOGIC FROM CONTROLS. UI changes pretty often, logic not (and when it changes probably isn't in parallel with UI). This is just the first step (now TempCalib isn't aware of who will use it). Next step (to be performed when too much things happen inside your form) is to remove this kind of logic from the form itself. Little example (very raw), keep TempCalib as before (with the event) and change MainForm to be passive:
public partial class MainForm : Form
{
public event EventHandler Calibrate;
protected virtual void OnCalibrate(EventArgs e)
{
// TODO
}
}
Now let's create a class to control the flow and logic:
public class MyTaskController
{
private MainForm _main;
private TempCalib _tempCalib;
public void Start()
{
_main = new MainForm();
_main.Calibrate += OnCalibrationRequested;
_main.Show(); // Or whatever else
}
private void OnCalibrationRequested(object sender, EventArgs e)
{
if (_tempCalib == null)
{
_tempCalib = new TempCalib();
_tempCalib.SomethingMustBeDone += OnSomethingMustBeDone();
}
_tempCalib.Show();
}
private OnSomethingMustBeDone(object sender, EventArgs e)
{
// Perform the task here then hide calibration window
_tempCalib.Hide();
}
}
Yes, you'll need to write much more code but this will decouple logic (what to do as response to an action, for example) from UI itself. When program grows up this will help you to change UI as needed keeping logic unaware of that (and in one well defined place). I don't even mention that this will allow you to use different resources (people) to write logic and UI (or to reuse logic for different UI, WinForms and WPF, for example). Anyway IMO the most obvious and well repaid benefit is...readability: you'll always know where logic is and where UI management is, no search, no confusion, no mistakes.
3. DECOUPLE LOGIC FROM IMPLEMENTATION. Again you have more steps to perform (when needed). Your controller is still aware of concrete types (MainForm and TempCalib). In case you need to select a different form at run-time (for example to have a complex interface and a simplified one or to use dependency injection) then you have to decouple controller using interfaces. Just an example:
public interface IUiWindow
{
void Show();
void Hide();
}
public interface IMainWindow : IUiWindow
{
event EventHandler Calibrate;
}
public interface ICalibrationWindow : IUiWindow
{
event EventHandler SomethingMustBeDone;
}
You could use a custom event that is declared in your UserControl. Then your form needs to handle this event and call the method you want to call. If you let the UserControl access your form, you are hard-linking both with each other which decreases reusability of your UserControl.
For example, in TempCalib:
public delegate void OkClickedHandler(object sender, EventArgs e);
public event OkClickedHandler OkClicked;
private void OkButton_Click(object sender, EventArgs e)
{
// Make sure someone is listening to event
if (OkClicked == null) return;
OkClicked(sender, e);
this.Hide();
}
in your mainform:
private void Mainform_Load(object sender, EventArgs e)
{
_tempCalib.OkClicked += CalibOkClicked;
}
private void CalibOkClicked(Object sender, EventArgs e)
{
StartTemp();
}
You create an event in your usercontrol and subscribe to this in the mainform.
That is the usual way.
Form1 Code:
UserControl1 myusercontrol = new UserControl1();
public void TabClose(Object sender,EventArgs e)
{
int i = 0;
i = tabControl1.SelectedIndex;
tabControl1.TabPages.RemoveAt(i);
}
private void Form1_Load(object sender, EventArgs e)
{
myusercontrol.Dock = DockStyle.Fill;
TabPage myTabPage = new TabPage();
myTabPage.Text = "Student";
myTabPage.Controls.Add(myusercontrol);
tabControl1.TabPages.Add(myTabPage);
myusercontrol.OkClick += TabClose;
}
UserControl1 Code:
public delegate void OkClickedHandler(Object sender, EventArgs e);
public partial class UserControl1 : UserControl
{
public event OkClickedHandler OkClick;
public UserControl1()
{
InitializeComponent();
}
private void button3_Click(object sender, EventArgs e)
{
if (OkClick == null) return;
OkClick(sender, e);
}
}
Try this:
From user control try this:
MainForm form = this.TopLevelControl as MainForm;
form.TempCommand();

When Form1 loads, hide it and show Form2

Been stuck for quite a while reading similar posts here, I did find a solution but it was in dummy code and I just don't know what I'm doing wrong.
I have 2 forms, when the main form loads up I want to hide it and show form2 (the login form)
code looks like this.
private void Form1_Load(object sender, EventArgs e)
{
login loginform = new login();
loginform.Show();
this.Hide();
}
But when I run the program both forms are open and visible.
What am I doing wrong? Shouldn't the main form be hidden?
The Hide method does not have any effect from the Load event, since there isn't a handle created yet.
You have two options:
Using the Shown event (or better, the HandleCreated event) and hide it if a condition is met (like a variable 'logon form not shown')
Show the logon form as start form, then open the 'main' form. You can do this by passing an ApplicationContext around and pass on control to the main form.
You can do it with help of owner property, here is working example
Main form
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var loginFormMax = new LoginFormMax { Owner = this };//save main form as owner inside child form
loginFormMax.Show();
}
}
Child Form
public partial class LoginFormMax : Form
{
public LoginFormMax()
{
InitializeComponent();
}
private void LoginFormMax_Shown(object sender, EventArgs e)
{
var owner = this.Owner;
owner.Hide();//now you have control over owner form, just hide it
}
private void LoginFormMax_FormClosing(object sender, FormClosingEventArgs e)
{
var owner = this.Owner;
owner.Show();//now you have control over owner form, just show it again
}
}

How to come back to parent form without creating new instance of parent class in C# windows application

How to come back to parent form without creating new instance of parent form in C# windows application?
I have tried this.Parent, this.MdiParent, this.MyParentForms but no one worked..
You can have a button in your parent form that is used to show another form. Add this code to the button's Click event:
//Click event of your button.
private void goToSecondForm_Click(object sender, EventArgs e)
{
this.Hide(); //Hides the parent form.
subform.ShowDialog(); //Shows the sub form.
this.Show(); //Shows the parent form again, after closing the sub form.
}
In your child form, add a public property with type of your parent form :
public class ChildForm:From
{
public ParentForm parent;
//...
}
Then, in your click event of showing child form, do this :
private void goToSecondForm_Click(object sender, EventArgs e)
{
this.Hide();
ChildForm child = new ChildForm();
child.parent = this;
//other stuff
child.Show();
}
At the end, in the FormClosing event of the child form, doing this :
private void Child_FormClosing(object sender, FormClosingEventArgs e)
{
this.parent.Show();
}
With this solution, if your parent form changes or updates, then you have the latest instance.

Need an event to fire when a Form in an MDI container closes?

I have a Multi Document Interface control with some Forms nested inside of it. I need an event to fire when one of those forms are closed. How may I bind such an event?
If it matters, the code I need to run accesses a global class called data, which has a public static property called Windows, which is accessed like so:
data.Windows -= 1;
It is indeed as L.B says: Create an override in the form class. It can be placed anywhere in the class
protected override void OnClosing(CancelEventArgs e)
data.Windows = -1; //assuming this variable still exists at that time
}
Here is your answer:
private void Form1_MdiChildActivate(object sender, EventArgs e)
{
//form is new mdi child
Form form = this.MdiChildren.Last();
form.FormClosed += SenderForm_Close;
}
private void SenderForm_Close(object sender, EventArgs e)
{
//form is new closed mdi child
Form form = sender as Form;
}

c# run a Form then show another form over it with showDialog?

I want to run my form (with all controls disabled)
and over it there will be another form for username and password run as showDialog!
people will not be able to go to the main form without login!
private void Form1_Load(object sender, EventArgs e)
{
this.Show();
Form2 f2 = new Form2 ();
f2.ShowDialog();
}
I tried the code above and it dose not work as it should!
how I can achieve it the way I need?
cheers
From the parent form:
childForm.ShowDialog(this);
That will make the child form modal to the parent form. As far as the location goes, there is a property off of the form (that you will want to set on the child form) that tells it where to start (center screen, center parent, etc)
System.Windows.Forms.Form implements IWin32Window, this is why it works.
It isn't clear what the issue/question is, but you could try making sure you pass in the parent-form, i.e.
using(var childForm = new MySpecialLoginForm(...)) {
childForm.ShowDialog(this);
}
erm...
DialogResult result = mySecondForm.ShowDialog()
That will disable the parent form until this one is closed. DialogResult will be an enum value that is something like OK/Cancel/YesNo etc
I typically use the following pattern if I want to do sth. after the Form has fully loaded:
public partial class BaseForm : Form
{
public event EventHandler Loaded;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Application.Idle += OnLoaded;
}
protected void OnLoaded(object sender, EventArgs e)
{
Application.Idle -= OnLoaded;
if (Loaded != null)
{
Loaded(sender, e);
}
}
}
If I derive my main form from BaseForm I have a Loaded event which, in your case, I would use as follows.
static class Program
{
[STAThread]
static void Main()
{
var mainForm = new MainForm();
mainForm.Loaded += (sender, e) => { new LoginDialog().ShowDialog(mainForm); };
Application.Run(mainForm);
}
}

Categories