Wiring and unwiring events in C# with arguments - c#

i am trying to make use of events in C#. I am really new to events. Following is my code.
public void GetVoltage(Object objName, Object objCcaVar)
{
DynamicSystemVariable mysys = new DynamicSystemVariable("VTS::M9_Ch3", "AvgVoltage");
mysys.ValueChanged += (sender, e) => mysys_ValueChanged(sender, e, ""); ;
}
void mysys_ValueChanged(object sender, EventArgs e,String name)
{
DynamicSystemVariable mysys = (DynamicSystemVariable)sender;
Output.WriteLine(mysys.GetValue().ToString());
Output.WriteLine("System Variable Changed");
if (_unwireEvent)
mysys.ValueChanged -= mysys_ValueChanged;
}
It gives me following error on the line where i am unwiring it.
No overload for 'mysys_ValueChanged' matches delegate 'System.EventHandler'
I will appreciate if somebody can help me out.
Thanks
Tom

Instead of sending name as a seperate parameter, create a new class deriving from EventArgs and add name parameter to this class as a property. Something like;
public class MyEventArgs : EventArgs
{
public string Name {get; private set;}
public MyEventArgs(EventArg e, string name)
{
this.Name = name;
}
}
mysys.ValueChanged += mysys_ValueChanged(sender, new MyEventArgs("some name"));
Also do not forget to change the signiture of mysys_ValueChanged.
Note that this is just a workaround, and proper way is defining a new delegate which uses MyEventArgs and using a seperate handling method instead of an inline method.

The problem is that you haven't register mysys_ValueChanged. You registered an anonymous method.
You have to change your code to:
public void GetVoltage(Object objName, Object objCcaVar)
{
DynamicSystemVariable mysys = new DynamicSystemVariable("VTS::M9_Ch3", "AvgVoltage");
mysys.ValueChanged += this.OnEvent;
}
private void OnEvent(object sender, EventArgs e)
{
mysys_ValueChanged(sender, e, "");
}
void mysys_ValueChanged(object sender, EventArgs e,String name)
{
DynamicSystemVariable mysys = (DynamicSystemVariable)sender;
Output.WriteLine(mysys.GetValue().ToString());
Output.WriteLine("System Variable Changed");
if (_unwireEvent)
mysys.ValueChanged -= OnEvent; // Unregister what you've registered.
}
EDIT
Having new input it could be solved that way:
public void GetVoltage(Object objName, Object objCcaVar)
{
DynamicSystemVariable mysys = new DynamicSystemVariable("VTS::M9_Ch3", "AvgVoltage");
EventHandler<EventArgs> handler = null;
handler = (s, e) => mysys_ValueChanged(s, e, "", handler);
mysys.ValueChanged += handler;
}
void mysys_ValueChanged(object sender, EventArgs e, String name, EventHandler<EventArgs> handler)
{
DynamicSystemVariable mysys = (DynamicSystemVariable)sender;
Output.WriteLine(mysys.GetValue().ToString());
Output.WriteLine("System Variable Changed");
if (_unwireEvent)
mysys.ValueChanged -= handler; // Unregister what you've registered.
}
I haven't tried it but I think this could work - but in my opinion it's hacked.

Related

Prevent function from being invoked from within itself [duplicate]

My application in C# has a Textbox with a txt_TextChanged event.
private void txt_TextChanged(object sender, EventArgs e)
{
//Do somthin
}
But there's one specific part that I want to change txt.Text without firing the txt_TextChanged event.
txt.Text ="somthing" //Don't fire txt_TextChanged
How can I do that?
There is no direct way to prevent the raising of events for the text property, however your event handler can use a flag to determine weather or not to perform a task. This i likely to be more efficient than attaching and detaching the event handler. This can be done by a variable within the page or even a specialized class wrapper
With a variable:
skipTextChange = true;
txt.Text = "Something";
protected void TextChangedHandler(object sender, EventArgs e) {
if(skipTextChange){ return; }
/// do some stuffl
}
With specialized event handler wrapper
var eventProxy = new ConditionalEventHandler<EventArgs>(TextBox1_TextChanged);
TextBox1.TextChanged = eventProxy.EventAction;
eventProxy.RaiseEvents = false;
TextBox1.Text = "test";
public void TextBox1_TextChanged(object sender, EventArgs e) {
// some cool stuff;
}
internal class ConditionalEventHadler<TEventArgs> where TEventArgs : EventArgs
{
private Action<object,TEventArgs> handler;
public bool RaiseEvents {get; set;}
public ConditionalEventHadler(Action<object, TEventArgs> handler)
{
this.handler = handler;
}
public void EventHanlder(object sender, TEventArgs e) {
if(!RaiseEvents) { return;}
this.handler(sender, e);
}
}
txt.TextChanged -= textBox1_TextChanged; // dettach the event handler
txt.Text = "something"; // update value
txt.TextChanged += textBox1_TextChanged; // reattach the event handler
You can extend text box and introduce there a new property that will not trigger the TextChanged event.
class SilentTextBox : TextBox
{
// if true, than the TextChanged event should not be thrown
private bool Silent { get; set; }
public string SilentText
{
set
{
try
{
Silent = true;
Text = value;
}
finally
{
Silent = false;
}
}
}
protected override void OnTextChanged(EventArgs e)
{
// raise event only if the control is in non-silent state
if (!Silent)
{
base.OnTextChanged(e);
}
}
}
try this extension method
public static class TextBoxExt
{
private static readonly FieldInfo _field;
private static readonly PropertyInfo _prop;
static TextBoxExt()
{
Type type = typeof(Control);
_field = type.GetField("text", BindingFlags.Instance | BindingFlags.NonPublic);
_prop = type.GetProperty("WindowText", BindingFlags.Instance | BindingFlags.NonPublic);
}
public static void SetText(this TextBox box, string text)
{
_field.SetValue(box, text);
_prop.SetValue(box, text, null);
}
}
you can use textbox.SetText("...") to change text and the TextChanged event will not be fired.
A quick and dirty way is to do an
ctrl.Enable = false;
ctrl.Text = "Something";
ctrl.Enable = true;
and then in the OnChange event, encapsulate the offending code with a
if (ctrl.Enabled) {
// offending code here.
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
EventHandler TextChanged_EventHandler = new EventHandler(textBox1_TextChanged);
textBox1.TextChanged -= TextChanged_EventHandler;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
MessageBox.Show("BUG");
}
}
I found a simple method, suitable for event handlers and controls that are not in the same .cs file
public static void SetTextWithoutRaiseEvent(this TextBox textBox, string content)
{
var scroll = textBox.Template.FindName("PART_ContentHost", textBox);
(scroll as ScrollViewer).Content = content;
}

-= new EventHandler(Method) vs -= Method when passing method as parameter

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.

How to get event name in event handler [duplicate]

This question already has answers here:
How to get event name in called method
(2 answers)
Closed 8 years ago.
I'm curious if is possible to get event name in event handler?
I'm pretty sure, that it's possible, can you help me find solution?
Ex:
public class Boy
{
public event EventHandler Birth;
public event EventHandler Die;
}
public class Mother
{
public Mother()
{
Boy son = new Boy();
son.Birth += son_Handler;
son.Die += son_Handler;
}
void son_Handler(object sender, EventArgs e)
{
// how to get event name (Birth/Die)?
throw new NotImplementedException();
}
}
I'm curious if is possible to get event name in event handler?
No, it's not. The event handler is just a method. It could be invoked directly, not in the context of any event.
What you could do is have:
public Mother()
{
Boy son = new Boy();
son.Birth += (sender, e) => Handler("Birth", sender, e);
son.Die += (sender, e) => Handler("Die", sender, e);
}
void Handler(string description, object sender, EventArgs e)
{
Log("I'm in the {0} event", description);
throw new NotImplementedException();
}
You need to inherit EventArgs class and add necessary fields.
class MyArgs : EventArgs
{
public string What { get; set; }
}
delegate void MyHandler(object sender, MyArgs e);
. . .
var myEvent = birthEvent;
if (myEvent != null)
myEvent(new MyArgs { What = "Birth"};

how to remove the listening of callback on anonymous method?

I wrote some class:
public class A
{
public A()
{
serviceAdapter.CompletedCallBackEvent += new EventHandler( foo );
.
.
.
}
void foo(object sender, EventArgs e)
{
serviceAdapter.CompletedCallBackEvent -= new EventHandler( foo );
}
}
Now, i want to change this callback listener with some anonymous - but i don't know how to remove the callback listener in the anonymous method .
class A
{
public A()
{
serviceAdapter.CompletedCallBackEvent += delegate( object sender, EventArgs ee )
{
... need to remove the listener to the event.
}
}
}
You could simply assign your delegate/handler to a private variable.
private EventHander _handler = null;
public A()
{
_handler = delegate( object sender, EventArgs ee)
{
ServiceAdapter.CompletedCallBackEvent -= _handler;
};
ServiceAdapter.CompletedCallBackEvent += _handler;
}
You can't remove the anonymous delegate like that. See MSDN article on anonymous delegates. Also worth reading this article
You may be able to do:
public A()
{
EventHandler myHandler = null;
myHandler = new EventHandler(delegate(object s, EventArgs e)
{
serviceAdapter.CompletedCallbackEvent -= myHandler;
});
serviceAdapter.CompletedCallBackEvent += myHandler;
}

How to subscribe to other class' events in C#?

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.

Categories

Resources