I have 2 forms connected to a database, LoadDocument form and a Fom1 that is the primary form. In LoadDocument I get document names out of my database, and when I close LoadDocument I send the document id to Form1 so I can retrieve its content there.
The only problem is that if i make a function in Form1, called public void showContent() my LoadDocument can't call it because it's not static, and if I make it static, I get problems creating radioButtons.
public partial class Form1 : Form
{
public void showTasks()
{
radioButtons = new RadioButton[numberOfTasks];
for (int i = 0; i < numberOfTasks; ++i)
{
radioButtons[i] = new RadioButton();
radioButtons[i].Text = "Task " + (i+1);
radioButtons[i].Location = new System.Drawing.Point(
10, 10 + i * 20);
groupBox1.Controls.Add(radioButtons[i]);
radioButtons[i].Click += new EventHandler(this.radioButtons_Click);
}
}
}
Is there any way I can call this function from LoadDocument without making it static? Do I have to make LoadDocument dynamic, and in that case how?
EDIT: I guess this piece of code would be quite relevant:
private LoadDocument m_form1;
private bool m_underConstruction = false;
private void ShowLoadDocument()
{
if (m_underConstruction)
{
// We're about to show it anyway
return;
}
m_underConstruction = true;
try
{
if (m_form1 == null)
{
m_form1 = new LoadDocument();
// m_form1.FormClosed += new FormClosedEventHandler(m_form1_FormClosed);
m_form1.Show();
}
}
finally
{
m_underConstruction = false;
}
m_form1.BringToFront();
m_form1.Activate();
}
I'm not sure about the control flow and the co-existence of the two forms, but you could pass the instance of Form1 to LoadDocument and call the method directly on that object. Like:
public class LoadDocument : Form {
private Form1 form1;
public LoadDocument(Form1 form1) {
this.form1 = form1;
}
// later
public void Method() {
form1.showTasks();
}
}
public class Form1 : Form {
public void SomeMethod() {
LoadDocument doc = new LoadDocument(this);
doc.Show();
}
}
You don't need to make it static, but you need to have a reference to Form1 to call it. You can pass this reference to the constructor of LoadDocument when you create it:
public class Form1 : Form
{
...
LoadDocument loadDocument = new LoadDocument(this);
loadDocument.ShowDialog();
...
}
public class LoadDocument : Form
{
private readonly Form1 _form1;
public LoadDocument(Form1 form1)
{
_form1 = form1;
InitializeComponent();
}
...
_form1.showTasks();
...
}
You can call the showContent method on an instance of Form1.
I understand that the LoadDocument form is created from Form1. Pass the instance of Form1 to the LoadDocument constructor. That way, you'll be able to do form1WhoCreatedMe.ShowContent() somewhere in LoadDocument.
The dynamic keyword won't help you there. dynamic is not the contrary of static.
Related
i have a WinForms app that consists of several forms.
What I'm trying to achieve is to pass an event handler from a second form, to a third one, but i cannot achieve that. i get a casting error which i can't figure out how to overcome.
i would appreciate the help:
code + further explanation below:
This is a rough image of what is supposed to happen:
Form1 can create several forms (it also holds the methods that i want to pass) - which i can pass successfully on sub form creation.
the problem starts when i create form3 from within form2: i try to pass the event handler, but i get Error CS0029/CS0030 (casting errors)
what am i doing wrong and how to fix it?
EDIT:
what needs to happen? -- Form3 needs to control (send back data) to a Gui control placed in Form1
Code:
Form1:
public delegate void sendMessageToConsoleDelegate(string value);
public sendMessageToConsoleDelegate sendMessageToConsoleCallback;
public delegate void SetPlaceHolderDelegate(TextBox tb);
public SetPlaceHolderDelegate SetPlaceHolderCallback;
private void SetPlaceHolder(TextBox tb)
{
if (!tb.InvokeRequired)
{
if (!tb.Focused)
{
if (string.IsNullOrWhiteSpace(tb.Text))
tb.Text = tb.Tag.ToString();
return;
}
if (tb.Text == tb.Tag.ToString())
tb.Text = "";
return;
}
SetPlaceHolderDelegate call = new SetPlaceHolderDelegate(SetPlaceHolder);
tb.BeginInvoke(call, tb);
}
private void SendMessageToConsole(string msg)
{
if (!textBoxConsole.InvokeRequired)
{
textBoxConsole.AppendText(msg);
return;
}
sendMessageToConsoleDelegate call = new sendMessageToConsoleDelegate(SendMessageToConsole);
textBoxConsole.BeginInvoke(call, msg);
}
private void AddNewDeviceForm()
{
frmAddDevice add_device = new frmAddDevice(devicesDBPath);
add_device.sendMessageToConsole += SendMessageToConsole;
add_device.Show();
}
private void StartEdit()
{
frmEditDBs editdb = new frmEditDBs(devicesDBPath, commandsDBPath);
editdb.sendMessageToConsole += SendMessageToConsole;
editdb.SetPlaceHolder += SetPlaceHolder;
editdb.Show();
}
Form2 (frmEditDBs)
public delegate void EventHandler_sendMessageToConsole(string msg);
public event EventHandler_sendMessageToConsole sendMessageToConsole = delegate { };
public delegate void EventHandler_SetPlaceHolder(TextBox tb);
public event EventHandler_SetPlaceHolder SetPlaceHolder = delegate { };
private void EditDevice()
{
frmAddDevice edit_device = new frmAddDevice(devicesDBpath, current_device);
edit_device.sendMessageToConsole += sendMessageToConsole; ****<== This is the issue (same for the placeholder)****
edit_device.Show();
}
i get error CS0029
how can i pass the same delegate to other sub forms (e.g. frmAddDevice)?
Your question is how to C# pass delegates to different forms so that you can (for example) sendMessageToConsole to your MainForm from the other forms. In your code you state that this is the problem:
// This is the issue (same for the placeholder)****
edit_device.sendMessageToConsole += sendMessageToConsole;
When I look at your code, in essence you are trying to implement your own version of an Event Pattern. One solution to your issue would be to use a standard event pattern. Then intellisense will recognize your custom event delegate in the standard way:
FIRST you need to make the delegate and the inherited EventArgs class outside of your MainForm class:
namespace pass_delegates
{
public partial class MainForm : Form
{
}
// Make sure these are outside of any other class.
public delegate void SendMessageToConsoleEventHandler(object sender, SendMessageToConsoleEventArgs e);
public class SendMessageToConsoleEventArgs : EventArgs
{
public string Message { get; }
public SendMessageToConsoleEventArgs(string message)
{
Message = message;
}
}
}
Your frmAddDevice (shown here in minimal format) declares the delegate using the event keyword. Your other form frmEditDBs does exactly the same thing.
public partial class frmAddDevice : Form
{
public event SendMessageToConsoleEventHandler SendMessageToConsole;
public frmAddDevice(string devicesDBpath)
{
InitializeComponent();
}
protected virtual void OnSendMessageToConsole(SendMessageToConsoleEventArgs e)
{
SendMessageToConsole?.Invoke(this, e);
}
// Clicking the button will call this as a test.
private void btnSendTestMessage_Click(object sender, EventArgs e)
{
OnSendMessageToConsole(new SendMessageToConsoleEventArgs("Message received from 'Add Device Form'"));
}
}
A button in the MainForm code creates a new frmAddDevice like this:
frmAddDevice frmAddDevice = null;
// This handler in the Main Form creates the frmAddDevice form
private void btnFrmAddDevice_Click(object sender, EventArgs e)
{
if (frmAddDevice == null)
{
frmAddDevice = new frmAddDevice(devicesDBpath: "Some path");
// This was the problem. Not anymore ****
frmAddDevice.SendMessageToConsole += outputMessageToConsole;
}
frmAddDevice.Show();
}
private void outputMessageToConsole(object sender, SendMessageToConsoleEventArgs e)
{
textBoxConsole.AppendText(e.Message + Environment.NewLine);
}
If you do these things, you will achieve the functionality of sendMessageToConsole that your code is attempting to do. Try it out by downloading my sample from GitHub.
I think the main concept you don't understand is that delegate is "same level" as class, enum, struct etc. You need to declare it in some shared scope to make it accessible in both forms.
namespace ConsoleApp6
{
public delegate void TestDelegate();
public class ClassA
{
public TestDelegate delegateA;
}
public class ClassB
{
public TestDelegate delegateB;
}
internal class Program
{
static void Main(string[] args)
{
TestDelegate del = () => { };
var classA = new ClassA()
{
delegateA = del,
};
var classB = new ClassB()
{
delegateB = classA.delegateA
};
}
}
}
Or, if you want to keep it inside of the form, you need reference it by a class name the same way you would do with a type.
namespace ConsoleApp6
{
public class ClassA
{
public delegate void TestDelegate();
public TestDelegate delegateA;
}
public class ClassB
{
public ClassA.TestDelegate delegateB;
}
internal class Program
{
static void Main(string[] args)
{
ClassA.TestDelegate del = () => { };
var classA = new ClassA()
{
delegateA = del,
};
var classB = new ClassB()
{
delegateB = classA.delegateA
};
}
}
}
As was described previously, your "delegates" should be declared generically at the namespace of your project, not within a specific class so they are visible throughout your app. To do so, maybe make a separate file in your project for "MyDelegates" and may look something like:
using System.Windows.Forms;
namespace WinHelp1
{
// Create your own delegates outside of your classes that need to be publicly
// visible within your app or even protected if so needed.
public delegate void EventHandler_SendMessageToConsole(string msg);
public delegate void EventHandler_SetPlaceHolder(TextBox tb);
}
Now, in your form 1 that you want to define WHAT to do, do so based on the signatures matching appropriately
using System.Windows.Forms;
namespace WinHelp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void DoThisForConsole(string msg)
{
// whatever to do with string
}
public void DoThisForTextBox(TextBox tb)
{
// whatever to do with textbox
}
private void Btn2_Click(object sender, System.EventArgs e)
{
var f2 = new Form2();
f2.SendMessageToConsole += DoThisForConsole;
f2.SetPlaceHolder += DoThisForTextBox;
f2.ShowDialog();
// OR, if using the PARAMETERIZED for pass-through to call
// when form2 calls form 3
var f2b = new Form2( DoThisForConsole, DoThisForTextBox );
f2b.ShowDialog();
}
private void Btn3_Click(object sender, System.EventArgs e)
{
var f3 = new Form3();
f3.SendMessageToConsole += DoThisForConsole;
f3.SetPlaceHolder += DoThisForTextBox;
f3.ShowDialog();
}
}
}
First, form3 since that will just have the direct event handlers, and you can invoke however within form 3
using System.Windows.Forms;
namespace WinHelp1
{
public partial class Form3 : Form
{
// now, for each form you want to USE them on...
public event EventHandler_SendMessageToConsole SendMessageToConsole;
public event EventHandler_SetPlaceHolder SetPlaceHolder;
public Form3()
{
InitializeComponent();
}
}
}
Now, in your form 2, is a bit different. Since you want to make available for form2 to call form3 with the same event handler, just add those event handlers as parameters to the constructor class. Then you can preserve them in that form, but at the same time, self-register them as in the var f2b = new Form2 of the second button click event. Then use those preserved values when form2 needs to call form3
using System.Windows.Forms;
namespace WinHelp1
{
public partial class Form2 : Form
{
// now, for each form you want to USE them on...
public event EventHandler_SendMessageToConsole SendMessageToConsole;
public event EventHandler_SetPlaceHolder SetPlaceHolder;
// now, for each form you want to USE them on...
public EventHandler_SendMessageToConsole passThroughForMessage;
public EventHandler_SetPlaceHolder passThroughForTextBox;
public Form2()
{
InitializeComponent();
}
public Form2(EventHandler_SendMessageToConsole forSendMsg, EventHandler_SetPlaceHolder forPlaceHolder ) : this()
{
// preserve into properties in-case you need to call form 3
passThroughForMessage = forSendMsg;
passThroughForTextBox = forPlaceHolder;
// and the constructor can auto-set for itself so IT can notify as well
if( forSendMsg != null )
SendMessageToConsole += forSendMsg;
if( forPlaceHolder != null )
SetPlaceHolder += forPlaceHolder;
}
private void Btn3_Click(object sender, System.EventArgs e)
{
var f3 = new Form3();
// and the constructor can auto-set for itself so IT can notify as well
if (passThroughForMessage != null)
f3.SendMessageToConsole += passThroughForMessage;
if (passThroughForTextBox != null)
f3.SetPlaceHolder += passThroughForTextBox;
f3.ShowDialog();
}
}
}
Remember, parameters can be practically anything, and you can have a variable stored in a property just like anything else... as long as it matches the respective type.
Then, from form3, either instance will invoke back to whatever the root instance method may be.
First I know there are already answer for this question but most solution seems complicated for nothing.
Situation :
I have a form called frm1. I want to pass it as parameter
myfunc(ref frm1)
I would then do
private void myfunc(ref Form frm1)
It says : frm1 is a type but is used as a variable.
My reason for doing this is because depending on choice I pass my form to one of either two functions which fills it differently.
Problem :
However I cannot pass as argument my form. However I can pass other controls like button in the same way. How can I do this simply with the form, without interface etc...
There is something wrong with the way you are passing the parameter in. Are you definitely passing in the instance and not the type?
Here's a working example.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Name = "form";
Form f = this;
doSomethingWithForm(f);
}
private void doSomethingWithForm(Form f)
{
Console.WriteLine(f.Name);
}
}
I have created one function. I think it will help you. I am using this in my practice.
-->function below:
public void showForm(Form _form, Form _main) {
if (_main != null)
{
if (_main.ActiveMdiChild != null)
{
_main.ActiveMdiChild.Close();
}
_form.MdiParent = _main;
_form.Activate();
_form.Show();
}
else
{
_form.Activate();
_form.ShowDialog();
}
-->how to use it:
objLib.showForm(new frmMain(), null);
OR
objLib.showForm(new frmNewspaper(), this);
Thank You
I will add to kenjara's answer.
// For example: change color of the form - from some other method
private void Form_Load(object sender, EventArgs e)
{
ChS = new ChangeSomething();
ChS.ChangeBackColor(this);
}
public class ChangeSomething
{
public void ChangeBackColor(Form form)
{
form.BackColor = System.Drawing.Color.Black;
return;
}
}
Tested VS2022 / .NET4.8 / Windows Forms
Form1.cs
public String Return_inf()
{
names = U_name.Text;
return names;
}
And i try to store it in another class string variable like :
public string CheckLogin()
{
Form1 f = new Form1();
string name=f.Return_inf();
}
But the variable is empty ....
The reason your variable name is empty is because you are creating a brand new Form1 object in your CheckLogin() method, instead of using an already existing Form1 object.
You could have your classes have references to one another.
Here is one example you could try by having the forms have references to one another
Form1 class:
public class Form1 : Form
{
// Class variable to have a reference to Form2
private Form2 form2;
// Constructor
public Form1()
{
// InitializeComponent is a default method created for you to intialize all the controls on your form.
InitializeComponent();
form2 = new Form2(this);
}
public String Return_inf()
{
names = U_name.Text;
return names;
}
}
Form2 class:
public class Form2 : Form
{
// Class variable to have a reference back to Form1
private Form1 form1;
public Form2(Form1 form1)
{
InitializeComponent();
this.form1 = form1;
}
public string CheckLogin()
{
// There is no need to create a Form1 object here in the method, because this class already knows about Form1 from the constructor
string name=form1.Return_inf();
// Use name how you would like
}
}
There are other ways of doing this, but IMO this would be the basics of sharing data between two forms.
you can do it by defining static class like this
static class GlobalClass
{
private static string U_name= "";
public static string U_name
{
get { return U_name; }
set { U_name= value; }
}
}
and you can use it as follow
GlobalClass.U_name="any thing";
and then recall it like this
string name=GlobalClass.U_name;
Im trying to set LabelStatus's text to a message in the class but it doesn't work.
Here's my code:
Class:
public bool openConnection()
{
SetStatus("Connecting to " + Server);
//Mysql code
}
private void SetStatus(string msg)
{
Form1 form = new Form1();
form.SetStatus(msg);
}
Form1:
public void SetStatus(string status)
{
labelStatus.Text = _status;
}
I'm fairly new to C# (php guy) and for the life of me can't figure out what I am doing wrong
Try calling the ShowDialog or Show Method on your form
private void SetStatus(string msg)
{
Form1 form = new Form1();
form.SetStatus(msg);
form.ShowDialog(this);
}
looks like you are setting the member variable and not the function's parameter.
//try something like this
this._status = status;
this.labelStatus.Text = this._status;
When setting labelStatus.Text, you're not setting it with the parameter you passed to SetStatus(string). It seems like you accidentally used a data member instead.
Look at the names : try to make them same, see
labelStatus.Text = **status**;
From your code, I think your class is change the status label of form label. To change form label text you need object of already opened form. define variable for form in your class.
public class ConnectionCheck
{
private Form myForm;
public void ConnectionCheck(Form form)
{
myForm = form;
}
public bool openConnection()
{
SetStatus("Connecting to " + Server);
//Mysql code
}
private void SetStatus(string msg)
{
//Call method to change label text
myForm .SetStatus(msg);
}
}
Pass form1 object at the time of ConnectionCheck object creation from from1 codebehind(form1.cs).
ConnectionCheck connection = new ConnectionCheck(this);
And Also, change _status to parameter variable.
public void SetStatus(string status)
{
labelStatus.Text = status;
}
I want to create a custom message box for a program so I added a windows form item. I would like it to behave like MessageBox in that it is static and I just call MessageBox.Show(a, b, c, ...). In the forms designer, however, I don't see how I can make it static. Can I just add static to the code? Is there a property setting I'm missing in the designer mode?
Thanks!
MessageBox is not a static class, the Show method however is. Make Show static, in code. E.g.
public class MyMessageBox : Form
{
public static int MyShow()
{
// create instance of your custom message box form
// show it
// return result
}
}
It is a regular class with one method as static which instantiate new instance and act.
public class MyMessageBox
{
public static MyResult Show(params)
{
var myMessageBox = new MyMessageBox();
myMessageBox.Message = params ...
return myMessageBox.ShowDialog();
}
}
Add a static method to your form that displays itself and returns a DialogResult:
public partial class MyMessageBoxForm : Form {
public static DialogResult Show(string message) {
using (MyMessageBoxForm form = new MyMessageBoxForm(message)) {
return form.ShowDialog();
}
private MyMessageBoxForm(string message) {
// do something with message
}
}
If you want create static Form1 for access to it without object reference, you can change Program.cs:
public class Program
{
public static Form1 YourForm;
[STAThread]
static void Main(string[] args)
{
using (Form1 mainForm = new Form1())
{
YourForm = mainForm;
Application.Run(mainForm);
}
YourForm = null;
}
}
and call Form1 class methods from any place of your program:
Program.YouForm.DoAnything();
Do not forget to call Invoke for access from other threads.