Catch Textbox event from another Form - c#

I have an event in my Form:
public void filterByType_TextChanged(object sender, EventArgs e)
{
dSearch = new D_Search(this);
dSearch.filterD(); }
which calls a function in another class. What I want to do is that I want to notice in my class which Textbox was altered and do something. So there are multiple functions like the one above and they all call the "filterD()" function in my DSearch class. I tried
if (sender == form1.filterByType_TextChanged)
{ sqlCmd = new SqlCommand("SELECT * FROM" } //SQL Statement
}
datTable = new DataTable();
sqlDatAdapter = new SqlDataAdapter(sqlCmd.CommandText,
connection);
sqlDatAdapter.Fill(datTable);
form1.setDataGrid = datTable;
but he can't find "sender" I also tried to create a new Button within the function in my Form and pass it but it doesn't seem to work.

try this -
In form 1
private void textBox1_TextChanged(object sender, EventArgs e)
{
var dSearch = new D_Search(this);
MessageBox.Show(dSearch.filterD(sender));
}
D_Search class
public class D_Search
{
Form1 frm = null;
public D_Search(Form1 frm1)
{
frm = frm1;
}
public string filterD(object sender)
{
string val = String.Empty;
if (sender == frm.textBox1)
{
val = (sender as TextBox).Text;
}
return val;
}
}
also if you want to access filterByType_TextChanged textbox in other class then change its modifier property to Internal

Related

Passing object from one windows form to another

I have two windows forms in my application. First one is Main form and the second one is lookup form. I'm trying to open lookup form from the main form in a text box key leave event and then I'm opening the lookup form. My lookup form has a data grid view and I' loading it in the form load event of the lookup form. I'm reading my selected value on the grid view of the lookup window to an object. I want to close the lookup window as soon as I read the values of the selected row to the object and I want to pass it to the main form? How can I do that?
This is what I have done.
In the main form.
LookupModelType="";
if (e.KeyCode.Equals(Keys.F3))
{
foreach (Form frm in Application.OpenForms)
{
if (frm is FormControllers.Lookup)
{
if (frm.WindowState == FormWindowState.Minimized)
{
frm.WindowState = FormWindowState.Normal;
frm.Focus();
return;
}
}
}
LookupModelType = "Product";
FormControllers.Lookup newLookUp = new FormControllers.Lookup(LookupModelType);
newLookUp.ShowDialog(this);
}
In the lookup window
private string GridType = "";
public Lookup(String LookupModelType)
{
InitializeComponent();
this.GridType = LookupModelType;
}
private void Lookup_Load(object sender, EventArgs e)
{
if (GridType == "Product")
{
using(DataControllers.RIT_Allocation_Entities RAEntity = new DataControllers.RIT_Allocation_Entities())
{
dgvLookup.DataSource = RAEntity.TBLM_PRODUCT.ToList<DataControllers.TBLM_PRODUCT>();
}
}
dgvLookup.ReadOnly = true;
}
private void dgvLookup_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0)
{
return;
}
int index = e.RowIndex;
dgvLookup.Rows[index].Selected = true;
}
you can do it like blow :
in the Main form :
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F3)
{
LookupForm look = new LookupForm();
var result = look.ShowDialog();
if(result == DialogResult.OK)
{
MessageBox.Show(look.data.ToString());
}
}
}
and in the look up form you have to declare 1 variable and fill whenever cell clicked
public partial class LookupForm : Form
{
public object data = new object();
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
data = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
this.DialogResult = DialogResult.OK;
this.Close();
}
}
of course, for better performance, you can declare the variable in specific type
To share data between Parent Child forms using events, here are the things needed:
A public custom event args class to share data.
Child form to have a event.
In your parent form whenever you create an instance of child, you
need to register eventhandlers
Please note that the code below is just a demo code and you will need to add null checks etc. to make it "robust".
Custom event args below
public class ValueSelectedEventArgs : EventArgs
{
public object Value { get; set; }
}
Your lookup form should have the following event declared:
public event EventHandler ValueSelected;
protected virtual void OnValueSelected(ValueSelectedEventArgs e)
{
EventHandler handler = ValueSelected;
if (handler != null)
{
handler(this, e);
}
// if you are using recent version of c# you can simplyfy the code to ValueSelected?.Invoke(this, e);
}
In my case I am firing the event on listbox selected index change and closing the form as well. Code for it:
private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e)
{
var i = this.checkedListBox1.SelectedIndex;
ValueSelectedEventArgs args = new ValueSelectedEventArgs();
args.Value = i;
OnValueSelected(args);
this.Close();
}
Finally in the parent form you have to register for the eventhandler
private void textBox1_Leave(object sender, EventArgs e)
{
lookup myLookup = new lookup();
myLookup.ValueSelected += MyLookup_ValueSelected;
myLookup.Show();
}
private void MyLookup_ValueSelected(object sender, EventArgs e)
{
textBox2.Text = (e as ValueSelectedEventArgs).Value.ToString();
}
I personal like to add dynamically the lookup window, and I do something like this:
//examble object
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
// the value which you want to get from datagridview
private Person _selectedValue;
// the datagridview datasource, which you neet to set
private IEnumerable<Person> _gridDataSource =
new List<Person>()
{
new Person {FirstName="Bob",LastName="Smith" },
new Person {FirstName="Joe",LastName="Doe"}
};
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode== Keys.F3)
{
var btnOk = new Button() { Text = "Ok", Anchor= AnchorStyles.None };
var btnCancel = new Button() { Text = "Cancel",Anchor= AnchorStyles.Right };
var dg = new DataGridView();
var bs = new BindingSource();
bs.DataSource = _gridDataSource;
dg.DataSource = bs;
dg.Dock = DockStyle.Fill;
dg.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
//setup a layout wich will nicely fit to the window
var layout = new TableLayoutPanel();
layout.Controls.Add(dg, 0, 0);
layout.SetColumnSpan(dg, 2);
layout.Controls.Add(btnCancel, 0, 1);
layout.Controls.Add(btnOk, 1, 1);
layout.RowStyles.Add(new RowStyle(SizeType.Percent));
layout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent));
layout.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
layout.Dock = DockStyle.Fill;
//create a new window and add the cotnrols
var window = new Form();
window.StartPosition = FormStartPosition.CenterScreen;
window.Controls.Add(layout);
// set the ok and cancel buttons of the window
window.AcceptButton = btnOk;
window.CancelButton = btnCancel;
btnOk.Click += (s, ev) => { window.DialogResult = DialogResult.OK; };
btnCancel.Click += (s, ev) => { window.DialogResult = DialogResult.Cancel; };
//here we show the window as a dialog
if (window.ShowDialog() == DialogResult.OK)
{
_selectedValue =(Person) bs.Current;
MessageBox.Show(_selectedValue.FirstName);
}
}
}

Form Using User Control Won't Return Value

I am writing a user control. I want it to return a customer number when the user double clicks on the customer. I can't seem to get it to work. The user control is displayed and, on the double click, the data shows in the messagebox but I can't seem to get it to update the value on the main form.
Anytime I try to add a return value into FindCustomerControl_ItemHasBeenSelected, I get an error. It's like it hangs out in the user control and I can't leave it with a return value. So far, this is what I have:
In my main window:
public partial class TestForm : Form
{
public TestForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// one close button on the form
Close();
}
private void ShowSelectFromListWidget()
{
// show the user control
var uc = new FindCustomerControl();
uc.ItemHasBeenSelected += uc_ItemHasBeenSelected;
MakeUserControlPrimaryWindow(uc);
}
void uc_ItemHasBeenSelected(object sender,
FindCustomerControl.SelectedItemEventArgs e)
{
// once it has been selected, change a label on the screen to show the customer number
var value = e.SelectedChoice;
lblCustomer.Text = value;
}
}
In my user control:
public partial class FindCustomerControl : UserControl
{
public class SelectedItemEventArgs : EventArgs
{ public string SelectedChoice { get; set; } }
public event EventHandler<SelectedItemEventArgs> ItemHasBeenSelected;
public FindCustomerControl()
{ InitializeComponent();}
DataTable dt = new DataTable();
public void btnFind_Click(object sender, EventArgs e)
{ var dt = GetData();
dataGridView1.DataSource = dt; }
//Query database
public DataTable GetData()
{
UtilitiesClass ru = new UtilitiesClass();
string connectionString = ru.getConnectionString();
DataTable dt = new DataTable();
SqlConnection myConnection = new SqlConnection(connectionString);
myConnection.Open();
SqlCommand cmd = new SqlCommand("FindCustomer", myConnection);
cmd.Parameters.AddWithValue("#customer", txtCustomer.Text.Trim());
cmd.CommandType = CommandType.StoredProcedure;
SqlDataAdapter ta = new SqlDataAdapter(cmd);
ta.Fill(dt);
myConnection.Close();
return (dt);
}
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
var handler = ItemHasBeenSelected;
string choice = dataGridView1[0, e.RowIndex].Value.ToString();
// this shows it
MessageBox.Show("Chosen: " + e.SelectedChoice);
if (handler != null) handler(this, new SelectedItemEventArgs { SelectedChoice = choice });
// I WOULD LIKE TO RETURN A VALUE HERE
}
}
It seems as though this should be common enough but, in spite of my hours of research and debugging, I have been unable to come up with a solution. I do know that uc.ItemHasBeenSelected += uc_ItemHasBeenSelected; in TestForm doesn't seem to ever get executed because I put a breakpoint there.
As I understood I guess you could use application current resources, where you can save any value you wish - in UWP it is something like this:
Application.Current.Resources["Name"] = customerNumber
Then you can cast this value to desired type:
(int)Application.Current.Resources["Name"]
Now you can use this value wherever you want.
Hope than helped in any way.
There is nothing wrong with the user class. It works fine. The problem is that the TestForm needs to start without the FindCustomerControl on it and instantiate the control within the program. It returns the value into the label or wherever else it needs to. Thanks very much to Brad Rem and this post: Return value from usercontrol after user action
public partial class TestForm : Form
{
public TestForm()
{
InitializeComponent();
ShowSelectFromListWidget();
}
private void button1_Click(object sender, EventArgs e)
{
Close();
}
private void ShowSelectFromListWidget()
{
var uc = new FindCustomerControl();
uc.ItemHasBeenSelected += uc_ItemHasBeenSelected;
this.MakeUserControlPrimaryWindow(uc);
}
void uc_ItemHasBeenSelected(object sender, FindCustomerControl.SelectedItemEventArgs e)
{
var value = e.SelectedChoice;
lblCustomer.Text = value;
lblMerchant.Focus();
//ClosePrimaryUserControl();
}
private void MakeUserControlPrimaryWindow(UserControl uc)
{
// my example just puts in in a panel, but for you
// put your special code here to handle your user control management
panel1.Controls.Add(uc);
}
private void ClosePrimaryUserControl()
{
// put your special code here to handle your user control management
panel1.Controls.Clear();
}
}

DGV updates only when cell is clicked

I have a WFA, at the moment it has 2 forms.
The first form contains a DataGridView, with it's data source being a list.
When the user clicks a button, this opens up form2. Within form2 I have a bubblesort algorithm which sorts the list by one of it's properties. It then passes the updates list back to form1, and sets the new datasource to the bubbledsorted updated list from form2.
Now this works, the bubblesort works. HOWEVER, the DGV on form1 doesn't update UNLESS I click on individual rows/cells of the DGV. I have to click on each one individually for them to be in their new sorted positions.
Here's the code I have:
FORM1:
//This just shows Form2
private void sortByPriority_Click(object sender, EventArgs e)
{
fm2 = new Form2();
fm2.Show();
}
//This is called by form2 to set the new datasource
public void refreshDataGrid(DataGridView p)
{
dataGridView1.DataSource = null;
dataGridView1.DataSource = p.DataSource;
}
FORM2:
private void sortPriority_Click(object sender, EventArgs e)
{
int temp = 0;
bool tempforComp;
string tempforDate = "";
string tempforDesc = "";
string tempforName = "";
for (int write = 0; write < 10; write++)
{
for (int sort = 0; sort < toDoGen.task.Count - 1; sort++)
{
if (toDoGen.task[sort].Priority > toDoGen.task[sort + 1].Priority)
{
temp = toDoGen.task[sort + 1].Priority;
tempforComp = toDoGen.task[sort + 1].Completed;
tempforDate = toDoGen.task[sort + 1].DateOfCompletion;
tempforDesc = toDoGen.task[sort + 1].Description;
tempforName = toDoGen.task[sort + 1].Name;
toDoGen.task[sort + 1].Priority = toDoGen.task[sort].Priority;
toDoGen.task[sort + 1].Completed = toDoGen.task[sort].Completed;
toDoGen.task[sort + 1].DateOfCompletion = toDoGen.task[sort].DateOfCompletion;
toDoGen.task[sort + 1].Description = toDoGen.task[sort].Description;
toDoGen.task[sort + 1].Name = toDoGen.task[sort].Name;
toDoGen.task[sort].Priority = temp;
toDoGen.task[sort].Completed = tempforComp;
toDoGen.task[sort].DateOfCompletion = tempforDate;
toDoGen.task[sort].Description = tempforDesc;
toDoGen.task[sort].Name = tempforName;
}
}
DataGrid n = new DataGrid();
n.DataSource = toDoGen.task;
refresh();
}
}
private void refresh()
{
fm1 = new Form1();
fm1.refreshDataGrid(n);
}
EDIT: updated and just to be clear - I need to use multiple forms (University Assignment), and nonetheless, it didn't update even when I had the sorting algorithm in Form1.
I'll make a simplified example that doesn't use the BubbleSort algorithm, I hope it helps:
This is the code of Form1 class. I define a StringValue class because of this: How to bind a List<string> to a DataGridView control?
public class StringValue
{
public StringValue(string s)
{
_value = s;
}
public string Value { get { return _value; } set { _value = value; } }
string _value;
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = new List<StringValue> {
new StringValue("string1"),
new StringValue("string3"),
new StringValue("string2")
};
}
private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2(this, dataGridView1.DataSource as List<StringValue>);
form2.Show();
}
public void RefreshGrid(List<StringValue> source)
{
dataGridView1.DataSource = source;
}
}
The button click event opens Form2 and passes to it the grid view datasource. Here's Form2:
public partial class Form2 : Form
{
Form1 _form1;
List<StringValue> _source;
public Form2(Form1 form1, List<StringValue> source)
{
_form1=form1;
_source=source;
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
_source = _source.OrderBy(x => x.Value).ToList();
_form1.RefreshGrid(_source);
this.Close();
}
}
After the click on the button in Form2 the DataGridView1's data source is refreshed with a sorted version, and Form2 is closed.

send TextBox Values from FormB to a datagridView in FormA

I have to send the value of 2 TextBoxes from FormB when I clic on the "validate buton" to the datagridView in FormA;this is what I try to code:
FormB:
namespace RibbonDemo.Fichier
{
public partial class NvFamillImmo : Form
{
public event BetweenFormEventHandler BetweenForm;
SqlDataAdapter dr;
DataSet ds = new DataSet();
string req;
public NvFamillImmo()
{
InitializeComponent();
affich();
}
private void button2_Click(object sender, EventArgs e) //the validate buton
{
if (BetweenForm != null)
BetweenForm(textBox1.Text, textBox2.Text);
}
private void fillByToolStripButton_Click(object sender, EventArgs e)
{
try
{
this.amortissementFiscalTableAdapter.FillBy(this.mainDataSet.amortissementFiscal);
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
}
}
and this is FormA:
namespace RibbonDemo.Fichier
{
public delegate void BetweenFormEventHandler(string txtbox1value, string txtbox2value);
public partial class FammileImm : Form
{
private NvFamillImmo nvFamillImmo;
public FammileImm()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
NvFamillImmo frm2 = new NvFamillImmo();
frm2.BetweenForm += frm2_BetweenForm;
frm2.ShowDialog();
}
void frm2_BetweenForm(string txtbox1value, string txtbox2value)
{
//dataGridView1.Refresh();
String str1 = nvFamillImmo.textBox1.Text.ToString();
this.dataGridView1.Rows[0].Cells[0].Value = str1;
}
}
}
EDIT:I filled the method frm2_BetwwenForm but now I get a problem in reference
thanks for Help
No Need to create event for that. you can create properties in second form where you want to send value from existing form. for example if you have two forms FormA and FormB then FormB should contains properties like Value1 and Value2.
//FormB
public class FormB :Form
{
public string Value1{get; set;}
public string Value2{get; set;}
}
Now you can assign value into both properties from FormA.
//FormA
public void button1_click(object sender, EventArgs e)
{
FormB myForm = new FormB();
myForm.Value1 = textBox1.Text;
myForm.Value2 = textBox1.Text;
myForm.Show();
}
Then you can get both textboxes value into FormB. You can handle value into Form Load event
//FormB
public void FormB_Load(object sender, EventArgs e)
{
string fromTextBox1 = this.Value1;
string formTextBox2 = this.Value2;
}
If the FormB is already loaded and want to send value from FormA then create a method UpdateValues() and modify the properties to call that method.
//FormB
string _value1 = string.Empty;
public string Value1
{
get { return _value1; }
set {
_value1 = value;
UpdateValues();
}
}
string _value2 = string.Empty;
public string Value1
{
get { return _value2; }
set {
_value2 = value;
UpdateValues();
}
}
private void UpdateValues()
{
string fromTextBox1 = this.Value1;
string fromTextBox2 = this.Value2;
}
and Assign the values in FormB.Value1 and FormB.Value2 properties from FormA.
//FormA
FormB myForm = new FormB();
public void button1_click(object sender, EventArgs e)
{
if (myForm != null && myForm.IsDisposed == false)
{
myForm.Value1 = textBox1.Text;
myForm.Value2 = textBox1.Text;
}
}
When the value is updated from FormA then UpdateValues() method will be called.

NullReferenceException was unhandled - what is null?

I'm trying to access an event in my main form by clicking a button (btnsearch_Click) and everytime I clicked it, it says 'object reference not set to an instance of an object'.
Here is my code:
USER CONTROL
namespace Purchase_Order
{
public partial class Search : UserControl
{
public event EventHandler btnSearchClicked;
public Search()
{
InitializeComponent();
}
private void btnsearch_Click(object sender, EventArgs e)
{
btnSearchClicked(sender, e);
}
}
}
MAIN FORM
namespace Purchase_Order
{
public partial class formMain : Form
{
public formMain()
{
InitializeComponent();
}
private void formMain_Load(object sender, EventArgs e)
{
Search searchbox = new Search();
searchbox.btnSearchClicked += new EventHandler(SearchClicked);
}
void SearchClicked(object sender, EventArgs e)
{
MySqlConnection con = new MySqlConnection(serverstring);
try
{
string query = "SELECT * FROM tblclassification WHERE INSTR(class_name, #search)";
MySqlCommand cmd = new MySqlCommand(query, con);
MySqlDataAdapter da = new MySqlDataAdapter(cmd);
Search content = new Search();
cmd.Parameters.AddWithValue("#search", content.btnsearch.Text);
DataTable dt = new DataTable();
da.Fill(dt);
classification control = new classification();
control.dataGridView1.DataSource = dt;
control.dataGridView1.DataMember = dt.TableName;
panelMain.Controls.Clear();
panelMain.Controls.Add(control);
MessageBox.Show("OK");
}
catch (Exception)
{
throw;
}
finally
{
if (con.State == ConnectionState.Open)
{
con.Close();
}
}
}
You are creating a new instance of your user control in SearchClicked method and you are not registering the event against it.
Search content = new Search();
Also its better if you check whether any control has register your event before raising it like:
private void btnsearch_Click(object sender, EventArgs e)
{
if(btnSearchClicked != null)
btnSearchClicked(sender, e);
}
That means that you haven't got an instance of the type you want to use.
public event EventHandler btnSearchClicked; is just a reference for the "real" object you want to use.
It's like you trying to open a door of a house you only have a blueprint. This isn't really possible (at least not in our universe). You will first need to build the house and then try to enter it. Something like this is the case with your problem.
You will have to read a few tutorials about C#
Edit:
The thing about null is that there is nothing the reference you have is pointing too. If you haven't created anything then there isn't anything to reference...
Because you are trying to use something that doesn't exists (is null) you are getting an exception.
To try and expand a little on Habib's answer (I was going to post this as a comment but it's a little lengthy), you are first creating an instance of Search and registering the event in formMain_Load here:
private void formMain_Load(object sender, EventArgs e)
{
Search searchbox = new Search();
searchbox.btnSearchClicked += new EventHandler(SearchClicked);
}
This is all fine and dandy. However, in SearchClicked, you create a new instance of Search like so:
Search content = new Search();
This is a separate object to the one you created in formMain_Load and you never register the event to this object. It looks like what you want to do is share the Search instance from formMain_Load with the SearchClicked method. To do this, create a property in your codebehind:
public partial class formMain : Form
{
private Search _searchbox;
...
}
Then, in formMain_Load:
private void formMain_Load(object sender, EventArgs e)
{
_searchbox = new Search();
_searchbox.btnSearchClicked += new EventHandler(SearchClicked);
}
Now, you can reuse this object with the event registered in SearchClicked by changing this:
Search content = new Search();
To this:
Search content = _searchbox;
You should find that the exception goes away. Hopefully, this will have provided a little more insight and will help you to understand the cause of the error and how to circumvent it.
Share the Search instance from formMain_Load with the SearchClicked method
MAIN FORM
public partial class formMain : Form
{
private Search _searchbox;
...
private void formMain_Load(object sender, EventArgs e)
{
_searchbox = new Search();
_searchbox.btnSearchClicked += new EventHandler(SearchClicked);
}
void SearchClicked(object sender, EventArgs e)
{
Search content = _searchbox;
MySqlConnection con = new MySqlConnection(serverstring);
try
{
string query = "SELECT * FROM tblclassification WHERE INSTR(class_name, #search)";
MySqlCommand cmd = new MySqlCommand(query, con);
MySqlDataAdapter da = new MySqlDataAdapter(cmd);
cmd.Parameters.AddWithValue("#search", content.btnsearch.Text);
DataTable dt = new DataTable();
da.Fill(dt);
classification control = new classification();
control.dataGridView1.DataSource = dt;
control.dataGridView1.DataMember = dt.TableName;
panelMain.Controls.Clear();
panelMain.Controls.Add(control);
MessageBox.Show("OK");
}
catch (Exception)
{
throw;
}
finally
{
if (con.State == ConnectionState.Open)
{
con.Close();
}
}
}
}
USER CONTROL
public partial class Search : UserControl
{
public event EventHandler btnSearchClicked;
public Search()
{
InitializeComponent();
}
private void btnsearch_Click(object sender, EventArgs e)
{
btnSearchClicked(sender, e);
}
}

Categories

Resources