c# How to send an array with an event? - c#

I have this array with information
string[] aInfo; // Contains information about this person
I have a clickevent on a menuitem that goes like this:
// Event for adding contact
mContact.Click += new EventHandler(addContactMenuClick);
Then further into the project i have the eventhandler:
// Eventhandler for adding a contact
private void addContactMenuClick(object sender, System.EventArgs e)
{
string sNumber = ((MenuItem)sender).Text;
MessageBox.Show(sNumber);
}
How can i send the array with the event?
All this is in a foreach loop, so the array will never be the same.
Thanks in advance

Define your own class that derives from EventArgs and add a field for your array there.
class MyEventArgs : EventArgs
{
public string[] Info { get; private set; }
public MyEventArgs(string[] info)
{
this.Info = info;
}
}
EDIT (thanks to the comments):
OF course, you cannot change the information that the Click-Event sends, because you can'T change to code that fires the event.
One possible solution would be to derive your own MenuItem and add the information array as a field to this derived class. Then provide a property for this field, so you can access it via the sender parameter of your event. Example:
class MyMenuItem : MenuItem
{
public string[] Info { get; private set; }
public MyMenuItem(string[] strInfo)
{
this.Info = strInfo;
}
}
Access:
protected void mnu_Click(object sender, EventArgs e)
{
MyMenuItem obj = sender as MyMenuItem;
if (obj != null)
{
//Access
}
}

each control has a Tag property that is of the "object" datatype. you could assign your array to this property. Then in the event, cast it back to an array, and use it.
string[] aInfo; // Contains information about this person
....
....
// Event for adding contact
mContact.Click += new EventHandler(addContactMenuClick);
mContact.Tag = aInfo;
// Eventhandler for adding a contact
private void addContactMenuClick(object sender, System.EventArgs e)
{
string sNumber = ((MenuItem)sender).Text;
string[] aInfo = (string[])((MenuItem)sender).Tag;
MessageBox.Show(sNumber);
}

Just put it in a custom Event Args object! Just create an object (ContactMenuClickedEventArgs) or something that inherits from Event Args.
Wrap mContact in another object, and override the 'click' functionality. Have it create the custom EventArgs, and it will get passed in as 'e'!

You can't really add the information to an existing event type. But you can derive your own EventArgs class (ContactAddedEventArgs) that can hold any information you like, and set up a new event (ContactAdded) that accepts this new data.
If you then wish to also Add contacts when you get a click, then just make the click event handler create the user info array (ContactAddedEventArgs) and then raise your ContactAdded event with it.

The key is in the comment to this line:
string[] aInfo; // Contains information about this person
"this person". So aInfo is a member of some class, correct? And when you click your addContact MenuItem you presumably want to use some currently selected object on the screen as your "contact-to-add". So you need to know how to do that part (find the currently selected object on the screen). This object will likely have some relationship to the type containing your aInfo member, and if it doesn't you need to fix that.

Related

return a string value from an EventHandler void

I'm using an EventHandler to check which button was clicked inside Autocad, the only problem is I don't know how can I return the string value from the void and use it inside the main class. It would be great to get some Help!
Autodesk.Windows.ComponentManager.ItemExecuted += new EventHandler<Autodesk.Internal.Windows.RibbonItemExecutedEventArgs>(ItemExecutedTest);
void ItemExecutedTest(object sender, Autodesk.Internal.Windows.RibbonItemExecutedEventArgs e)
{
string scriptName = e.Item.Text;
}
string script = scriptName;
The only normal way of passing a value to the event caller from the event handler is through the event args. You should also add a flag e.g. IsHandled that you can set to true.
The dirty way is by making the handler non void.
You obviously cannot change the return type of your EventHandler and doing so wouldn't help neither. What you need to do is: set a class field or property.
Example:
public class Example
{
private string ScriptName {get; set;} = string.Empty;
public Example()
{
// register events
Autodesk.Windows.ComponentManager.ItemExecuted += new EventHandler<Autodesk.Internal.Windows.RibbonItemExecutedEventArgs>(ItemExecutedTest);
}
void ItemExecutedTest(object sender, Autodesk.Internal.Windows.RibbonItemExecutedEventArgs e)
{
ScriptName = e.Item.Text;
// class property now contains e.Item.Text
}
}
Heads Up: If you access UI-Items inside that handler, you need to check if you are*) on the UI Thread and possibly marshal to it.
*) "you are" as in "if the handler is executed on the UI Thread" ;)

How do I change the value of form controls without triggering any event?

I want to change the value that is assign to control of a form in c# (visual studio 2010), while the form is loaded.
I want my form should display to the end user, but at the same time as I get the data from server, I want it to reflect the same data onto the controls. (without any using timer, thread or any event).
Example : textBox1.text ="abc";
if server is sending "xyz" than while form is already loaded testbox's value should automatically change to xyz.
without any click or any kind of event.
You have to look at how Properties in c# work:
If we decompile a simple class on sharplab.io
public class C {
public int foo
{get;set;}
}
You will see that the compile will always generate backing fields and a getter and setter method.
So if you don't want to trigger an event you will have to bypass these methods as most likely the event will be triggered in there.
This should be doable with an reflection which is normally pretty easy to do.
BUT Textbox doesn't seem to have a backing field which is easily accessible for its Text-Property. Most likely it is set by its private StringSource field. Which is from the internal type StringSource. So first we have to get the type. Get a reference to the constructor then call this and set the private field.
This is how far i've come:
private int number = 0;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
number++;
this.textBox1.Text = number.ToString();
}
private void button2_Click(object sender, EventArgs e)
{
number++;
Type cTorType = typeof(string[]);
string[] cTorParams = new string[] { number.ToString() };
Type type = this.textBox1.GetType().GetRuntimeFields().ElementAt(11).FieldType;
ConstructorInfo ctor = type.GetConstructor(new[] { cTorType });
object stringSourceInstance = ctor.Invoke(new[] { cTorParams });
this.textBox1.GetType().GetRuntimeFields().ElementAt(11).SetValue(this.textBox1, stringSourceInstance);
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
MessageBox.Show("Changed!");
}
I'd recommend digging a bit more into reflection and see what you can find in the TextBox class by using typeof(TextBox).GetFields / .GetProperties because somewhere there must be a field or property which you can change to bypass your setter method triggering the event.
Hope this helps.

Passing Data back to First Form from Second Form in C#

I have two Forms. Say FormA, FormB.
From FormA i called FormB using
frmB.Show();
In FormB, i've two textboxes and a combobox controls.
Assume User enters some data in those two textboxes and selected an item from combobox in Form2 and clicked an OK button.
After the click i want those textboxes user entered values, combobox selected item value back to FormA.
How can i achieve this using C#.
I approached the simple way .. little embellishments..
create public variables in your form class i.e.
public string passVariable1 = "";
if you have text boxes go to properties, then click on the lightning bolt and double click on the empty TextChanged eventhandler. This will create a code snippet in the code begind that gets executed when the content of the textbox changed .. in this code block assign the content of the text box to your corresponding public variable.
i.e. my public variable was
public string issue = "";
private void txtIssue_TextChanged(object sender, EventArgs e)
{
issue = txtIssue.Text;
}
Add a button and create a click event for this button (simply double click on the button in the design pane). In the click event code block set the dilog result to ok and hide the
this.DialogResult = DialogResult.OK;
this.Hide();
In the parent window code check on the dialog result and grab the form data from the child form's public variables
if (f.ShowDialog() == DialogResult.OK)
{
string b = f.issue;
string e = f.year;
string f = f.month;
};
In the scenario that you are describing I would probably call frmB.ShowDialog() rather than frmB.Show().
// Inside FormA open frmB as a modal dialog waiting for
// OK or Cancel result using the following statement
if (frmB.ShowDialog() == DialogResult.OK)
{
// Retrieve selected values from frmB here (while frmB is still not disposed)
}
The benefits of ShowDialog() are that you:
Get the return value from the form easily allowing you to determine that OK (rather than cancel) was clicked to close it.
The form is not immediately disposed when closed thus allowing you to retrieve the values that you want.
By opening frmB as a modal dialog you avoid having to check for the complexities that may occur if your user starts interacting with formA while frmB is open.
NOTE: When designing frmB you have to set the DialogResult property of the OK button-control to DialogResult.OK in order for the form to return the correct DialogResult when this button is pressed (alternatively can also set this.DialogResult in the OK button's Click event handler)
Or you could pass an object from FormA to FormB and bind its properties to the controls in FormB. If you want FormA to be notified when you click OK button you could declare an event in your data container class, subscribe to it in FormA and fire it from FormB.
Be DataContainer some class you define
public class DataContainer
{
public event EventHandler AcceptedChanges;
protected virtual void OnAcceptedChanges()
{
if ((this.AcceptedChanges != null))
{
this.AcceptedChanges(this, EventArgs.Empty);
}
}
public void AcceptChanges()
{
this.OnAcceptedChanges();
}
public string Text1 { get; set; }
public string Text2 { get; set; }
}
in FormA:
private void button4_Click(object sender, EventArgs e)
{
DataContainer data = new DataContainer();
data.Text1 = "text1";
data.Text1 = "text2";
Form2 frm = new Form2();
frm.Data = new DataContainer();
data.AcceptedChanges += new EventHandler(data_AcceptedChanges);
frm.Show();
}
void data_AcceptedChanges(object sender, EventArgs e)
{
// your code here
}
and in FormB:
public DataContainer Data { get; set; }
private void Form2_Load(object sender, EventArgs e)
{
textBox1.DataBindings.Add(new Binding("Text", Data, "Text1"));
textBox2.DataBindings.Add(new Binding("Text", Data, "Text2"));
}
private void button1_Click(object sender, EventArgs e)
{
Data.AcceptChanges();
}
You should also implement INotifyPropertyChanging and INotifyPropertyChanged on DataContainer class to play nice with bindings.
You can create an EventHandler on FormB which FormA will subscribe to. Also, add a couple of public properties to FormB that represent that data that you want FormA to be able to use. Then, when FormB fires off the event, FormA will know to refresh his data.
Note: The key principle in this example is implementing an EventHandler (you can create your own event handler type) which notifies FormA when data is ready to be refreshed/viewed/etc. Hopefully, this example will allow you to see how you might implement an event handler for your particular situation.
Example:
FormA -
public partial class FormA : Form
{
//FormA has a private instance of FormB
private FormB formB = null;
public FormA()
{
InitializeComponent();
}
void formB_OnDataAvailable(object sender, EventArgs e)
{
//Event handler for when FormB fires off the event
this.label1.Text = string.Format("Text1: {0}\r\nText2: {1}",
formB.Text1, formB.Text2);
}
private void InitializeFormB()
{
this.formB = new FormB();
//FormA subscribes to FormB's event
formB.OnDataAvailable += new EventHandler(formB_OnDataAvailable);
}
private void button1_Click(object sender, EventArgs e)
{
this.InitializeFormB();
formB.Show();
}
}
FormB -
public partial class FormB : Form
{
//Event that fires when data is available
public event EventHandler OnDataAvailable;
//Properties that expose FormB's data
public string Text1 { get; private set; }
public string Text2 { get; private set; }
public FormB()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Set the exposed properties, then fire off the event.
this.Text1 = this.textBox1.Text;
this.Text2 = this.textBox2.Text;
if (OnDataAvailable != null)
OnDataAvailable(this, EventArgs.Empty);
}
}
A dirty, but also fastest solution is to make those controls public. This you can do by adding the word public in the Form2.Decisgner.cs file. If FormA has a member variable or local variable of FormB, you can access the control (say TextBox1) with:
frmB.TextBox1.Text
which is now accessible outside FormB too.
How about using events and delegates? See this http://colinmackay.scot/2005/04/22/passing-values-between-forms-in-net/
I was having this same issue and came up with an idea which is a bit different. In my scenario, I am making a flashcard program for my youngest two children and I wanted to be able to carry back the answer provided to the parent form (new child form for each new flashcard question so that the parent form can update how many are left, how many correct, how many incorrect, etc.) without having to add values to a database. Seems to be overkill for something that should be simple. What I did was to create a class with 3 of each variable type. I figured three of each type would be sufficient for most jobs.
This is an example of my new class:
namespace ClassNamespace
{
public class ValueHolder
{
public int intValue1 { get; set; }
public int intValue2 { get; set; }
public int intValue3 { get; set; }
public long longValue1 { get; set; }
.
.
.
}
}
I create a new ValueHolder (ValueHolder vh;) from parent form and pass it to the child form. In the child form I create a new ValueHolder and then set it equal to the ValueHolder object sent in the child form's class constructor. Now, when the enter key is pressed (answer given), I can set vh.intValue1 equal to this.answerBox.text;... well, I have to use int.tryparse(); but you get the idea. I then only need to reference vh.intValue1 from the parent form to get the value entered.
Parent form:
for (int i = 0; i < limit; i++)
{
ValueHolder vh = new ValueHolder();
ChildClass cc = new ChildClass(vh);
MessageBox.Show(vh.intValue1.ToString()); //to test that it works
}
and child form:
ValueHolder vh;
public ChildClass (ValueHolder vhIncoming)
{
vh = vhIncoming;
}
private void answerBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
vh.intValue1 = 1234;
}
}
This seems to be the simplest solution for my scenario. I know that this question is old, but wanted to add this option for anyone in a similar position. Just add the class to your project, add more of a type or more types to the class as needed, rinse repeat for future projects.
If its on the same page you should be able to read it directly from your controls as Textbox1.Text, Textbox2.Text, Combobox.SelectedValue (i guess)
But if its on different pages use Session variables like:
Session["date1"] = TextBox1.Text;
Session["date2"] = TextBox2.Text;
Session["comboValue"] = Combobox.SelectedValue;
and use them to populate your form
This would depend on how you normally design your applications.
You could work by using a event
driven system where you would create
events and delegates. Mentioned by #Dave81
Or you could create properties that
return the given/selected values so
that the parent can retrieve them
from the object (Wanted to say Dialog
but not sure about what your using).
Or you can follow #zmilojko and just
set them public, which is basically
the same as creating properties but
more to the dark side of coding
practices :D
All these would work but it all depends on how you like your applications to be structured.

how to access Custom EventArgs class in Button click event?

As a follow up to:
access values within custom eventargs class
How do I access public variables within custom Eventargs class, using button click or any other method?
Example Custom Event Args class:
public class TraderEventArgs: EventArgs
{
private int _shares;
private string _symbol;
public TraderEventArgs(int shs, string sym)
{
this._shares = shs;
this._symbol = sym;
}
public decimal Price
{
get {return _prices;}
}
public int Shares
{
get { return _shares; }
}
}
Code behind button_click event:
public partial class _Default : System.Web.UI.Page
{
protected void Button1_Click(object sender, EventArgs e)
{
// run trader app
myApp.Main();
// try to access TraderEventArgs class
TraderEventArgs: EventArgs ev = TraderEventArgs: EventArgs(); // Invalid
TraderEventArgs ev = new TraderEventArgs(); // this needs argument variables that are unassigned... ?
TraderEventArgs ev = (TraderEventArgs)e; // Unable to cast object of type 'System.EventArgs' to type TraderEventArgs'.
string sym = ev.Symbol.ToString();
string sharws = ev.Shares.ToString();
// do something with data
}
thanks for help.
When the button click event is raised, it's creating the EventArgs that gets passed into "e". That object was not created by you, but rather by the framework itself, and is of type EventArgs. This prevents you from being able to cast it to a different type.
If you want to have an event that raises TraderEventArgs, you need to create an event, preferably of type EventHandler<TraderEventArgs>, and raise this event somewhere that is in your control. This allows you to generate the class of the correct type, then handle it (in a separate event handler) directly.
You can't do that. The EventArgs of the Click event is always of type EventArgs; you can't expect it to be of type TraderEventArgs, because the event args is created by the button, and the button doesn't know anything about TraderEventArgs. The only way it could work is if you create your own Button control that raises the event with a TraderEventArgs instead of an EventArgs
Solution: Pass custom event args through a custom delegate and event that returns the data (Datatable, Array, etc)...using whatever button click or other event necessary.
So as a function of the delegate the correct data is returned.. I can not post the complete code here, but it is a modification of this very excellent example on event delegate usage...
Core C# and .NET
3.7. Delegates and Events
http://flylib.com/books/en/4.253.1.38/1/

how do I subscribe to an event of a usercontrol

I have a group of usercontrols that I use multiple instances of through out my form.
The usercontrols have contain either a textbox, combobox, or checkbox and a get value method to return the value of it's repective control. Usually I have a button on the form whose clicked event calls the usercontrols getValue function, but now I need for something to happen on the form whenever the usercontrols controls changed event happens. Something like the following.
In form1.cs
form1.Controls.Add(UserControl1);
form1.Controls.Add(UserContorl2);
// gets called every time the combobox on UserControl1 has it's
// ValueChanged event raised
private void UserControl1_Changed(object Sender, EventArgs e)
{
form1.property1 = UserControl1.getValue();
}
// gets called everytime the textbox on UserControl2 has it's
// textChanged event raised
private void UserControl2_Changed(object Sender, EventArgs e)
{
form1.property2 = UserControl2.getValue();
}
I can't figure out how to throw/catch that event in form. I'm using VS 2005.
here is the code in one of my usercontrols. txtValue is a textbox
public partial class StringParameterControl : BaseParameterControl
{
public StringParameterControl(string aName, string aValue)
: base(aName)
{
InitializeComponent();
txtValue.Text = aValue;
}
public StringParameterControl(string aName)
: base(aName)
{
InitializeComponent();
}
public StringParameterControl()
: base()
{
InitializeComponent();
}
public void SetValue(string aValue)
{
txtValue.Text = aValue;
}
public override object GetValue()
{
return txtValue.Text;
}
}
UserControl1.Changed += UserControl1_Changed;
Update your control to include the following:
// A delegate type for hooking up change notifications.
// This is _what kind_ of event you want. It sets the signature your event handler methods must have.
public delegate void ChangedEventHandler(object sender, EventArgs e);
//the actual event
public event ChangedEventHandler Changed;
// Method to raise/fire the Changed event. Call this whenever something changes
protected virtual void OnChanged(EventArgs e)
{
ChangedEventHandler handler = Changed;
if (handler != null) handler(this, e);
}
//and update your existing SetValue() function like so:
public void SetValue(string aValue)
{
txtValue.Text = aValue;
OnChanged(EventArgs.Empty);
}
You can change your event signature to pass any information you want — for example the old or new value of the property (or both). I just used the standard event arguments for the example.
And speaking or properties, don't write separate Get/Set methods in C# like you just did. If you find yourself doing that, you probably want to use a property instead, which will enforce the correct get/set semantics automatically:
public string Value
{
get { return txtValue.Text;}
set {txtValue.Text = value; OnChanged(EventArgs.Emtpy); }
}
As far as I understand the usercontrols you are using do not fire events whenever their value changes, so you can't just subscribe to some "ValueChanged" event.
A possible solution might be to find the control you are interested in (Combobox, Textbox, etc.) in the usercontrols' "Controls" collection and directly subscribe to its appropriate events.
Or you can do with type inference style.
UserControl.Changed = (sender, e) => this.controlFired = true; //or whatever
The Changed is the public event you expose through a property in your control with the type of the delegate (void(object sender, EventArges e)). You can look up how to publish the event on msdn - there is plenty of articles on that.

Categories

Resources