String to event - c#

I'm trying to programmatically call a function with event.
How to convert string to a event in general? My problem is actually not knowing How to do this?
How to convert str to event?
str = "test1";
// UserControlsBackgroundEventArgs = EventArgs
EventArgs arg = (EventArgs)str; --> ?
UserControlsBackgroundOutput(str);
//function
private string CLICKNAME = "test0";
private void UserControlsBackgroundOutput(EventArgs e)
{
if (CLICKNAME == e.output)
return;
if (e.output == "test1"){}
}
Error solved:
I had to do
UserControlsBackgroundEventArgs arg = new UserControlsBackgroundEventArgs(CLICKNAME);
instead of
UserControlsBackgroundEventArgs arg = new (UserControlsBackgroundEventArgs)(CLICKNAME);

i've written a code that mimic you code, hopefully you will find it useful:
public class UserControlsBackgroundEventArgs
{
public string output;
public UserControlsBackgroundEventArgs(string up)
{
output = up;
}
}
public delegate void UserControlsBackgroundOutputHandle(UserControlsBackgroundEventArgs e);
public class testEvent
{
public event UserControlsBackgroundOutputHandle UserControlsBackgroundOutput;
public void DoSomeThings()
{
// do some things
if (UserControlsBackgroundOutput != null)
{
string str = "test1";
UserControlsBackgroundEventArgs arg = new UserControlsBackgroundEventArgs(str);
UserControlsBackgroundOutput(arg); // you've done that with str, whitch makes me
// you don't know what the event param is
}
}
}
public class test
{
private testEvent myTest;
private const string CLICKNAME = "whatever"; // i don't know what you want here
public test()
{
myTest = new testEvent();
myTest.UserControlsBackgroundOutput += UserControlsBackgroundOutput;
}
void UserControlsBackgroundOutput(UserControlsBackgroundEventArgs e)
{
if (CLICKNAME == e.output)
return;
if (e.output == "test1")
{
}
}
}

Your event class needs to have a constructor accepting a string. Then you will be able to create a new event instance using a string. You can't "convert" a string to an instance of the event class. If the event class comes from a library or sth and doesn't have a string constructor, you can subclass it, implement a string constructor and override the output property.

If you want this kind of conversion to be possible, you have to use an explicit operator:
public static explicit operator UserControlsBackgroundEventArgs(string s)
{
var args = new UserControlsBackgroundEventArgs();
args.output = s;
return args;
}
This is only possible with a new class, not with EventArgs, because you can't change the code of that class.

Your UserControlsBackgroundEventArgs Implementation could provide implicit/explicit casts.
Take a look at implicit keyword documentation
However, the answer from Wojciech Budniak is better.

Related

Passing delegate and parameters to be used in the delegate to function [duplicate]

Let's say I want to pass some extra data when assigning an event handler. Consider the following code:
private void setup(string someData)
{
Object.assignHandler(evHandler);
}
public void evHandler(Object sender)
{
// need someData here!!!
}
How would I go about getting someData into my evHandler method?
private void setup(string someData)
{
Object.assignHandler((sender) => evHandler(sender,someData));
}
public void evHandler(Object sender, string someData)
{
// need someData here!!!
}
I had a hard time figuring out #spender's example above especially with: Object.assignHandler((sender) => evHandler(sender,someData)); because there's no such thing as Object.assignHandler in the literal sense. So I did a little more Googling and found this example. The answer by Peter Duniho was the one that clicked in my head (this is not my work):
snip
The usual approach is to use an anonymous method with an event handler
that has your modified signature. For example:
void Onbutton_click(object sender, EventArgs e, int i) { ... }
button.Click += delegate(object sender, EventArgs e)
{ Onbutton_click(sender, e, 172); };
Of course, you don't have to pass in 172, or even make the third parameter
an int. :)
/snip
Using that example I was able to pass in two custom ComboBoxItem objects to a Timer.Elapsed event using lambda notation:
simulatorTimer.Elapsed +=
(sender, e) => onTimedEvent(sender, e,
(ComboBoxItem) cbPressureSetting.SelectedItem,
(ComboBoxItem) cbTemperatureSetting.SelectedItem);
and then into it's handler:
static void onTimedEvent(object sender, EventArgs e, ComboBoxItem pressure, ComboBoxItem temperature)
{
Console.WriteLine("Requested pressure: {0} PSIA\nRequested temperature: {1}° C", pressure, temperature);
}
This isn't any new code from the examples above, but it does demonstrate how to interpret them. Hopefully someone like me finds it instructive & useful so they don't spend hours trying to understand the concept like I did.
This code works in my project (except for a non-thread-safe exception with the ComboBoxItem objects that I don't believe changes how the example works). I'm figuring that out now.
Captured variables:
private void setup(string someData)
{
Object.assignHandler((sender,args) => {
evHandler(sender, someData);
});
}
public void evHandler(Object sender, string someData)
{
// use someData here
}
Or (C# 2.0 alternative):
Object.assignHandler((EventHandler)delegate(object sender,EventArgs args) {
evHandler(sender, someData);
});
you can try doing this:
string yourObject;
theClassWithTheEvent.myEvent += (sender, model) =>
{
yourObject = "somthing";
}
My question that was similar was marked a duplicate so thought I'd add an answer here since it won't let me on my question.
class Program
{
delegate void ComponentEventHandler(params dynamic[] args);
event ComponentEventHandler onTest;
static void Main(string[] args)
{
Program prg = new Program();
// can be bound to event and called that way
prg.onTest += prg.Test;
prg.onTest.Invoke("What", 5, 12.0);
Console.ReadKey();
}
public void Test(params dynamic[] values)
{
// assign our params to variables
string name = values[0];
int age = values[1];
double value = values[2];
Console.WriteLine(name);
Console.WriteLine(age);
Console.WriteLine(value);
}
}
Well, the simplest method id to make someData a member variable like so:
public class MyClass
{
private string _eventData;
private void setup(string someData)
{
_eventData = someData;
Object.assignHandler(evHandler);
}
public void evHandler()
{
// do something with _eventData here
}
}
I'm not sure that's the best way to do it, but it really depends on the event type, the object, etc.
You could create a custom object having additional properties based on Object:
class CustomObject : Object
{
public string SomeData;
}
private void setup(string someData)
{
CustomObject customObject = new CustomObject { SomeData = someData };
CustomObject.assignHandler(evHandler);
}
public void evHandler(Object sender)
{
string someData = ((CustomObject)sender).SomeData;
}
If the data should not be changed anymore after initialization, you could also add a custom constructor, for example.
Here is my one-line solution that pass extra parameters to a timer handler.
private void OnFailed(uint errorCode, string message)
{
ThreadPoolTimer.CreateTimer((timer) => {
UI.ErrorMessage = string.Format("Error: 0x{0:X} {1}", errorCode, message);
}, System.TimeSpan.FromMilliseconds(100));
}
This solution offers a way to pass extra parameters to an event handler while still allowing to unsubscibe:
Within the Subscribe() function of my example I create an Action that invokes a lambda function that supplies my event handler with the event args and my extra parameter. I then store this Action in a dictionary. When I want to unsubscribe, I can use the stored Actions to do so.
This works, I read the length of listeners before and after unsubscribing and it did decrease - you can unsubscribe again without problems.
public class Player
{
public Action<JumpInfo> OnJump;
}
public class PlayerJumpListener
{
public List<Player> MyPlayerList;
private Dictionary<Player, Action<JumpInfo>> _jumpActionsByPlayer = new Dictionary<Player, Action<JumpInfo>>();
private void Subscribe()
{
foreach (Player player in MyPlayerList)
{
Action<JumpInfo> playerJumpAction = (jumpInfo) => HandlePlayerJump(jumpInfo, player);
player.OnJump += playerJumpAction;
_jumpActionsByPlayer.Add(player, playerJumpAction);
}
}
private void Unsubscibe()
{
foreach (KeyValuePair<Player, Action<JumpInfo>> kvp in _jumpActionsByPlayer)
{
kvp.Key.OnJump -= kvp.Value;
}
}
private void HandlePlayerJump(JumpInfo jumpInfo, Player player)
{
// player jumped
}
}
I scoured the internet before a coworker kindly helped me, and boy I felt dumb. Brackets is the solution for the EventHandler.
Ex.
event EventHandler<(int, bool)> EventName;
and then pick it up with:
private void Delegate_EventName(object sender, (int, bool) e)
you can then access the info:
var temp = e.Item1;<br>
var temp2 = e.Item2;<br>
or you can add names as you would expect for parameters and call them via e:
private void Delegate_EventName(object sender, (int num, bool val) e)
you can then access the info:
var temp = e.num;
var temp2 = e.val;

get publisher class field from sender

I want to get my field >>> NumberOfElementsInMyList from sender, How Can I do it? I couldn't find this kind of question here (what I have seen, was about windows forms), so ...
class Program
{
static void Main(string[] args)
{
Publisher PublisherObject = new Publisher();
PublisherObject.NumberAdded += PublisherObject_NumberAdded;
PublisherObject.AddNumber(int.Parse(Console.ReadLine());
}
static void PublisherObject_NumberAdded(object sender, EventArgs e)
{
//I want to write on the console "NumberOfElementsInMylist"
//I tried:
//sender.NumberOfElementsInMylist -- not works
//Publisher obj=(publisher)sender and then sender.NumberOfElementsInMylist
//not works
Console.WriteLine("number of elements in list is ---> "+ ???? );
}
}
class Publisher
{
public event EventHandler NumberAdded;
public int NumberOfElementsInMyList;
List<int> MyList=new List<int>();
public void AddNumber(int NumberToAdd)
{
MyList.Add(NumberToAdd);
NumberOfElementsInMyList = MyList.Count;
NumberAdded(this, new EventArgs());
}
}
To literally answer your question, the reason why you can't access the NumberOfElementsInMyList field is because when you create the EventArgs, your instance of Publisher is being cast as an object (which you can do since all classes inherit from object.) So to see the properties (or field) of Publisher, you have to cast the sender as Publisher.
var numberOfElements = ((Publisher)sender).NumberOfElementsInMyList;
A downside to this is that hypothetically, sender might not be a Publisher. Because sender is an object, it could technically be anything.
You can also create your own event handler delegate and event args instead of using the boilerplate EventHandler delegate.
public delegate void NumberAdded(Publisher source, NumberAddedEventArgs eventArgs);
public class NumberAddedEventArgs : EventArgs
{
public NumberAddedEventArgs(int numberAdded, numberOfItemsInList)
{
NumberAdded = numberAdded;
NumberOfItemsInList = numberOfItemsInList;
}
public int NumberAdded { get; private set; }
public int NumberOfItemsInList { get; private set; }
}
public class Publisher
{
public event EventHandler NumberAddedEvent;
public int NumberOfElementsInMyList;
List<int> MyList = new List<int>();
public void AddNumber(int NumberToAdd)
{
MyList.Add(NumberToAdd);
NumberOfElementsInMyList = MyList.Count;
NumberAddedEvent?.Invoke(this, new NumberAddedEventArgs(NumberToAdd,
NumberOfElementsInMyList));
}
}
var numberOfElementsInList = args.NumberOfItemsInList; // much better!
The (object sender, EventArgs args) is a strange convention. In any other scenario we would create strongly-typed methods and delegates. But in this case there's a tendency to use something that's not strongly-typed because it's a convention.
You can simply cast the sender, can't you?
var publisher = (Publisher)sender;
Console.WriteLine(publisher.NumberOfElementsInMyList);
Or more safely:
Console.WriteLine(
(sender as Publisher)?.NumberOfElementsInMyList?.ToString() ?? "sender is not a publisher!");

Visual C# returning value from an event handler

I have a form that has a button to get a method executed in another class.
Code on the form:
public delegate void CustomPreviewCreate();
public static event CustomPreviewCreate CustomPreviewCreate_Do;
private void CreatePreview()
{
if (CustomPreviewCreate_Do !=null)
{
CustomPreviewCreate_Do();
}
}
This event then gets handled in another class. What I would like to achieve is that I can feed back to the form some form of return value if the method correctly executed.
What I tried so far does not get me the result.
Here is the code:
public void Initialize()
{
SubAsstViewPartControl.CustomPreviewCreate_Do += SubAsstViewPartControl_CustomPreviewCreate_Do;
// this gives me a the compiler error that the return type is wrong
}
private bool SubAsstViewPartControl_CustomPreviewCreate_Do()
{
// do stuff
return false;
}
Is there any direct way to return value from an event handler or I need to use a separate static field to store the event result in?
Update:
Per #Jon's comment, which seemed the simplest to me, I added an answer below demonstrating the simplest approach.
The common approach is to encapsulate your value in the type of EventArgs your event expects. For example, the Framework's CancelEventArgs contains a settable bool Cancel property, allowing each CancelEventHandler to assign a value. The sender can then read the property after the event has been invoked. You could also use a container-like EventArgs class if you want to collect separate values from individual event handlers. For example:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
public class SingleValueEventArgs : EventArgs
{
public int Value { get; set; }
}
public class MultiValueEventArgs : EventArgs
{
private List<int> _values = new List<int>(); // Private to prevent handlers from messing with each others' values
public IEnumerable<int> Values
{
get { return _values; }
}
public void AddValue(int value) { _values.Add(value); }
}
public class Exposer
{
public event EventHandler<SingleValueEventArgs> WantSingleValue;
public event EventHandler<MultiValueEventArgs> WantMultipleValues;
public void Run()
{
if (WantSingleValue != null)
{
var args = new SingleValueEventArgs();
WantSingleValue(this, args);
Console.WriteLine("Last handler produced " + args.Value.ToString());
}
if (WantMultipleValues != null)
{
var args = new MultiValueEventArgs();
WantMultipleValues(this, args);
foreach (var value in args.Values)
{
Console.WriteLine("A handler produced " + value.ToString());
}
}
}
}
public class Handler
{
private int _value;
public Handler(Exposer exposer, int value)
{
_value = value;
exposer.WantSingleValue += exposer_WantSingleValue;
exposer.WantMultipleValues += exposer_WantMultipleValues;
}
void exposer_WantSingleValue(object sender, SingleValueEventArgs e)
{
Console.WriteLine("Handler assigning " + _value.ToString());
e.Value = _value;
}
void exposer_WantMultipleValues(object sender, MultiValueEventArgs e)
{
Console.WriteLine("Handler adding " + _value.ToString());
e.AddValue(_value);
}
}
class Program
{
static void Main(string[] args)
{
var exposer = new Exposer();
for (var i = 0; i < 5; i++)
{
new Handler(exposer, i);
}
exposer.Run();
}
}
}
Per Jon Skeet's comment, which seemed the simplest to me, the simplest approach seems to be as follows:
public delegate bool CustomPreviewCreate(); // here we declare a return type
public static event CustomPreviewCreate CustomPreviewCreate_Do;
private void CreatePreview()
{
if (CustomPreviewCreate_Do !=null)
{
bool returnval = CustomPreviewCreate_Do();
}
}
And then:
// the method is declared to return the same type
bool SubAsstViewPartControl_CustomPreviewCreate_Do()
{
// do stuff
return true; // return the value of the type declared
}

creating a template method in a static method

I created a class InputBox that only has one method, which is static:
Public static Show(string i_Prompt)
this method creates an InputBoxForm and gives the form a method for this property: public Predicate<char> isKeyValid { get; set; }
which runs in here:
private void textBoxInput_KeyPress(object sender, KeyPressEventArgs e)
{
if (isKeyValid != null)
{
e.Handled = !isKeyValid(e.KeyChar);
}
}
the idea is that a developer will derive my class and create he's own logic on how to deal with getting characters from the user.
this implementation of the static Show method is:
public static string Show(string i_Prompt)
{
string input = string.Empty;
using (InputBoxForm form = new InputBoxForm(i_Prompt))
{
form.isKeyValid = s_Instance.keyValidationLogic;
if (form.ShowDialog() == DialogResult.OK)
{
input = form.Input;
}
}
return input;
}
the template is keyValidationLogic. (which return true for all the keys in the base InputBox)
the problem, as you can see that i cannot overwrite a static method.
how would I implement a template method in a static method?
I have to create an instance of the Input Box, but I want to use the derived class instance
the class InputBox is not static. i want it to be derived, so developers will be able to customize the logic of the input box.
thanks
I'm not sure your approach is the best way to to about this, but you should be able to solve your issue in the following way.
You can do this with ordinary inheritance:
class InputBox
{
protected virtual bool ValidateKey(char key)
{
// Allow anything
return true;
}
public string Show(string i_Prompt)
{
using (InputBoxForm form = new InputBoxForm(i_Prompt))
{
form.isKeyValid = this.ValidateKey;
if (form.ShowDialog() == DialogResult.OK)
{
return form.Input;
}
}
return string.Empty;
}
}
class DigitInputBox : InputBox
{
protected override bool ValidateKey(char key)
{
return key >= '0' && key <= '9';
}
}
To use:
(new MyCustomizedInputBox()).Show("Numbers only, please!");

error learning how to use custom events

i'm learning how to use custom events in c#, but i get some errors
i get "An object reference is required for the nonstatic field, method, or property" in the bold words
so i tried following this
but case 1 couldn't be tried 'cause TypeChanged is already a nonstatic method (i think)
in case 2 i get "impossible to acces BicycleType as an instance reference, qualify it as a type"
public class Bicycle
{
public event EventHandler TypeChanged;
private string type;
...
public string BicycleType {
get { return this.type; }
set {
this.type = value;
if (this.TypeChanged != null)
this.TypeChanged( this, new EventArgs() );
}
}
public Bicycle() {}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("heila!");
Bicycle istanza = new Bicycle();
istanza.TypeChanged += new EventHandler(**istanza_TypeChanged**);
istanza.BicycleType = "io";
Console.WriteLine("io");
}
void istanza_TypeChanged(object sender, EventArgs e) {
Console.WriteLine("rofkd");
}
}
the tutorial i followed told me i can use events "as" methods, maybe i'm wrong here?
the code is completely similar to te tutorial code
sorry for my bad english and thanks in advance
As you are registering the event from the main method, which is static, the event handler (istanza_TypeChanged) has to be made static too.
You problem is that Main is static and can therefore not access nonstatic members of the class Program. However you try to access istanza_TypeChanged. That is what is causing your exception.
You have to make istanza_TypeChanged static too to solve the issue
class Program
{
static void Main(string[] args)
{
Console.WriteLine("heila!");
Bicycle istanza = new Bicycle();
istanza.TypeChanged += new EventHandler(**istanza_TypeChanged**);
istanza.BicycleType = "io";
Console.WriteLine("io");
}
static void istanza_TypeChanged(object sender, EventArgs e)
{
Console.WriteLine("rofkd");
}
}
Register the event from a non-static context or change your event to be static.
Change istanza_TypeChanged to the following:
private static void istanza_TypeChanged(object sender, EventArgs e)
{
Console.WriteLine("rofkd");
}
The following fired the event for me:
public class Bicycle
{
public event EventHandler TypeChanged;
private string type;
public string BicycleType
{
get { return this.type; }
set
{
this.type = value;
if (this.TypeChanged != null)
this.TypeChanged(this, new EventArgs());
}
}
public Bicycle()
{
}
private class Program
{
private static void Main(string[] args)
{
Console.WriteLine("heila!");
Bicycle istanza = new Bicycle();
istanza.TypeChanged += istanza_TypeChanged;
istanza.BicycleType = "io";
Console.WriteLine("io");
}
private static void istanza_TypeChanged(object sender, EventArgs e)
{
Console.WriteLine("rofkd");
}
}
}

Categories