Using a control from the main form on subforms - c#

My main form contains a TextBox control that will be used throughout the application as a notepad-like feature.
Some of the subforms that are called from the main form will share the Text property of the main form's TextBox, which will not be visible - only the ones in the subforms will.
I'm using an extended Form for each subform, and they are being called using ShowDialog().
What's the best way to "share" this text between all subforms and the main form?
Please forgive my broken English.

You can create a class having a public static property which points to some function, then use this property as method on other forms. You should initialize this property on the initialization of your main form.
E.g.
public class Utility
{
public static Action<string> SetNotePadValue
{
get;
set;
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Utility.SetNotePadValue = (s) =>
{
// textBox1 is a control on this form
this.textBox1.AppendText(s + "\r\n");
};
}
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// this will set value in Form1's textBox1
Utility.SetNotePadValue("Some text");
}
}

What you're looking to do here is to create a new event on your form:
public class Form2 : Form
{
public event Action<string> TextChanged; //TODO consider renaming
private void button1_Click(object sender, EventArgs e)
{
var handler = TextChanged;
if(handler != null)
handler(textbox.Text);
}
}
The main form can then subscribe to this event when creating the form:
Form2 popup = new Form2();
popup.TextChanged += text => DoSomethingWithText(text);
popup.ShowDialog();

Related

Forms Communication

I have 2 forms which consist of:
Form1:
2buttons named:
btnCopy and
btnPaste
(with functions inside like rtb.Copy(); and rtb.Paste(); that should work for richtextbox in Form2)
Form2:
1richtextbox named: rtb
My question was:
How can I communicate between the 2buttons from Form1 (with its functions) and the richtextbox in Form2.
like: When I type text inside richtextbox(rtb) in Form2 then i SelectAll text then I Press the CopyButton(btnCopy) from Form1, text should be copied same as when I Press PasteButton(btnPaste) from Form1, text that has been copied should be Paste in RichTextBox(rtb) that could be Found on Form2 .
How can I do that?
Let's say you have Form1 and ToolStrip Button name PasteToolStripButton like:
public partial class Form1 : Form
{
Form2 formChild;
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
}
void Form1_Load(object sender, EventArgs e)
{
formChild = new Form2();
formChild.MdiParent = this;
formChild.Show();
}
private void CopyToolStripButton_Click(object sender, EventArgs e)
{
formChild.CopyText(); // Method to copy Rich Text Box in Form2
}
private void PasteToolStripButton_Click(object sender, EventArgs e)
{
formChild.PasteText(); // Method in Form2 to Paste to the RichTextBox in Form2
}
}
In your Form2 you need to add a Public method named PasteText and CopyText like:
public void PasteText()
{
rtbChild.Text = Clipboard.GetText(); // this one simulates the rtb.Paste()
}
public void CopyText()
{
rtb.Copy();
}
I also named the RichTextBox in Form2 as rtbChild so every time you click for example paste in will be copied in your RichTextBox in Form2.
Create a public property on Form1 then set it from Form2.
EDIT:
On Form1:
public string TextForRTB {get; set;}
On Form2:
Form1 a = new Form1();
a.TextForRtb = rtb.Text;
Sol1: Pass one of the forms to the other, as Form1(Form parent){....} in the constructor, then you should see it's public properties and methods.
Sol2: Create custom events to raise it when text changed on your rich text box, so than the forms that initialized the form with this rich box will do something, like enable/disable a button or something
...Actually, there is a lot of solutions to this kind of behavior, and I wonder why you need to put your text box in a different form from your buttons that seems to be related very closely in business logic together!
You could expose 2 methods GetRichTextBoxContent and SetRichTextBoxContent in Form2.
Which would update the contents of richTextBox in Form2.
Then you could work on the Instance of Form2 form Form1
Note: The major think here is how you get the Instance of Form2. It is up to your implementation to get that instance.
public class Form2 : Form
{
public string GetRichTextBoxContent()
{
return this.richTextBox1.Text;
}
public void SetRichTextBoxContent(string content)
{
this.richTextBox1.Text = content;
}
}
public class Form1 : Form
{
//Based on your implementation
Form2 form2 = new Form2();
private void Button_CopyClick(object sender, EventArgs e)
{
var contentFromRtb = form2.GetRichTextBoxContent();
}
private void Button_PasteClick(object sender, EventArgs e)
{
var someContent = "Content to be copied to text box"
form2.SetRichTextBoxContent(someContent );
}
}

How to access Parent class function/control from a child user control loaded in a pannel

I have Main Form which contains a Panel which loads different Usercontrol into the panel.
Now i need to access functions in the Main Form from the UserControl.
Below i have given my code;
This is my main Windows form class:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
loadlogin();
}
private void loadlogin()
{
login log = new login();
mainPannel.Controls.Clear();
mainPannel.Controls.Add(log);
}
public void mytest()
{
}
}
As you can see i am loading a usercontrol to the mainPannel.
Now lets look at the usercontrol:
public partial class login : UserControl
{
string MyConString = "";
public login()
{
InitializeComponent();
}
public void button1_Click_1(object sender, EventArgs e)
{
//I want to call the parent function mytest(); HOW????
}
}
I want to access mytest() function when button1 us clicked. I have tried alot of other solution but i am still confused.
I have used:
Form my = this.FindForm();
my.Text = "asdasfasf";
This gives me reference to parent and i can change the form text but how can i access its functions???
Ok, the above answer will work but it is not good coding practice to pass in a "Parent Form" to a user control. UserControls should be located in a separate project from your forms project and your forms project should reference your control project in order to gain visiblity to them. Lets say for instance that you want this UserControl to be nested in another UserControl at some point. Your code no longer works without overloading the constructor. The better solution would be to use an event. I have provided an implementation using a CustomEventArg. By doing this, your login UserControl can sit on anything and still work. If the functionality to change the parents text is not requried, simply do not register with the event. Here is the code, hope this helps someone.
Here is the form code:
public Form1()
{
InitializeComponent();
loadlogin();
}
private void loadlogin()
{
login log = new login();
//Registers the UserControl event
log.changeParentTextWithCustomEvent += new EventHandler<TextChangedEventArgs>(log_changeParentTextWithCustomEvent);
mainPannel.Controls.Clear();
mainPannel.Controls.Add(log);
}
private void log_changeParentTextWithCustomEvent(object sender, TextChangedEventArgs e)
{
this.Text = e.Text;
}
Here is the "login" UserControl code (in my test solution, just a userControl with a button)
public partial class login : UserControl
{
//Declare Event with CustomArgs
public event EventHandler<TextChangedEventArgs> changeParentTextWithCustomEvent;
private String customEventText = "Custom Events FTW!!!";
public login()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Check to see if the event is registered...
//If not then do not fire event
if (changeParentTextWithCustomEvent != null)
{
changeParentTextWithCustomEvent(sender, new TextChangedEventArgs(customEventText));
}
}
}
And finally, the CustomEventArgs class:
public class TextChangedEventArgs : EventArgs
{
private String text;
//Did not implement a "Set" so that the only way to give it the Text value is in the constructor
public String Text
{
get { return text; }
}
public TextChangedEventArgs(String theText)
: base()
{
text = theText;
}
}
Writing your controls in this fashion, with no visibility to Forms will allow your UserControls to be completely reusable and not bound to any type or kind of parent. Simply define the behaviors a UserControl can trigger and register them when necessary. I know this is an old post but hopefully this will help someone write better UserControls.
This may helps:
public partial class Form1 : Form
{
//Other codes
private void loadlogin()
{
login log = new login(this); //CHANGE HERE
mainPannel.Controls.Clear();
mainPannel.Controls.Add(log);
}
//Other codes
}
And
public partial class login : UserControl
{
Form1 _parent; //ADD THIS
public login(Form1 parent)
{
InitializeComponent();
this._parent = parent; //ADD THIS
}
public void button1_Click_1(object sender, EventArgs e)
{
this._parent.mytest(); //CALL WHAT YOU WANT
}
}
From your UserControl:
((Form1)Parent).mytest();

Enter Data to main form

I Made an application. The Main form Name is Form1.
And the other Form is called PoP.
public partial class pops : Form
{
public pops()
{
InitializeComponent();
CenterToScreen();
}
private void pops_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
Close();
}
private void lblAdminNo_Click(object sender, EventArgs e)
{
}
}
Make two public properties on popup form and retrieve them from parent form.
string username = string.Empty;
string password = string.Empty;
using (LoginForm form = new LoginForm ())
{
DialogResult result = form.ShowDialog();
if (result == DialogResult.Ok)
{
username = form.Username;
password = form.Password;
}
}
It all depends on from where are you calling the Pop form.
If it is called from the Form1 itself, then the Popform's object itself would provide you the value.
Pop popFrm = new Pop();
if(popFrm.ShowDialog() == Ok)
{
string userName = popFrm.TextBox1.Text;
}
If the Pop is invoked from a different area/part of application, you may have to store it somewhere common to both the forms.
This can be done through events. This approach is particularly useful when data to be posted even when the child form is kept open.
The technique is- From parent form, subscribe to a child from event. Fire the event when child form closes, to send data
----- SAMPLE CODE-----
Note: In the Parent Form add a Button:button1
namespace WindowsFormsApplication2
{
public delegate void PopSaveClickedHandler(String text);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Pops p = new Pops();
p.PopSaveClicked += new PopSaveClickedHandler(p_PopSaveClicked);//Subscribe
p.ShowDialog();
}
void p_PopSaveClicked(string text)
{
this.Text = text;//you have the value in parent form now, use it appropriately here.
}
}
Note: In the Pops Form add a TextBox:txtUserName and a Button:btnSave
namespace WindowsFormsApplication2
{
public partial class Pops : Form
{
public event PopSaveClickedHandler PopSaveClicked;
public Pops()
{
InitializeComponent();
}
private void btnSave_Click(object sender, EventArgs e)
{
if(PopSaveClicked!=null)
{
this.PopSaveClicked(txtUserName.Text);
}
}
}
}
Summary:
1.Add a delegate(place where it available to both parent and child form) :
public delegate void PopSaveClickedHandler(String text);
2.In form:Pops, Add an event:
public event PopSaveClickedHandler PopSaveClicked;
3.Subscribe to the event in Parent Form:
p.PopSaveClicked += new PopSaveClickedHandler(p_PopSaveClicked);
4.Invoke the event in form:Pops Save Button Click
if(PopSaveClicked!=null)
{
this.PopSaveClicked(txtUserName.Text);
}
You can send data to the form object before you display it. Create a method to call, send the info through the constructor... etc.

passing data between two forms using properties

I am passing data between 2 windows forms in c#. Form1 is the main form, whose textbox will receive the text passed to it from form2_textbox & display it in its textbox (form1_textbox).
First, form1 opens, with an empty textbox and a button, on clicking on the form1_button, form2 opens.
In Form2, I entered a text in form2_textbox & then clicked the button (form2_button).ON click event of this button, it will send the text to form1's textbox & form1 will come in focus with its empty form1_textbox with a text received from form2.
I am using properties to implement this task.
FORM2.CS
public partial class Form2 : Form
{
//declare event in form 2
public event EventHandler SomeTextInSomeFormChanged;
public Form2()
{
InitializeComponent();
}
public string get_text_for_Form1
{
get { return form2_textBox1.Text; }
}
//On the button click event of form2, the text from form2 will be send to form1:
public void button1_Click(object sender, EventArgs e)
{
Form1 f1 = new Form1();
f1.set_text_in_Form1 = get_text_for_Form1;
//if subscribers exists
if(SomeTextInSomeFormChanged != null)
{
SomeTextInSomeFormChanged(this, null);
}
}
}
FORM1.CS
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public string set_text_in_Form1
{
set { form1_textBox1.Text = value; }
}
private void form1_button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Show();
f2.SomeTextInSomeFormChanged +=new EventHandler(f2_SomeTextInSomeFormChanged);
}
//in form 1 subcribe to event
Form2 form2 = new Form2();
public void f2_SomeTextInSomeFormChanged(object sender, EventArgs e)
{
this.Focus();
}
}
Now, in this case I have to again SHOW the form1 in order to automatically get the text in its textbox from form2, but I want that as I click the button on form2, the text is sent from Form2 to Form1, & the form1 comes in focus, with its textbox containing the text received from Form2.
I know this is a (really) old question, but hell..
The "best" solution for this is to have a "data" class that will handle holding whatever you need to pass across:
class Session
{
public Session()
{
//Init Vars here
}
public string foo {get; set;}
}
Then have a background "controller" class that can handle calling, showing/hiding forms (etc..)
class Controller
{
private Session m_Session;
public Controller(Session session, Form firstform)
{
m_Session = session;
ShowForm(firstform);
}
private ShowForm(Form firstform)
{
/*Yes, I'm implying that you also keep a reference to "Session"
* within each form, on construction.*/
Form currentform = firstform(m_Session);
DialogResult currentresult = currentform.ShowDialog();
//....
//Logic+Loops that handle calling forms and their behaviours..
}
}
And obviously, in your form, you can have a very simple click listener that's like..
//...
m_Session.foo = textbox.Text;
this.DialogResult = DialogResult.OK;
this.Close();
//...
Then, when you have your magical amazing forms, they can pass things between each other using the session object. If you want to have concurrent access, you might want to set up a mutex or semaphore depending on your needs (which you can also store a reference to within Session). There's also no reason why you cannot have similar controller logic within a parent dialog to control its children (and don't forget, DialogResult is great for simple forms)

How to access a form control for another form?

I have two Form classes, one of which has a ListBox. I need a setter for the SelectedIndex property of the ListBox, which I want to call from the second Form.
At the moment I am doing the following:
Form 1
public int MyListBoxSelectedIndex
{
set { lsbMyList.SelectedIndex = value; }
}
Form 2
private ControlForm mainForm; // form 1
public AddNewObjForm()
{
InitializeComponent();
mainForm = new ControlForm();
}
public void SomeMethod()
{
mainForm.MyListBoxSelectedIndex = -1;
}
Is this the best way to do this?
Making them Singleton is not a completely bad idea, but personally I would not prefer to do it that way. I'd rather pass the reference of one to another form. Here's an example.
Form1 triggers Form2 to open. Form2 has overloaded constructor which takes calling form as argument and provides its reference to Form2 members. This solves the communication problem. For example I've exposed Label Property as public in Form1 which is modified in Form2.
With this approach you can do communication in different ways.
Download Link for Sample Project
//Your Form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2(this);
frm.Show();
}
public string LabelText
{
get { return Lbl.Text; }
set { Lbl.Text = value; }
}
}
//Your Form2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private Form1 mainForm = null;
public Form2(Form callingForm)
{
mainForm = callingForm as Form1;
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
this.mainForm.LabelText = txtMessage.Text;
}
}
(source: ruchitsurati.net)
(source: ruchitsurati.net)
Access the form's controls like this:
formname.controls[Index]
You can cast as appropriate control type, Example:
DataGridView dgv = (DataGridView) formname.Controls[Index];
I usually use the Singleton Design Pattern for something like this http://en.wikipedia.org/wiki/Singleton_pattern . I'll make the main form that the application is running under the singleton, and then create accessors to forms and controls I want to touch in other areas. The other forms can then either get a pointer to the control they want to modify, or the data in the main part of the application they wish to change.
Another approach is to setup events on the different forms for communicating, and use the main form as a hub of sorts to pass the event messages from one form to another within the application.
It's easy, first you can access the other form like this:
(let's say your other form is Form2)
//in Form 1
Form2 F2 = new Form2();
foreach (Control c in F2.Controls)
if(c.Name == "TextBox1")
c.Text = "hello from Form1";
That's it, you just write in TextBox1 in Form2 from Form1.
If ChildForm wants to access the ParentForm
Pass ParentForm instance to the ChildForm constructor.
public partial class ParentForm: Form
{
public ParentForm()
{
InitializeComponent();
}
public string ParentProperty{get;set;}
private void CreateChild()
{
var childForm = new ChildForm(this);
childForm.Show();
}
}
public partial class ChildForm : Form
{
private ParentForm parentForm;
public ChildForm(ParentForm parent)
{
InitializeComponent();
parentForm = parent;
parentForm.ParentProperty = "Value from Child";
}
}
There is one more way, in case you don't want to loop through "ALL" controls like Joe Dabones suggested.
Make a function in Form2 and call it from Form1.
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public void SetIndex(int value)
{
lsbMyList.SelectedIndex = value;
}
}
public partial class Form1 : Form
{
public Form2 frm;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
frm=new Form2();
frm.Show();
}
private void button1_Click(object sender, EventArgs e)
{
frm.SetIndex(Int.Parse(textBox1.Text));
}
}
Here's also another example that does "Find and Highlight". There's a second form (a modal) that opens and contains a textbox to enter some text and then our program finds and highlights the searched text in the RichTextBox (in the calling form). In order to select the RichTextBox element in the calling form, we can use the .Controls.OfType<T>() method:
private void findHltBtn_Click(object sender, EventArgs e)
{
var StrBox = _callingForm.Controls.OfType<RichTextBox>().First(ctrl => ctrl.Name == "richTextBox1");
StrBox.SelectionBackColor = Color.White;
var SearchStr = findTxtBox.Text;
int SearchStrLoc = StrBox.Find(SearchStr);
StrBox.Select(SearchStrLoc, SearchStr.Length);
StrBox.SelectionBackColor = Color.Yellow;
}
Also in the same class (modal's form), to access the calling form use the technique mentioned in the #CuiousGeek's answer:
public partial class FindHltModalForm : Form
{
private Form2 _callingForm = null;
public FindHltModalForm()
{
InitializeComponent();
}
public FindHltModalForm(Form2 CallingForm)
{
_callingForm = CallingForm;
InitializeComponent();
}
//...

Categories