This is my first question. I'm a complete newbie (I have some Arduino and Delphi knowledge, but nothing on C#) and there's something I've been attempting without success. In order to optimize some code I received I found some functions copypasted on each form and I would liek to reduce them to one (and better if in a separate .cs file), and access it from different forms.
For example: I have labels on Form1 and Form2, whose colour I want to be changed based on the .Checked property of a CheckBox on each Form. It's obvious cb_colorear finds controls in Form1. I tried to pass it values like (String formName) and then tried formName.Controls.Find but that didn't work. Any tips?
I'd also love to be pointed to some documentation on these matter. I've tried searching a bit, but without knowing C# and english not being fluent on English I'm struggling to find info I understand. Thank you all for your help.
//Form1 Code
namespace PruebaAccesoMetodos
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.Show(); ;
}
public Color cb_colorear(String cbName, String label)
{
Control[] ctrl = Controls.Find(cbName, true);
CheckBox cb = ctrl[0] as CheckBox;
Control[] ctrl2 = Controls.Find(label, true);
Label lbl = ctrl2[0] as Label;
if (cb.Checked == false)
{
return Color.Red;
}
else
{
return Color.LawnGreen;
}
}
private void button1_Click(object sender, EventArgs e)
{
label1.BackColor = cb_colorear(checkBox1.Name, label1.Name);
}
private void button3_Click(object sender, EventArgs e)
{
System.Diagnostics.Process.Start("explorer.exe", #"c:\");
}
}
}
And Form2 code:
namespace PruebaAccesoMetodos
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form1 frm1instance = new Form1();
label1.BackColor = frm1instance.cb_colorear(this.checkBox1.Name, this.label1.Name);
}
}
}
Update:
Ok, I made it work. Should've tried a bit more before asking haha.
Changed the cb_colorear function to receive Form type values:
public Color cb_colorear(String cbName, String label, Form formName)
{
Control[] ctrl = formName.Controls.Find(cbName, true);
CheckBox cb = ctrl[0] as CheckBox;
Control[] ctrl2 = formName.Controls.Find(label, true);
Label lbl = ctrl2[0] as Label;
if (cb.Checked == false)
{
return Color.Red;
}
else
{
return Color.LawnGreen;
}
}
Then added a this to each button calling the function:
private void button1_Click(object sender, EventArgs e)
{
label1.BackColor = cb_colorear(checkBox1.Name, label1.Name, this);
}
But, while it works, is this the propper solution?
You could use an extension method.
public static class Extensions
{
public static void cb_colorear(this Form form, string cbName, string label)
{
Control[] ctrl = form.Controls.Find(cbName, true);
CheckBox cb = ctrl[0] as CheckBox;
Control[] ctrl2 = form.Controls.Find(label, true);
Label lbl = ctrl2[0] as Label;
if (!cb.Checked)
{
lbl.BackColor = Color.Red;
}
else
{
lbl.BackColor = Color.LawnGreen;
}
}
}
So what have we done here:
We create a new static class (I chose to call it Extensions for the example).
We create our extension method. This method has to be static. Notice the first argument (this Form form instead of just Form form). This single keyword makes all the difference. It is what turns our normal method to an extension.
The rest is the same as your code. We use form as we would any other arguments. There is no need to return the Color, as we can set the label's BackColor property directly.
With the extension method declared, we can do the following in any form:
private void SomeFormMethod()
{
this.cb_colorear(checkBox.Name, label.Name)
}
The first argument is passed to the extension method implicitly, allowing us to use the this.method() syntax.
Related
I have a Form (Form1) where the ComboBox is located, and another form (Form2) where the label is located.
All I want to do is increase that label number when selecting a specific item from the ComboBox and clicking a button.
The code from Form2:
public partial class Form2 : Form
{
public static int counter;
private void btnCadastrar_Click(object sender, EventArgs e)
{
if (combobox.SelectedItem.ToString() == "Item1")
{
counter = Int32.Parse(Form2.labelincrease);
counter++;
Form2.labelincrease = counter.ToString();
}
}
}
The code from Form 1:
public partial class Form1 : Form
{
public static string labelincrease;
}
private void Form1_Load(object sender, EventArgs e)
{
labelincrease = lblIncrease.Text.ToString()
}
I am getting a lot of errors and I am trying a lot of methods but can't get there, I would appreciate any help, thanks.
Hope this will help you.
Instantiated Form2 f2 = new Form2();
labelincrease = f2.lblIncrease.Text.ToString();
I have a form with 2 tabs on it. I can chose the tab viewed after initialization and I need some initial code every time after the tab2 is initialized:
public partial class SetupComponent : Form
{
public SetupComponent(bool tab2)
{
InitializeComponent();
if (tab2)
{
this.tabControl1.SelectedTab = tabPage2;
}
}
private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
{
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
textBox2.SelectionStart = textBox2.Text.Length;
textBox2.Focus();
}
}
if I call this class with tab2=false and then click onto tab2, tabControl1_SelectedIndexChanged is called.
But if I select the tab2=true during SetupComponent, I find no possibility to do that code. All the TabControl1_Events I found are too early and I don`t find a matching TabPage2_Event.
How can I manage it?
I managed this problem using the Paint_Event:
bool activated = false;
private void tabPage2_Paint(object sender, PaintEventArgs e)
{
if (!activated)
{
tabControl1_SelectedIndexChanged(null, null);
activated = true;
}
}
I use the variable because the Paint_Event is called many times.
I am trying to create a notepad like application in C# by using a Textbox.
I want to implement find function in it. I want an ability to search the text entered in textbox of Find form in textbox of Form1 and then highlight it.
Please help i am unable to do it
Form1.cs
private void findToolStripMenuItem_Click(object sender, EventArgs e)
{
Find f = new Find();
f.Show();
}
public void find()
{
int idx = 0;
while((idx=textBox1.Text.IndexOf(text))!=1)
{
textBox1.Select();//Select the text which are found
}
}
Find.cs
public partial class Find : Form
{
Form1 f = new Form1();
public Find()
{
InitializeComponent();
}
private void Cancelbutton2_Click(object sender, EventArgs e)
{
this.Close();
}
private void Findbutton1_Click(object sender, EventArgs e)
{
f.text =textBox1.Text;
f.find();
}
You need to specify the start and length parameter in the "Select" method. For Example:
textBox1.Select(idx, text.Length);
You can only highlight one section of data at a time with the standard TextBox. Try FastColourTextbox if you want better support.
private void textBox1_Enter(object sender, System.EventArgs e){
if (!String.IsNullOrEmpty(textBox1.Text))
{
textBox1.SelectionStart = 0;
textBox1.SelectionLength = textBox1.Text.Length;
}
}
I have a form called SelectCatagoryId which contains a DataGridView. I want to pass the selected cellvalue from here to another form called Add_product.
This is the code inside the button event in SelectcatagoryId.
private void dataGridView1_MouseClick(object sender, MouseEventArgs e)
{
String dgv;
dgv = dataGridView1.CurrentCell.Value.ToString();
Add_product ap = new Add_product(dgv);
this.Close();
}
This is the code inside Add_product form
namespace Supermarket
{
public partial class Add_product : Form
{
public Add_product()
{
InitializeComponent();
}
SqlConnection con;
string file;
public Add_product(String datagridvalue)
{
// MessageBox.Show(datagridvalue);
textBox10.Text = Convert.ToString(datagridvalue);
}
MessageBox is working correctly,value of dgv in form selectCatagoryId is passed correctly to form Add_product, but I can't assign the value of variable datagridvalue to textBox10.Text.
Before assign text to textBox you need to show form Add_product.
private void dataGridView1_MouseClick(object sender, MouseEventArgs e)
{
String dgv;
dgv = dataGridView1.CurrentCell.Value.ToString();
Add_product ap = new Add_product();
ap.Show();
ap.SetProduct(dgv);
this.Close();
}
...
Also add this method to Add_product class
public SetProduct(String datagridvalue)
{
// MessageBox.Show(datagridvalue);
textBox10.Text = datagridvalue;
}
Even with you are creating a overload of constructor, you need to InitializeComponent() so all the instance of the controls are created.
public Add_product(String datagridvalue)
{
InitializeComponent();
// MessageBox.Show(datagridvalue);
textBox10.Text = Convert.ToString(datagridvalue);
}
By default all the UI Component are initiated within the constructor of the form.
And Visual Studio generates all the Initialization in the InitializeComponent() method.
I have "formA" and 2 buttons on it (button1 and button2). What I want to do is:
When I click on button1 to call "formB" display text written in label1.
When I click button2 to call the same form ("formB") hide label1 and display label2.
The problem is that I don't know how to check what button is clicked on "formA".
Edit: Thanks very much folks for the quick answer. Problem is solved!
This is where events come in handy:
public class FormA
{
private void button1_Click(object sender, EventArgs e)
{
formB.Button1WasClicked();
}
private void button2_Click(object sender, EventArgs e)
{
formB.Button2WasClicked();
}
}
public class FormB
{
public void Button1WasClicked()
{
label2.Visible = false;
label1.Visible = true;
label1.Text = "Button 1 was clicked!";
}
public void Button2WasClicked()
{
label1.Visible = false;
label2.Visible = true;
label2.Text = "Button 2 was clicked!";
}
}
button1 and button2 have their own separate Click event handlers. This way we can differentiate the two when they are clicked.
If you have the same event handler for both buttons (as mentioned in one of the comments), you can identify them with the sender parameter using:
Object.ReferenceEquals(sender, button1);
or
Object.ReferenceEquals(sender, button2);
Then your code would look like this:
private void button_Click(object sender, EventArgs e)
{
if (Object.ReferenceEquals(sender, button1))
{
formB.Button1WasClicked();
}
else
{
formB.Button2WasClicked();
}
}
FormB can't find out, the buttons are a private implementation details of FormA. They might not even be a button, surely you are going to add a menu or a toolbar to FormA some day.
The workaround becomes much simpler if you stop thinking of "calling a form". You never call a form, you create an instance of it. And then you make it visible by calling its Show() method. Lots of things you can do in between those two steps.
Add a public method to FormB. For lack of a better name:
public void MakeLabel2Visible() {
this.label1.Visible = false;
this.label2.Visible = true;
}
Now it becomes simple. Implement button2's Click event handler like this:
private void button2_Click(object sender, EventArgs e) {
var frm = new FormB();
frm.MakeLabel2Visible();
frm.Show();
}
Adding another constructor to a form that lets you initialize it differently is another very common approach. These are just classes, standard programming techniques are appropriate.
Because you are using winforms you can do all this very easily due to the fact that you have a stateful environment.
Assuming a very basic set up with:
event handlers in the code behind of form a
a reference to an instance of form b in form a (or the button click creating such an instance)
a method to use in form b to pass it data
Your code will be something like this:
public partial class FormA : Form
{
private FormB formB;
public FormA()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (formB == null || formB.IsDisposed)
{
formB = new FormB();
}
formB.UpdateLabel("Button A");
formB.Show();
}
private void button2_Click(object sender, EventArgs e)
{
if (formB == null || formB.IsDisposed)
{
formB = new FormB();
}
formB.UpdateLabel("Button B");
formB.Show();
}
}
public partial class FormB : Form
{
public FormB()
{
InitializeComponent();
}
public void UpdateLabel(string message)
{
label1.Text = message;
}
}
Of course, there are lots of improvements to this - using events and alerts more intelligently and refactoring to remove duplication, but this is a basic example of the sort of things you can do.