Passing additional parameters to event Action; - c#

Definittion of ProgressChanged:
// Summary:
// Event called whenever the progress of the upload changes.
public event Action<IUploadProgress> ProgressChanged;
public void insertFile(String filePath)
{
//.. some code
insertRequest.ProgressChanged += Upload_ProgressChanged;
}
public void Upload_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
{
//.. I need filePath from insertFile() here!
}
How to pass additional paramtres to Upload_ProgressChanged ?
I did the following:
public void insertFile(String filePath)
{
//.. some code
ProgressChangedEventArgs args = new ProgressChangedEventArgs()
{
path = filePath
};
insertRequest.ProgressChanged += Upload_ProgressChanged;
}
static void Upload_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
public class ProgressChangedEventArgs : EventArgs
{
public string path { get; set; }
}
And I have mistake Can not implicitly convert type 'void' to 'System.Action<Google.Apis.Upload.IUploadProgress>'

Instead of using an event you can capture the variable inside a closure
insertRequest.ProgressChanges += progress => { /* Do something with filePath here */ };

Firstly, define the EventArgs class - this will let you have whatever information you like...
public class ProgressChgEventArgs : System.EventArgs
{
public string Name { get;set; }
public int InstanceId { get;set; }
public ProgressChgEventArgs(string name, int id)
{
Name = name;
InstanceId = id;
}
}
Next, create the event that consumes these arguments:
public event EventHandler<ProgressChgEventArgs> ProgressChanged;
Then, have an 'On....' method that invokes the handlers
public void OnProgressChanged(ProgressChgEventArgs e)
{
var handler = new EventHandler<ProgressChgEventArgs>();
if (handler != null)
handler(this, e);
}
Now, at the relevant point in your code (presumably when the progress changes!) you call OnProgressChanged(), passing in an appropriate instance of the ProgressChgEventArgs:
private void Progress(string caller, int callerId)
{
var arguments = new ProgressChgEventArgs(caller, callerId);
OnProgressChanged(arguments);
}

Related

EventHandler bubbling up

I want to bubble up a message through classes. I used events and did this:
public class TopLevel{
public event EventHandler<string> Message;
public MiddleLevel mid;
public TopLevel()
{
mid.Message += (s, e) => { Message(s, e) };
}
}
public class MiddleLevel{
public event EventHandler<string> Message;
public BottomLevel bottom;
public MiddleLevel()
{
bottom.Message += (s, e) => { Message(s, e) };
}
}
public class BootomLevel{
public event EventHandler<string> Message;
public void DoSomething()
{
Message?.Invoke(this, "I did it.");
}
}
public class Handler{
public void HandleEvent(TopLevel top)
{
top.Message += PrintMessage;
}
public void PrintMessage(object sender, string message)
{
Console.WrteLine(message);
}
}
Also tried changing constructor to lambda expressions like this:
public class TopLevel{
public event EventHandler<string> Message;
public MiddleLevel mid;
public TopLevel()
{
mid.Message += (s, e) => { Message?.Invoke(s, e); };
}
}
public class MiddleLevel{
public event EventHandler<string> Message;
public BottomLevel bottom;
public MiddleLevel()
{
bottom.Message += (s, e) => { Message?.Invoke(s, e); };
}
}
public class BootomLevel{
public event EventHandler<string> Message;
public void DoSomething()
{
Message?.Invoke(this, "I did it.");
}
}
public class Handler{
public void HandleEvent(TopLevel top)
{
top.Message += PrintMessage;
}
public void PrintMessage(object sender, string message)
{
Console.WrteLine(message);
}
}
Codes above doesn't print any message. Even if I handle event in MiddleLevel class, I still get no message. I assume it is because message call is made in constructor (Even though linq quarries update themselves)? If I handle event in Handle class straight from BottomLevel class, it obviously - works. But I need to bubble the message up, I can't think of any other way to to this, because of how classes are constructed. Is it even possible to do what I have in mind with a standard Eventhandler class? If so than how? Should I just make an event class myself as in one of the sites i refered?
I refered to these sites:
What is the preferred way to bubble events?
https://www.carlosble.com/2016/04/event-bubbling-in-c/
Updated answer:
If you want 'Handler' to be triggered you will have to make sure that 'BottomLevel' falls within the hierarchy of the 'TopLevel' class being passed to the handler, this can be done via dependency injection (DI).
If 'BottomLevel' instantiates it's own classes (no DI) then it will not know about 'Handler', so handler will never be triggered.
If you comment out the DI setup and un-comment the 'BottomLevel' instantiation you can see the different behaviors.
class Program
{
static void Main(string[] args)
{
//setup the classes (dependency injection)
TopLevel topLevel = new TopLevel();
MiddleLevel middleLevel = new MiddleLevel(topLevel);
BottomLevel bottomLevel = new BottomLevel(middleLevel);
//set up the handler
Handler h = new Handler(topLevel);
//using this will not link to 'Handler' as there is no relation between this bottom and top
//BottomLevel bottomLevel = new BottomLevel();
//trigger the bottom class
bottomLevel.TriggerBottom();
//or
bottomLevel.DoSomething(null, "call from main");
Console.ReadLine();
}
}
public class Handler
{
TopLevel _topLevel;
public Handler(TopLevel topLevel)
{
if (topLevel != null)
_topLevel = topLevel;
_topLevel.Message += _topLevel_Message;
}
private void _topLevel_Message(object sender, string e)
{
Console.WriteLine($"handler triggered : {e}");
}
}
public class TopLevel
{
public event EventHandler<string> Message;
public TopLevel()
{ }
public void TriggerTop()
{
Message?.Invoke(this, "origin top");
}
public void DoSomething(object sender, string e)
{
Console.WriteLine($"Do something at top : {e}");
Message?.Invoke(this, e);
}
}
public class MiddleLevel
{
TopLevel _TopLevel;
public event EventHandler<string> Message;
public MiddleLevel(TopLevel topLevel) : this()
{
_TopLevel = topLevel;
}
public MiddleLevel()
{
if (_TopLevel == null)
_TopLevel = new TopLevel();
//subscribe this message to bottom message event method
Message += (s, e) => { _TopLevel.DoSomething(s, e); };
}
public void TriggerMiddle()
{
Message?.Invoke(this, "origin middle");
}
public void DoSomething(object sender, string e)
{
Console.WriteLine($"do something in middle : {e}");
//invoke the event(s)
Message?.Invoke(sender, e);
}
}
public class BottomLevel
{
MiddleLevel _MidLevel;
public event EventHandler<string> Message;
public BottomLevel(MiddleLevel midLevel) : this()
{
_MidLevel = midLevel;
}
public BottomLevel()
{
if (_MidLevel == null)
_MidLevel = new MiddleLevel();
////here you assign it
Message += (s, e) => { _MidLevel.DoSomething(s, e); };
}
public void TriggerBottom()
{
DoSomething(this, "origin bottom");
}
public void DoSomething(object sender, string e)
{
Console.WriteLine($"do something at bottom : {e}");
Message?.Invoke(sender, e);
}
}

C# Custom Event Handler is always returning null

I am creating a car simulator where I have a key that turns on an engine. The engine is tied to a specific key with a callback method which calls the OnEngineTurn method which raises the event. No matter what I do to the EventHandler, I it never works because it always is null. Here is the code below. I am relatively new to C# so any help is appreciated
public delegate void MyEventHandler(object sender, EventArgs e);
class Engine
{
public event MyEventHandler EngineTurn;
//raise the event
protected virtual void OnEngineTurn(EngineEventArgs e)
{
MyEventHandler engineTurn = EngineTurn;
if (engineTurn != null)
{
MessageBox.Show("Hello World");
engineTurn(this, e);
}
else
{
MessageBox.Show("Null");
}
}
public CarKey GetNewKey()
{
return new CarKey(new KeyCallBack(OnEngineTurn));
}
}
class EngineEventArgs : EventArgs
{
public string name { get; set; }
}
delegate void KeyCallBack(EngineEventArgs e);
class CarKey
{
//we need a way to hook the engine up to the car so we don't crank, but one car with one key
private KeyCallBack keyCallBack;
public CarKey(KeyCallBack callBackDelegate)
{
this.keyCallBack = new KeyCallBack(callBackDelegate);
}
public void TurnTheKey(EngineEventArgs e)
{
if (keyCallBack != null)
{
MessageBox.Show("A");
keyCallBack(e);
}
}
}
carKey = engine1.GetNewKey() should tie a specific key to a specific engine with a callback method that calls back to the EngineTurn Event.... carKey.TurnTheKey(engineEventArgs) is suppose to raise the event.... Below is the constructor for CarKey... I have it inside the Engine class for the callback method...
carKey = engine1.GetNewKey();
engineEventArgs = new EngineEventArgs();
carKey.TurnTheKey(engineEventArgs);
public CarKey GetNewKey()
{
return new CarKey(new KeyCallBack(OnEngineTurn));
}
Solved the problem
class Simulator
{
private Engine engine = new Engine();
private Transmission transmission;
CarKey carKey;
//public ObservableCollection<string> FanSays { get { return fan.FanSays; } }
//public ObservableCollection<string> PitcherSays { get { return pitcher.PitcherSays; } }
// public int Trajectory { get; set; }
//public int Distance { get; set; }
public Simulator()
{
transmission = new Transmission(engine);
carKey = engine.GetNewKey();
}
public async void StartSimulator()
{
EngineEventArgs engineEventArgs = new EngineEventArgs("America!");
await new MessageDialog("made it inside the start method").ShowAsync();
carKey.StartTheEngine(engineEventArgs);
}
}

Update a form in parallel with an installation script?

I currently have an installation "framework" that does specific things. What I need now to do is be able to call my form in parallel with my script. Something like this:
InstallationForm f = new InstallationForm();
Application.Run(f);
InstallSoftware(f);
private static void InstallSoftware(InstallationForm f) {
f.WriteToTextbox("Starting installation...");
Utils.Execute(#"C:\temp\setup.msi", #"-s C:\temp\instructions.xml");
...
f.WriteToTextbox("Installation finished");
The current way I can do this is by adding the Form.Shown handler in InstallSoftware, but that seems really messy. Is there anyway I can do this better?
Your code will not work, because Application.Run(f) returns not until the form was closed.
You may use a simplified Model/View/Controller pattern. Create an InstallationFormController class that has several events, e.g. for textual notifications to be written to your textbox. The InstallationForm registers on these events in it's OnLoad() method and then calls InstallationFormController.Initialize(). That method starts your installation (on a worker thread/task). That installation callback method fires several text events.
InstallationForm f = new InstallationForm(new InstallationFormController());
Application.Run(f);
internal class InstallationFormController
{
public event EventHandler<DataEventArgsT<string>> NotificationTextChanged;
public InstallationFormController()
{
}
public void Initialize()
{
Task.Factory.StartNew(DoInstallation);
}
private void DoInstallation()
{
...
OnNotificationTextChanged(new DataEventArgsT<string>("Installation finished"));
}
private void OnNotificationTextChanged(DataEventArgsT<string> e)
{
if(NotificationTextChanged != null)
NotificationTextChanged(this, e);
}
}
public class DataEventArgsT<T> : EventArgs
{
...
public T Data { get; set; }
}
internal class InstallationForm : Form
{
private readonly InstallationFormController _controller;
public InstallationForm()
{
InitializeComponent();
}
public InstallationForm(InstallationFormController controller) : this()
{
if(controller == null)
throw new ArgumentNullException("controller")
_controller = controller;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_controller.NotificationTextChanged += Controller_NotificationTextChanged;
_controller.Initialize();
}
protected virtual void Controller_NotificationTextChanged(object sender, DataEventArgsT<string> e)
{
if(this.InvokeRequired)
{ // call this method on UI thread!!!
var callback = new EventHandler<DataEventArgsT<string>>(Controller_NotificationTextChanged);
this.Invoke(callback, new object[] {sender, e});
}
else
{
_myTextBox.Text = e.Data;
}
}
...
}

delegate or reflection?

I have a class with a method in which a string will be passed. That method will do some things to that string and it then passes the string to a certain object which can do other things with the string.
So it basically looks like this:
class Main
{
public Main()
{
strClass str = new strClass(this);
}
public function handler ( )
{
console.log("No string is passed yet, but this method is called from receiveData()");
}
}
class strClass
{
object handler;
public strClass ( handler )
{
// save the object
this.handler = handler;
}
public receiveData ( string str )
{
// This method does some stuff with the string
// And it then passes it on to the supplied object (handler) which will do
// the rest of the processing
// I'm calling the "handler" method in the object which got passed in the
// constructor
Type thisType = this.handler.GetType();
MethodInfo theMethod = thisType.GetMethod("handler");
theMethod.Invoke(this.handler, null);
}
}
Now this code works good, with the reflection stuff. But i was wondering, shouldn't this be possible (and maybe even better?) with delegates?? If so, how can i implement this by using a delegate instead?
Couldn't you use interfaces instead:
interface IStringHandler {
void HandleString(string s);
}
class strClass
{
IStringHandler handler = null;
public strClass(IStringHandler handler)
{
this.handler = handler;
}
public void ReceiveData(string s)
{
handler.HandleString(s);
}
}
class Main : IStringHandler
{
// Your code
}
A delegate is a better option here.
class Main
{
public Main()
{
StrClass str = new StrClass(this.Handler);
}
public void Handler ( )
{
//called from recieve data
}
}
class StrClass
{
readonly Action _handler;
public StrClass ( Action callback)
{
// save the object
this._handler = callback;
}
public void receiveData( string str )
{
this._handler();
}
}
You can do it with an Action like this:
class Main
{
public Main()
{
strClass str = new strClass(newString =>
{
console.log("This string I got back: " + newString);
});
}
}
class strClass
{
Action<string> callback;
public strClass (Action<string> callback)
{
// save the action
this.callback = callback;
}
public receiveData ( string str )
{
// Do something with the string
callback(str);
}
}
Even nicer than using delegates whould be using the
Chain of Responsibility design pattern, which does exactly what you need :).
Firstly, if you must call an unknown method by name, use dynamic - it is heavily optimised for this (although still not a great idea):
((dynamic)handler).handler(); // but please don't use this! see below
However, I would instead look at either an Action<string> (or maybe Func<string,string>), or an interface with a known method on it.
Basically, you want to change how your StrClass object react to data begin received. Sounds like events to me.
something like this, where you have handling methods both in the Main and in a generic HandlerObject:
class StrClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = null;
public void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
private string receivedString;
public string ReceivedString
{
get;
set
{
string oldStr = receivedString;
receivedString = value;
PropertyChanged(receivedString, new PropertyChangedEventArgs("ReceivedString"));
}
}
public void receiveData(string str)
{
//event fires here
ReceivedString = str;
}
}
class HandlerObject
{
public void HandlerMethod1(string s)
{
//magic
}
public void HandlerMethod2(string s)
{
//different kind of magic
}
}
class Program
{
static void HandlerMethod3(string s)
{
//another kind of magic!
}
static void Main(string[] args)
{
StrClass class1 = new StrClass();
StrClass class2 = new StrClass();
StrClass class3 = new StrClass();
HandlerObject handler = new HandlerObject();
class1.PropertyChanged += (s, e) => { handler.HandlerMethod1(s.ToString()); };
class2.PropertyChanged += (s, e) => { handler.HandlerMethod2(s.ToString()); };
class3.PropertyChanged += (s, e) => { HandlerMethod3(s.ToString()); };
}
}

Event Bus implementation question

I'm trying to implement simple Event Bus
I started like this:
public class RegistrationData
{
public object RegisteredObject { get; set; }
public Type eventType { get; set; }
public EventHandler MethodToInvoke;
}
public class EventBus
{
private static EventBus instance;
private static readonly object lockObject = new object();
private static List<RegistrationData> registrationList;
private EventBus()
{
}
public static EventBus Instance
{
get
{
lock (lockObject)
{
registrationList = new List<RegistrationData>();
return instance ?? new EventBus();
}
}
}
public void Subscribe(RegistrationData registrationData)
{
if(!registrationList.Contains(registrationData)) registrationList.Add(registrationData);
}
public void Unsubscribe(object objectToUnregister, Type eventType)
{
foreach(RegistrationData data in registrationList)
if (data.RegisteredObject == objectToUnregister && data.eventType == eventType) registrationList.Remove(data);
}
public void UnregisterAllMessages(object objectToUnregister)
{
foreach(RegistrationData data in registrationList)
if(data.RegisteredObject == objectToUnregister) registrationList.Remove(data);
}
public void PublishEvent(object sender, EventArgs eventArgs)
{
foreach (RegistrationData data in registrationList)
if (EventArgs is typeof(data.Type)) data.MethodToInvoke(sender, eventArgs);
}
}
But I have problem in PublishEvent method. I'm unable to determine type of event argument.
And I'm suspicious that all this is pretty wrong.
Can someone point out what I do wrong, how should I implement this?
Or how event bus is generally implemented, or some framework which I can use instead of implementing my own and spending time on that.
Um, not really sure how your Eventbus should behave. Short of knowing where you are heading it can be useful to look at how other people implemented the problem.
There is a down-to-earth event aggregator in the caliburn.micro project
I like to use MemBus when I need an event aggregator, partly because I wrote it myself, partly because it covers all my needs in that respect. It is more involved than caliburn's one, but then it has more features
I think you should start by defining Event Bus. What do you see as the difference between an Event Bus and the built-in .NET mechanisms for firing and sinking events? What you have so far looks like it implements not much more than the equivalent of .NET events. .NET intrinsically supports event handling so you wouldn't need an event bus if you don't need more than what .NET already provides:
class Program
{
static void Main(string[] args)
{
BusinessObject1 bo = new BusinessObject1("First Value");
// Subscribe
bo.Publish += new BusinessObject.PublishObject(bo_Publish);
bo.Update("Second Value");
// UnSubscribe
bo.Publish -= new BusinessObject.PublishObject(bo_Publish);
bo.Update("Third Value");
// Subscribe multiple
bo.Publish += new BusinessObject.PublishObject(bo_Publish);
bo.Publish += new BusinessObject.PublishObject(bo_Publish2);
bo.Update("Fourth Value");
// UnregisterAllMessages
bo.UnsubcribeAll();
bo.Update("Fifth Value");
}
static void bo_Publish(BusinessObject sender, EventArgs args)
{
if (sender is BusinessObject1)
{
BusinessObject1 bo1 = (BusinessObject1)sender;
BusinessObject1.PublishBusinessObject1EventArgs args1 =
(BusinessObject1.PublishBusinessObject1EventArgs)args;
Console.WriteLine("Updated {0} to {1}", args1.oldValue, bo1.Value);
}
}
static void bo_Publish2(BusinessObject sender, EventArgs args)
{
if (sender is BusinessObject1)
{
BusinessObject1 bo1 = (BusinessObject1)sender;
BusinessObject1.PublishBusinessObject1EventArgs args1 =
(BusinessObject1.PublishBusinessObject1EventArgs)args;
Console.WriteLine("Second handler detected updated of {0} to {1}", args1.oldValue, bo1.Value);
}
}
}
abstract class BusinessObject
{
public delegate void PublishObject(BusinessObject sender, EventArgs args);
public event PublishObject Publish;
// PublishEvent
protected void Update(EventArgs args)
{
if (Publish != null)
Publish(this, args);
}
public void UnsubcribeAll()
{
Publish = null;
}
}
class BusinessObject1 : BusinessObject
{
public class PublishBusinessObject1EventArgs : EventArgs
{
public string oldValue;
public PublishBusinessObject1EventArgs(string oldValue)
{
this.oldValue = oldValue;
}
}
public delegate void PublishBusinessObject1(BusinessObject1 sender, PublishBusinessObject1EventArgs args);
public string Value {get; private set;}
public BusinessObject1(string value)
{
this.Value = value;
}
public void Update(string newValue)
{
PublishBusinessObject1EventArgs args = new PublishBusinessObject1EventArgs(Value);
Value = newValue;
base.Update(args);
}
}
Edit:
If you don't want your business objects to have to inherit from a common base class (as you suggested in your comment) you can make a few modifications so that EventBus stands more independently, but you still don't need to re-implement all the event registration framework to do this:
class Program
{
static void Main(string[] args)
{
BusinessObject1 bo = new BusinessObject1("First Value");
// Subscribe
EventBus.Publish += new EventBus.PublishObject(EventBus_Publish);
bo.Update("Second Value");
// UnSubscribe
EventBus.Publish -= new EventBus.PublishObject(EventBus_Publish);
bo.Update("Third Value");
// Subscribe multiple
EventBus.Publish += new EventBus.PublishObject(EventBus_Publish);
EventBus.Publish += new EventBus.PublishObject(EventBus_Publish2);
bo.Update("Fourth Value");
// UnregisterAllMessages
EventBus.UnsubcribeAll();
bo.Update("Fifth Value");
}
static void EventBus_Publish(object sender, EventArgs args)
{
if (sender is BusinessObject1)
{
BusinessObject1 bo1 = (BusinessObject1)sender;
BusinessObject1.PublishBusinessObject1EventArgs args1 =
(BusinessObject1.PublishBusinessObject1EventArgs)args;
Console.WriteLine("Updated {0} to {1}", args1.oldValue, bo1.Value);
}
}
static void EventBus_Publish2(object sender, EventArgs args)
{
if (sender is BusinessObject1)
{
BusinessObject1 bo1 = (BusinessObject1)sender;
BusinessObject1.PublishBusinessObject1EventArgs args1 =
(BusinessObject1.PublishBusinessObject1EventArgs)args;
Console.WriteLine("Second handler detected updated of {0} to {1}", args1.oldValue, bo1.Value);
}
}
}
static class EventBus
{
public delegate void PublishObject(object sender, EventArgs args);
public static event PublishObject Publish;
// PublishEvent
public static void Update(object sender, EventArgs args)
{
if (Publish != null)
Publish(sender, args);
}
public static void UnsubcribeAll()
{
Publish = null;
}
}
class BusinessObject1
{
public class PublishBusinessObject1EventArgs : EventArgs
{
public string oldValue;
public PublishBusinessObject1EventArgs(string oldValue)
{
this.oldValue = oldValue;
}
}
public delegate void PublishBusinessObject1(BusinessObject1 sender, PublishBusinessObject1EventArgs args);
public string Value { get; private set; }
public BusinessObject1(string value)
{
this.Value = value;
}
public void Update(string newValue)
{
PublishBusinessObject1EventArgs args = new PublishBusinessObject1EventArgs(Value);
Value = newValue;
EventBus.Update(this, args);
}
}
Edit 2: By the way, if you want more control over the subscription process, you can get more control there too by defining custom event accessors as described at http://msdn.microsoft.com/en-us/library/bb882534.aspx:
static class EventBus
{
public delegate void PublishObject(object sender, EventArgs args);
private static List<PublishObject> subscribers = new List<PublishObject>();
public static event PublishObject Publish
{
add
{
subscribers.Add(value);
Console.WriteLine("Added subscriber {0}.{1}", value.Method.DeclaringType.Name, value.Method.Name);
}
remove
{
bool result = subscribers.Remove(value);
Console.WriteLine("Removed subscriber {0}.{1} ({2})", value.Method.DeclaringType.Name, value.Method.Name, result ? "success" : "failure");
}
}
// PublishEvent
public static void Update(object sender, EventArgs args)
{
foreach (PublishObject p in subscribers)
{
Console.WriteLine("Publishing to {0}.{1}", p.Method.DeclaringType.Name, p.Method.Name);
p.Invoke(sender, args);
}
}
public static void UnsubcribeAll()
{
subscribers.Clear();
}
}
Well, as a first suggestion, it looks to me as if you're trying to implement this as a singleton. Otherwise, what would the
private static EventBus instance;
be good for? But the private instance member is never assigned anywhere, that's one thing I'd suggest you should fix. For reference, here's a really good article on various implementations of singletons. If you've got access to .net4 I'd suggest you use the LazySingleton3 approach.
The only other thing that comes to mind is, this looks like it could be a use-case for Generics. Have a look at the EventHandler<TEventArgs> Delegate.
Apart from that, I can't recommend much more since I don't exactly understand what you're trying to do.
EDIT
Have a look at the accepted answer on this question. It contains a link to a blog post of someone who implemented this several years ago. Seems like you don't need to re-invent the wheel.

Categories

Resources