I am just trying my hand at some WinForm Applications and was creating a simple event handler, but I get an error message. Code:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public delegate void MyHandler1(object sender, EventArgs e);
public Form1()
{
InitializeComponent();
List<string> names = new List<string>();
names.Add("S");
names.Add("I");
names.Add("G");
MyHandler1 onClicked = new MyHandler1(clicked);
listBox1.DataSource = names;
listBox1.Click += onClicked;
}
public void clicked(object sender, EventArgs e)
{
label1.ResetText();
label1.Text = listBox1.SelectedItem.ToString();
}
}
}
Error:
Error 1 Cannot implicitly convert type 'WindowsFormsApplication1.Form1.MyHandler1' to 'System.EventHandler'
The reason that your code doesn't compile is that implicit conversions do not exist between different delegate-types, even when the signatures are 'compatible'.
Try either of these:
// Implicit method-group conversion, should work from C# 2.0 or later.
// Essentially shorthand for listBox1.Click += new EventHandler(clicked);
listBox1.Click += clicked;
// Creating a delegate-instance from a 'compatible' delegate,
// a trick I recently learnt from his highness Jon Skeet
listBox1.Click += new EventHandler(onClicked);
As an aside, unless the intention is to learn how to use delegates, I suggest you don't create your own delegate-type when one that comes with the framework will do the job.
Just use this code instead:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public delegate void MyHandler1(object sender, EventArgs e);
public Form1()
{
InitializeComponent();
List<string> names = new List<string>();
names.Add("S");
names.Add("I");
names.Add("G");
listBox1.DataSource = names;
listBox1.Click += clicked;
}
public void clicked(object sender, EventArgs e)
{
label1.ResetText();
label1.Text = listBox1.SelectedItem.ToString();
}
}
}
You don't really need the EventHandler1 in order to listen to handle an event with clicked method.
You do not need to create an entirely new delegate type to subscribe to an existing event. The event you are subscribing to already uses the existing System.EventHandler delegate type.
You only need to do:
listBox1.Click += new EventHandler(onClicked);
Related
What is the difference between -= new EventHandler(Method) to -= Method
when the method passing as parameter?
Why does the removeNew failed to unsubscribe?
see the following class:
public class Class1
{
public EventHandler _eh;
public void OnEvent()
{
if (_eh != null)
{
_eh.Invoke("", new EventArgs());
}
}
public void remove(EventHandler evHandler)
{
// unsubscribe successfully
_eh -= evHandler;
}
public void removeNew(EventHandler evHandler)
{
// failed to unsubscribe
_eh -= new EventHandler(evHandler);
}
}
Update:
#SchabseLaks, just to clearify my questation I'm adding the code that call this methods:
public partial class Form1 : Form
{
Class1 c1 = new Class1();
public Form1()
{
InitializeComponent();
c1._eh += Hello;
}
private void button1_Click(object sender, EventArgs e)
{
c1.OnEvent();
}
private void Hello(object sender, EventArgs e)
{
MessageBox.Show("hello");
}
private void button2_Click(object sender, EventArgs e)
{
c1.removeNew(Hello);
}
private void button3_Click(object sender, EventArgs e)
{
c1.remove(Hello);
}
}
A delegate can only be created from a method.
new EventHandler(evHandler) is shorthand for new EventHandler(evHandler.Invoke), because Invoke is the method on any delegate type that actually calls the delegate.
Since your _eh doesn't have evHandler.Invoke as a handler, that does nothing.
The syntax of EventHandler is often confusing. The key to understanding it is to realise it overrides the Equals operator such that one EventHandler is equal to another because they hold the same Delegate (or list of delegates) as the events target(s).
So;
var x = new EventHandler(myDelegate);
var y = new EventHandler(myDelegate);
Assert.IsTrue(x == y);
var x = new EventHandler(myDelegate);
var y = new EventHandler(anotherDelegate);
Assert.IsFalse(x == y);
When you += or -= a new instance of EventHandler such as
myHandler -= new EventHandler(someDelegate);
the new EventHander is passed into the decrement method of the myHandler instance where its target delegate is compared to those already in the list. Its the Target that is being removed, not the new EventHandler instance. Conversely when you;
myHandler += new EventHandler(someDelegate);
The someDelegate is added to the existing list of delegates on the target multicast delegate called myHandler. The new EventHandler is discarded and is just a cargo carrier for that single increment method call.
I'm quite new in C#, so I'm struggling with this more than two days. I hope that some one can help me out with this one.
Below some simplified code from my application.
I want to pass a List from Form1 to Form2 using delegate and event.
How can I do this? I read tons of explanations about events and delegates, but I still can't figure it out, how this really works.
Form1:
public delegate List<string> ProfileImportEventHandler();
public event ProfileImportEventHandler ProfileImported;
private void btnImport_Click(object sender, EventArgs e)
{
// raise an event
OnProfileImported();
}
protected virtual void OnProfileImported()
{
if (ProfileImported != null) // check if there are subscribers
{
ProfileImported();
}
}
Form2:
public partial class Form2 : Form
{
Form1 frm1;
public Form1()
{
// Constructor logic
frm1.ProfileChanged += new Form1.ProfileImportEventHandler(Form1_OnProfileImported);
}
}
List<string> Form1_OnProfileImported()
{
// TO DO
}
UPDATE
None of the solutions worked so far. Here is what I have already tried:
Form 2
// use generic list for profiles that will be imported from USB-Stick
private List<string> profilePaths = new List<string>();
public delegate void ProfileImportEventHandler(object sender, ProfileImportEventArgs e);
public event ProfileImportEventHandler ProfileImported;
public delegate void ImportButtonClickedEventHandler();
public event ImportButtonClickedEventHandler ButtonImportClicked;
public delegate void HaveDataDelegate(IList<string> data);
public event HaveDataDelegate HaveData;
//....
private void btnImport_Click(object sender, EventArgs e)
{
// do something...
// raise an event
var ea = new ProfileImportEventArgs(profilePaths);
OnProfileImported(ea);
OnButtonImportClicked();
// When there is data:
var copy = HaveData; // Use copy to avoid race conditions
if (copy != null)
{
copy(profilePaths);
}
// close form
this.Dispose();
}
protected virtual void OnProfileImported(ProfileImportEventArgs ea)
{
if (ProfileImported != null) // check if there are any subscribers
{
ProfileImported(this, ea);
}
}
protected virtual void OnButtonImportClicked()
{
if (ButtonImportClicked != null)
{
// fire event
ButtonImportClicked();
}
}
Form 1
public partial class frm_1 : Form
{
// child form
frm_2 frm2;
public frm_1()
{
InitializeComponent();
// do something...
// not sure if this is correct code and the correct place for it
frm2 = new frm_2();
frm2.ProfileImported += new frm_2.ProfileImportEventHandler(frm2_OnProfileImported);
//frm2.ProfileImported += frm2_OnProfileImported;
frm2.ButtonImportClicked += new frm_2.ImportButtonClickedEventHandler(frm2_ButtonImportClicked);
// In creation/init:
frm2.HaveData += DataFromForm2;
}
void frm2_OnProfileImported(object sender, ProfileImportEventArgs e)
{
// do something
}
void frm2_ButtonImportClicked()
{
// do something
}
private void DataFromForm2(IList<string> data)
{
// Process the data from Form2.
}
}
What am I still missing? Thank you for your help.
frm1.ProfileChanged += new Form1.ProfileImportEventHandler(Form1_OnProfileImported);
[…]
List<string> frmLoadProfileUSB_OnProfileImported()
First those names do not match. Second, with matching signatures you do not need (since C#2 if I recall correctly) to explicitly create the delegate. Thus:
frm1.ProfileChanged += frmLoadProfileUSB_OnProfileImported;
However, I think you have the event in the wrong place. It appears it is Form2 trying to pass data to Form1. Thus the event needs to be on Form2, with a delegate that is passed the data. Thus:
In Form2
public delegate void HaveDataDelegate(IList<string> data);
public event HaveDataDelegate HaveData;
// When there is data:
var copy = HaveData; // Use copy to avoid race conditions
if (copy != null) {
copy(data);
}
In Form1
// In creation/init:
Form2Instance.HaveData += DataFromForm2;
private void DataFromForm2(IList<string> data) {
// Process the data from Form2.
}
It's better not to use strong coupling.
So best solution here would be to store data in database or create proxy-object (class/struct).
like:
public (static) class ProfileChangesMonitor
{
...your logic here
}
If you want to use event handlers, you should follow the general pattern, defining a class that inherits EventArgs (supposing you want to involve a list in the event) in this way:
// Event Args
public class ProfileImportEventArgs : EventArgs {
private IList<string> list;
public ProfileImportEventArgs(IList<string> list) {
this.list = list;
}
public IList<string> List {
get {
return this.list;
}
}
}
// Event Handler Delegate
public delegate void ProfileImportEventHandler(object sender, ProfileImportEventArgs e);
// Form1:
public event ProfileImportEventHandler ProfileImported;
// ...
private void btnImport_Click(object sender, EventArgs e)
{
// raise an event
List<string> list = new List();
// Add something to list if needed
var ea = new ProfileImportEventArgs(list);
OnProfileImported(ea);
// Use ea.list here if necessary
}
protected virtual void OnProfileImported(ProfileImportEventArgs ea)
{
if (ProfileImported != null) { // check if there are subscribers
ProfileImported(this, ea);
}
}
// Form2:
public partial class Form2 : Form
{
Form1 frm1;
public Form1()
{
// Constructor logic
// TODO: Instantiate frm1 first.
frm1.ProfileImported += new Form1.ProfileImportEventHandler(Form1_OnProfileImported);
}
}
private void frmLoadProfileUSB_OnProfileImported(object sender, ProfileImportEventArgs e)
{
// Use and/or modify e.List if needed
}
I am creating a C# WinForms app that should closes the application using the voice command "exit".
However it gives me an exception:
Operator += cannnot be applied to operands of System speech or main method
In this code:
public partial class Form1 : Form
{
SpeechRecognitionEngine sRecongize = new SpeechRecognitionEngine();
private void Form1_Load(object sender, EventArgs e)
{
// Compiler error here:
sRecongize += sRecongize_SpeechRecognized;
}
private void sRecongize_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
if (e.Result.Text == "exit")
{
Application.Exit();
}
}
}
How can I subscribe to an event?
You need to subscribe to a specific event, in this case SpeechRecognized, not the entire class:
sRecongize.SpeechRecognized += sRecongize_SpeechRecognized;
Total n00b to C# and events although I have been programming for a while.
I have a class containing a text box. This class creates an instance of a communication manager class that is receiving frames from the Serial Port. I have this all working fine.
Every time a frame is received and its data extracted, I want a method to run in my class with the text box in order to append this frame data to the text box.
So, without posting all of my code I have my form class...
public partial class Form1 : Form
{
CommManager comm;
public Form1()
{
InitializeComponent();
comm = new CommManager();
}
private void updateTextBox()
{
//get new values and update textbox
}
.
.
.
and I have my CommManager class
class CommManager
{
//here we manage the comms, recieve the data and parse the frame
}
SO... essentially, when I parse that frame, I need the updateTextBox method from the form class to run. I'm guessing this is possible with events but I can't seem to get it to work.
I tried adding an event handler in the form class after creating the instance of CommManager as below...
comm = new CommManager();
comm.framePopulated += new EventHandler(updateTextBox);
...but I must be doing this wrong as the compiler doesn't like it...
Any ideas?!
Your code should look something like:
public class CommManager()
{
delegate void FramePopulatedHandler(object sender, EventArgs e);
public event FramePopulatedHandler FramePopulated;
public void MethodThatPopulatesTheFrame()
{
FramePopulated();
}
// The rest of your code here.
}
public partial class Form1 : Form
{
CommManager comm;
public Form1()
{
InitializeComponent();
comm = new CommManager();
comm.FramePopulated += comm_FramePopulatedHander;
}
private void updateTextBox()
{
//get new values and update textbox
}
private void comm_FramePopulatedHandler(object sender, EventArgs e)
{
updateTextBox();
}
}
And here's a link to the .NET Event Naming Guidelines mentioned in the comments:
MSDN - Event Naming Guidelines
Here you have "The Simplest C# Events Example Imaginable".
public partial class Form1: Form
{
CommManager comm;
public Form1()
{
InitializeComponent();
comm = new CommManager();
comm.OnFramePopulated += new EventHandler(updateTextBox);
}
private void updateTextBox(object sender, EventArgs ea)
{
//update Textbox
}
}
class CommManager
{
public EventHandler OnFramePopulated;
public void PopulateFrame()
{
OnFramePopulated(this, null);
}
}
Yes - change the signature of updateTextBox to :
private void updateTextBox(object sender, Eventargs ea)
Although that might not be the best design. Things would look a lot neater if you wrote a proper event handler, and then called updateTextBox from there...
A simple scenario: a custom class that raises an event. I wish to consume this event inside a form and react to it.
How do I do that?
Note that the form and custom class are separate classes.
public class EventThrower
{
public delegate void EventHandler(object sender, EventArgs args) ;
public event EventHandler ThrowEvent = delegate{};
public void SomethingHappened() => ThrowEvent(this, new EventArgs());
}
public class EventSubscriber
{
private EventThrower _Thrower;
public EventSubscriber()
{
_Thrower = new EventThrower();
// using lambda expression..could use method like other answers on here
_Thrower.ThrowEvent += (sender, args) => { DoSomething(); };
}
private void DoSomething()
{
// Handle event.....
}
}
Inside your form:
private void SubscribeToEvent(OtherClass theInstance) => theInstance.SomeEvent += this.MyEventHandler;
private void MyEventHandler(object sender, EventArgs args)
{
// Do something on the event
}
You just subscribe to the event on the other class the same way you would to an event in your form. The three important things to remember:
You need to make sure your method (event handler) has the appropriate declaration to match up with the delegate type of the event on the other class.
The event on the other class needs to be visible to you (ie: public or internal).
Subscribe on a valid instance of the class, not the class itself.
Assuming your event is handled by EventHandler, this code works:
protected void Page_Load(object sender, EventArgs e)
{
var myObj = new MyClass();
myObj.MyEvent += new EventHandler(this.HandleCustomEvent);
}
private void HandleCustomEvent(object sender, EventArgs e)
{
// handle the event
}
If your "custom event" requires some other signature to handle, you'll need to use that one instead.