What ways are there for classes to provide progress information - c#

I have multiple classes that do lengthy tasks in threads and want them to output some kind of progress, so i can display it to a progress bar or a counter.
I could use an event or a delegate, defined in an interface, but it seems for every implementation I will need to write the exact same FireEvent code to check if the event is null and raise it, if it's not.
Using an abstract class seems bad too, since functionality like that does not belong in the top most class, which means I have to implement it at different places again.
How do I do that in the most reusable way, without duplicate code everywhere?

If you're using a BackgroundWorker for your other threads, you can use the ReportProgress method, which will raise the ProgressChanged event.
http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx

I usually reverse the relationship between the view and the model so that the view knows about the model. In this example the progress dialog would have a reference to a IProgress interface. It then hooks up to a ProgressChanged event and the view can thus update itself when it needs to. The main advantage of this is the code inside the various classes are not duplicated - Only the code that tells how much is left is inside those classes. This way it is also very easy to clamp progress updates of classes that emit progress status very often.
Just to give you an idea what I usually do:
interface IProgress
{
event EventHandler ProgressChanged;
int ProgressTarget { get; }
int CurrentProgress { get; }
}
And a implementing class. I don't even know if it works as it should - It's just to give an impression on how to implement this interface.
class StreamCopier: IProgress
{
private Stream _source;
private Stream _destination;
public StreamCopier(Stream source, Stream destination)
{
_source = source;
_destination = destination;
}
public void WriteAll()
{
int b;
while ((b = _source.ReadByte()) != -1)
{
_destination.WriteByte((byte)b);
EventRaiser.Raise(ProgressChanged, this); // Just one call here! Can't be less
}
}
public event EventHandler ProgressChanged;
public int ProgressTarget {
get { return (int)_source.Length; }
}
public int CurrentProgress {
get { return (int)_destination.Position; }
}
}
And then the EventRaiser class. Note how the handler reference is passed on the parameter stack, and therefor no thread-safe copy to a 'tmp' is necessary! :)
static class EventRaiser
{
public static void Raise(EventHandler handler, object sender, EventArgs args)
{
handler(sender, args);
}
public static void Raise(EventHandler handler, object sender)
{
Raise(handler, sender, EventArgs.Empty);
}
}

Related

Event Handlers and Interfaces

I have an interface called IDataIO:
public interface IDataIO
{
event DataReceivedEvent DataReceived;
//.....more events,methods and properties
}
I also have multiple classes that implement this interface, namely UdpIO, TcpIO, SerialIO.
Now, I have an IO class that allows me to switch between different input/output hardware. Each instance of this class has a CurrentIODevice property, which could be one of SerialIO,UdpIO or TcpIO. When this property is assigned, i attach 1 or more handlers to the DataReceivedEvent so that my GUI is notified when incoming data is received, as well as other classes that need to be notified.
public class IO
{
IDataIO CurrentIODevice;
public IO()
{
SerialIO serial = new SerialIO();
TcpIO tcp = new TcpIO();
UdpIO udp = new UdpIO();
CurrentIODevice = serial;
}
}
I also have a IOManager class that holds multiple IO objects.
public class IOManager
{
List<IO> Ports = new List<IO>();
public IOManager()
{
Ports.Add(new IO());
Ports.Add(new IO());
}
Ports[0].CurrentIODevice = serial;
Ports[0].CurrentIODevice.DataReceivedHandler += MyGuiUpdate;
Ports[0].CurrentIODevice.DataReceivedHandler += MyDataProcessing;
}
My concern (its not an issue atm) is how I am going to change between different IDataIO interfaces at runtime.
What is the effect of, at runtime, performing the following statement:
//i know this is illegal but just to demonstrate
IOManager.Ports[0].CurrentIODevice = tcp;
Will the event handlers still be functioning (and correctly)?
Do i need to unassign the events before the CurrentIODevice is assigned, and then re-assign the handlers again after? If this is the case, I can see this approach getting quite messy, so if anyone has a better approach to this problem I'm all ears :)
No, your handlers will not work because they're attached to the old object. Interfaces provides...an interface to an object, see it as a kind of contract but they're not a different object themselves.
If you need to switch between different implementations of the interface (at run-time) and to keep all handlers working you have to have the same object reference for the interface itself, kind of strategy pattern (more or less).
In your case you may, for example, implement the IDataIO interface in a DataIO object. It'll expose a property (or a method, I think its intent is more clear) to switch between different implementations of that interface (serial, TCP or whatever). It'll be the only one object to attach an event handler to that interface (and it'll drop the handler when the concrete implementation will change). Users of that object will always see it, whatever it's the concrete implementation it's using.
Example
This is a small example to explain this concept. The generic interface is this:
interface IDataIO
{
void Write(byte[] data);
byte[] Read();
event EventHandler DataReceived;
}
This is the concrete implementation of IDataIO, other classes will use only this class directly:
sealed class DataIO : IDataIO
{
public void SetChannel(IDataIO concreteChannel)
{
if (_concreteChannel != null)
_concreteChannel.DataReceived -= OnDataReceived;
_concreteChannel = concreteChannel;
_concreteChannel.DataReceived += OnDataReceived;
}
public void Write(byte[] data)
{
_concreteChannel.Write(data);
}
public byte[] Read()
{
return _concreteChannel.Read();
}
public event EventHandler DataReceived;
private IDataIO _concreteChannel;
private void OnDataReceived(object sender, EventArgs e)
{
EventHandler dataReceived = DataReceived;
if (dataReceived != null)
dataReceived(this, e);
}
}
Finally some code for testing:
class Test
{
public Test()
{
_channel = new TcpIO();
_channel.DataReceived += OnDataReceived;
}
public void SetChannel(IDataIO channel)
{
_channel.SetChannel(channel);
// Nothing will change for this "user" of DataIO
// but now the channel used for transport will be
// the one defined here
}
private void OnDataReceived(object sender, EventArgs e)
{
// You can use this
byte[] data = ((IDataIO)sender).Read();
// Or this, the sender is always the concrete
// implementation that abstracts the strategy in use
data = _channel.Read();
}
private DataIO _channel;
}
Obviously you should consider the strategy pattern. I will post the code first and explain later:
public interface IDataIO
{
event DataReceivedEvent DataReceived;
//this the new added method that each IO type should implement.
void SetStrategy();
}
public class SerialIO : IDataIO
{
public void SetStrategy()
{
//put the code that related to the Serial IO.
this.DataReceivedHandler += MyGuiUpdate;
this.DataReceivedHandler += MyDataProcessing;
}
}
public class TcpIO : IDataIO
{
public void SetStrategy()
{
//put the code that related to the Tcp IO.
//I will not implement it because it is a demo.
}
}
public class UdpIO : IDataIO
{
public void SetStrategy()
{
//put the code that related to the Udp IO.
//I will not implement it because it is a demo.
}
}
public class IO
{
IDataIO port = new IDataIO();
public void SetIOType(IDataIO ioType)
{
this.port = ioType;
port.SetStrategy();
}
}
public class IOManager
{
List<IO> ports = new List<IO>();
SerialIO serial = new SerialIO();
TcpIO tcp = new TcpIO();
ports[0].SetIOType(serial);
ports[1].SetIOType(tcp);
}
The interface IDataIO define basics that the all the IO types should implement.
The SerialIO, TcpIO, UdpIO classes derived from IDataIO implement the method SetStrategy() to meet each of their own need.
The IO class owns a field(named port) refers to a IDataIO type, this field can be setted to a certain IO type during the runtime by calling the method SetIOType() defined in the IO
class. Once this method is being called, we know which type the 'port' field refers to, and
then call the SetStrategy() method, it will run the overrided method in one of the IO class.
The IOManager class is the client. when it needs a certain IO type, say SerialIO, it only need to new a IO class and call the SetIOType() method by passing a SerialIO class instance, and all the logic related to the SerialIO type will be setted automatically.
Hope my description can help you.

Call Delegate methods from another class

I am having trouble figuring out how to program delegate method calls across classes in C#. I am coming from the world of Objective-C, which may be confusing me. In Objective-C, I can assign a delegate object inside a child class, to be the parent class (I.e., childViewcontroller.delegate = self;). Then I can to fire a method in the delegate class by using:
if([delegate respondsToSelector:#selector(methodName:)]) {
[delegate methodName:parametersgohere];
}
However, I can't figure out how to do this in C#. I've read a bit about C# delegates in general (for example, here), but I'm still stuck.
Are there any examples that explain this?
Here is my scenario in full:
I have classA which instantiates an instance of classB. ClassB fires a method (which call a web service), and upon response, I'd like to fire a method in classA.
Any 'Hello World' types of tutorials out there that might explain the very basics of this?
A delegate is an object that points to a method, be it a static or instance method. So for your example, you would just use the event model:
class Caller {
public void Call() {
new Callee().DoSomething(this.Callback); // Pass in a delegate of this instance
}
public void Callback() {
Console.WriteLine("Callback called!");
}
}
class Callee {
public void DoSomething(Action callback) {
// Do stuff
callback(); // Call the callback
}
}
...
new Caller().Call(); // Callback called!
The Caller instance passes a delegate to the Callee instance's DoSomething method, which in turn calls the pointed-to method, which is the Callback method of the Caller instance.
In C# what I think you are looking for are called events. They are a language feature that allows a class instance to expose a public delegate in a way that other class instances can subscribe to. Only the exposing class is allowed to raise the event.
In your example:
public class ClassB {
// Note the syntax at the end here- the "(s, e) => { }"
// assigns a no-op listener so that you don't have to
// check the event for null before raising it.
public event EventHandler<MyEventArgs> MyEvent = (s, e) => { }
public void DoMyWork() {
// Do whatever
// Then notify listeners that the event was fired
MyEvent(this, new MyEventArgs(myWorkResult));
}
}
public class ClassA {
public ClassA(ClassB worker) {
// Attach to worker's event
worker.MyEvent += MyEventHandler;
// If you want to detach later, use
// worker.MyEvent -= MyEventHandler;
}
void MyEventHandler(Object sender, MyEventArgs e) {
// This will get fired when B's event is raised
}
}
public class MyEventArgs : EventArgs {
public String MyWorkResult { get; private set; }
public MyEventArgs(String myWorkResult) { MyWorkResult = myWorkResult; }
}
Note that the above will be synchronous. My understanding is that Objective-C delegates are all Actor pattern, so they are asynchronous. To make the above asynch, you'll need to delve into threading (probably want to google "C# Thread pool").

Propagating a "volatile" property

I put "volatile" because it's only vaguely so.
I have a class which has a property called StopRequested. This flag can be set by other threads at any time, and needs to indicate to my code that it should stop what it's doing and exit (this is a Windows Service based process, and when Stop is called, all processing needs to clean up and stop).
I wish to create some other classes to do the actual brunt of the processing work, however these classes also have to be aware of the "stop" flag. You can't just pass the flag because it will pass a copy, and you can't pass properties as ref types.
So how do you propagate a property that might change at any time into other classes?
The only thing I can think of is to pass a reference to the parent class, but I dislike coupling the worker classes to the parent for one flag. Any suggestions would be appreciated.
EDIT:
Here's a basic example:
public class A
{
public bool StopRequested { get; set; }
private Worker = new Worker();
public void DoWork();
{
worker.DoWork();
}
}
public class Worker
{
public void DoWork()
{
while(!StopRequested)
{
....
}
}
}
You could have each of your worker classes have their own StopRequest property and then just set that whenever StopRequest is flagged.
private List<IStopable> WorkerClasses = new List< IStopable > ()
public Bool StopRequest{
get
{
return _stopRequest;
}
set
{
_stopReqest = value;
foreach (var child in WorkerClasses)
child.StopRequest = value;
}
}
Like Rubens said, use an event. What you described basically defines event to a T:
Propagate a property change to other classes.
There is actually a facility in .NET that provides this already, albeit in a generic way: INotifyPropertyChanged. This interface provides a single event, PropertyChanged, that allows a class to notify any listeners of any property change.
In your case, you could easily provide your own interface that is more specific:
interface IStopNotifier
{
event EventHandler StopRequested;
}
This interface would be implemented by your main work manager (whatever it is), and could propagate itself like so:
class WorkManager: IStopNotifier
{
public event EventHandler StopRequested;
protected void OnStopRequested()
{
if (StopRequested != null) StopRequested(this, new EventArgs());
}
public void StopAllWorkers()
{
OnStopRequested();
}
public Worker CreateWorker<T>()
where T: Worker
{
var worker = new T(this);
return worker;
}
}
class abstract Worker: IDisposable
{
public Worker(IStopNotifier stopNotifier)
{
stopNotofier.StopRequested += HandleStopRequested;
}
private IStopNotifier m_stopNotifier;
private bool m_stopRequested = false;
internal void HandleStopRequested(object sender, EventArgs e)
{
m_stopRequested = true;
}
public void Dispose()
{
m_stopNotifier.StopRequested -= HandleStopRequested;
}
}
Why don't to create an event to handle stop requests?

Event vs Delegates [duplicate]

What are the differences between delegates and an events? Don't both hold references to functions that can be executed?
An Event declaration adds a layer of abstraction and protection on the delegate instance. This protection prevents clients of the delegate from resetting the delegate and its invocation list and only allows adding or removing targets from the invocation list.
To understand the differences you can look at this 2 examples
Example with Delegates (in this case, an Action - that is a kind of delegate that doesn't return a value)
public class Animal
{
public Action Run {get; set;}
public void RaiseEvent()
{
if (Run != null)
{
Run();
}
}
}
To use the delegate, you should do something like this:
Animal animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();
This code works well but you could have some weak spots.
For example, if I write this:
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running");
animal.Run = () => Console.WriteLine("I'm sleeping") ;
with the last line of code, I have overridden the previous behaviors just with one missing + (I have used = instead of +=)
Another weak spot is that every class which uses your Animal class can invoke the delegate directly. For example, animal.Run() or animal.Run.Invoke() are valid outside the Animal class.
To avoid these weak spots you can use events in c#.
Your Animal class will change in this way:
public class ArgsSpecial : EventArgs
{
public ArgsSpecial (string val)
{
Operation=val;
}
public string Operation {get; set;}
}
public class Animal
{
// Empty delegate. In this way you are sure that value is always != null
// because no one outside of the class can change it.
public event EventHandler<ArgsSpecial> Run = delegate{}
public void RaiseEvent()
{
Run(this, new ArgsSpecial("Run faster"));
}
}
to call events
Animal animal= new Animal();
animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
animal.RaiseEvent();
Differences:
You aren't using a public property but a public field (using events, the compiler protects your fields from unwanted access)
Events can't be assigned directly. In this case, it won't give rise to the previous error that I have showed with overriding the behavior.
No one outside of your class can raise or invoke the event. For example, animal.Run() or animal.Run.Invoke() are invalid outside the Animal class and will produce compiler errors.
Events can be included in an interface declaration, whereas a field cannot
Notes:
EventHandler is declared as the following delegate:
public delegate void EventHandler (object sender, EventArgs e)
it takes a sender (of Object type) and event arguments. The sender is null if it comes from static methods.
This example, which uses EventHandler<ArgsSpecial>, can also be written using EventHandler instead.
Refer here for documentation about EventHandler
In addition to the syntactic and operational properties, there's also a semantical difference.
Delegates are, conceptually, function templates; that is, they express a contract a function must adhere to in order to be considered of the "type" of the delegate.
Events represent ... well, events. They are intended to alert someone when something happens and yes, they adhere to a delegate definition but they're not the same thing.
Even if they were exactly the same thing (syntactically and in the IL code) there will still remain the semantical difference. In general I prefer to have two different names for two different concepts, even if they are implemented in the same way (which doesn't mean I like to have the same code twice).
Here is another good link to refer to.
http://csharpindepth.com/Articles/Chapter2/Events.aspx
Briefly, the take away from the article - Events are encapsulation over delegates.
Quote from article:
Suppose events didn't exist as a concept in C#/.NET. How would another class subscribe to an event? Three options:
A public delegate variable
A delegate variable backed by a property
A delegate variable with AddXXXHandler and RemoveXXXHandler methods
Option 1 is clearly horrible, for all the normal reasons we abhor public variables.
Option 2 is slightly better, but allows subscribers to effectively override each other - it would be all too easy to write someInstance.MyEvent = eventHandler; which would replace any existing event handlers rather than adding a new one. In addition, you still need to write the properties.
Option 3 is basically what events give you, but with a guaranteed convention (generated by the compiler and backed by extra flags in the IL) and a "free" implementation if you're happy with the semantics that field-like events give you. Subscribing to and unsubscribing from events is encapsulated without allowing arbitrary access to the list of event handlers, and languages can make things simpler by providing syntax for both declaration and subscription.
What a great misunderstanding between events and delegates!!! A delegate specifies a TYPE (such as a class, or an interface does), whereas an event is just a kind of MEMBER (such as fields, properties, etc). And, just like any other kind of member an event also has a type. Yet, in the case of an event, the type of the event must be specified by a delegate. For instance, you CANNOT declare an event of a type defined by an interface.
Concluding, we can make the following Observation: the type of an event MUST be defined by a delegate. This is the main relation between an event and a delegate and is described in the section II.18 Defining events of ECMA-335 (CLI) Partitions I to VI:
In typical usage, the TypeSpec (if present) identifies a delegate whose signature matches the arguments passed to the event’s fire method.
However, this fact does NOT imply that an event uses a backing delegate field. In truth, an event may use a backing field of any different data structure type of your choice. If you implement an event explicitly in C#, you are free to choose the way you store the event handlers (note that event handlers are instances of the type of the event, which in turn is mandatorily a delegate type---from the previous Observation). But, you can store those event handlers (which are delegate instances) in a data structure such as a List or a Dictionary or any other else, or even in a backing delegate field. But don’t forget that it is NOT mandatory that you use a delegate field.
NOTE: If you have access to C# 5.0 Unleashed, read the "Limitations on Plain Use of Delegates" in Chapter 18 titled "Events" to understand better the differences between the two.
It always helps me to have a simple, concrete example. So here's one for the community. First I show how you can use delegates alone to do what Events do for us. Then I show how the same solution would work with an instance of EventHandler. And then I explain why we DON'T want to do what I explain in the first example. This post was inspired by an article by John Skeet.
Example 1: Using public delegate
Suppose I have a WinForms app with a single drop-down box. The drop-down is bound to an List<Person>. Where Person has properties of Id, Name, NickName, HairColor. On the main form is a custom user control that shows the properties of that person. When someone selects a person in the drop-down the labels in the user control update to show the properties of the person selected.
Here is how that works. We have three files that help us put this together:
Mediator.cs -- static class holds the delegates
Form1.cs -- main form
DetailView.cs -- user control shows all details
Here is the relevant code for each of the classes:
class Mediator
{
public delegate void PersonChangedDelegate(Person p); //delegate type definition
public static PersonChangedDelegate PersonChangedDel; //delegate instance. Detail view will "subscribe" to this.
public static void OnPersonChanged(Person p) //Form1 will call this when the drop-down changes.
{
if (PersonChangedDel != null)
{
PersonChangedDel(p);
}
}
}
Here is our user control:
public partial class DetailView : UserControl
{
public DetailView()
{
InitializeComponent();
Mediator.PersonChangedDel += DetailView_PersonChanged;
}
void DetailView_PersonChanged(Person p)
{
BindData(p);
}
public void BindData(Person p)
{
lblPersonHairColor.Text = p.HairColor;
lblPersonId.Text = p.IdPerson.ToString();
lblPersonName.Text = p.Name;
lblPersonNickName.Text = p.NickName;
}
}
Finally we have the following code in our Form1.cs. Here we are Calling OnPersonChanged, which calls any code subscribed to the delegate.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Mediator.OnPersonChanged((Person)comboBox1.SelectedItem); //Call the mediator's OnPersonChanged method. This will in turn call all the methods assigned (i.e. subscribed to) to the delegate -- in this case `DetailView_PersonChanged`.
}
Ok. So that's how you would get this working without using events and just using delegates. We just put a public delegate into a class -- you can make it static or a singleton, or whatever. Great.
BUT, BUT, BUT, we do not want to do what I just described above. Because public fields are bad for many, many reason. So what are our options? As John Skeet describes, here are our options:
A public delegate variable (this is what we just did above. don't do this. i just told you above why it's bad)
Put the delegate into a property with a get/set (problem here is that subscribers could override each other -- so we could subscribe a bunch of methods to the delegate and then we could accidentally say PersonChangedDel = null, wiping out all of the other subscriptions. The other problem that remains here is that since the users have access to the delegate, they can invoke the targets in the invocation list -- we don't want external users having access to when to raise our events.
A delegate variable with AddXXXHandler and RemoveXXXHandler methods
This third option is essentially what an event gives us. When we declare an EventHandler, it gives us access to a delegate -- not publicly, not as a property, but as this thing we call an event that has just add/remove accessors.
Let's see what the same program looks like, but now using an Event instead of the public delegate (I've also changed our Mediator to a singleton):
Example 2: With EventHandler instead of a public delegate
Mediator:
class Mediator
{
private static readonly Mediator _Instance = new Mediator();
private Mediator() { }
public static Mediator GetInstance()
{
return _Instance;
}
public event EventHandler<PersonChangedEventArgs> PersonChanged; //this is just a property we expose to add items to the delegate.
public void OnPersonChanged(object sender, Person p)
{
var personChangedDelegate = PersonChanged as EventHandler<PersonChangedEventArgs>;
if (personChangedDelegate != null)
{
personChangedDelegate(sender, new PersonChangedEventArgs() { Person = p });
}
}
}
Notice that if you F12 on the EventHandler, it will show you the definition is just a generic-ified delegate with the extra "sender" object:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
The User Control:
public partial class DetailView : UserControl
{
public DetailView()
{
InitializeComponent();
Mediator.GetInstance().PersonChanged += DetailView_PersonChanged;
}
void DetailView_PersonChanged(object sender, PersonChangedEventArgs e)
{
BindData(e.Person);
}
public void BindData(Person p)
{
lblPersonHairColor.Text = p.HairColor;
lblPersonId.Text = p.IdPerson.ToString();
lblPersonName.Text = p.Name;
lblPersonNickName.Text = p.NickName;
}
}
Finally, here's the Form1.cs code:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
Mediator.GetInstance().OnPersonChanged(this, (Person)comboBox1.SelectedItem);
}
Because the EventHandler wants and EventArgs as a parameter, I created this class with just a single property in it:
class PersonChangedEventArgs
{
public Person Person { get; set; }
}
Hopefully that shows you a bit about why we have events and how they are different -- but functionally the same -- as delegates.
You can also use events in interface declarations, not so for delegates.
Delegate is a type-safe function pointer. Event is an implementation of publisher-subscriber design pattern using delegate.
An event in .net is a designated combination of an Add method and a Remove method, both of which expect some particular type of delegate. Both C# and vb.net can auto-generate code for the add and remove methods which will define a delegate to hold the event subscriptions, and add/remove the passed in delegagte to/from that subscription delegate. VB.net will also auto-generate code (with the RaiseEvent statement) to invoke the subscription list if and only if it is non-empty; for some reason, C# doesn't generate the latter.
Note that while it is common to manage event subscriptions using a multicast delegate, that is not the only means of doing so. From a public perspective, a would-be event subscriber needs to know how to let an object know it wants to receive events, but it does not need to know what mechanism the publisher will use to raise the events. Note also that while whoever defined the event data structure in .net apparently thought there should be a public means of raising them, neither C# nor vb.net makes use of that feature.
To define about event in simple way:
Event is a REFERENCE to a delegate with two restrictions
Cannot be invoked directly
Cannot be assigned values directly (e.g eventObj = delegateMethod)
Above two are the weak points for delegates and it is addressed in event. Complete code sample to show the difference in fiddler is here https://dotnetfiddle.net/5iR3fB .
Toggle the comment between Event and Delegate and client code that invokes/assign values to delegate to understand the difference
Here is the inline code.
/*
This is working program in Visual Studio. It is not running in fiddler because of infinite loop in code.
This code demonstrates the difference between event and delegate
Event is an delegate reference with two restrictions for increased protection
1. Cannot be invoked directly
2. Cannot assign value to delegate reference directly
Toggle between Event vs Delegate in the code by commenting/un commenting the relevant lines
*/
public class RoomTemperatureController
{
private int _roomTemperature = 25;//Default/Starting room Temperature
private bool _isAirConditionTurnedOn = false;//Default AC is Off
private bool _isHeatTurnedOn = false;//Default Heat is Off
private bool _tempSimulator = false;
public delegate void OnRoomTemperatureChange(int roomTemperature); //OnRoomTemperatureChange is a type of Delegate (Check next line for proof)
// public OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above),
public event OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above),
public RoomTemperatureController()
{
WhenRoomTemperatureChange += InternalRoomTemperatuerHandler;
}
private void InternalRoomTemperatuerHandler(int roomTemp)
{
System.Console.WriteLine("Internal Room Temperature Handler - Mandatory to handle/ Should not be removed by external consumer of ths class: Note, if it is delegate this can be removed, if event cannot be removed");
}
//User cannot directly asign values to delegate (e.g. roomTempControllerObj.OnRoomTemperatureChange = delegateMethod (System will throw error)
public bool TurnRoomTeperatureSimulator
{
set
{
_tempSimulator = value;
if (value)
{
SimulateRoomTemperature(); //Turn on Simulator
}
}
get { return _tempSimulator; }
}
public void TurnAirCondition(bool val)
{
_isAirConditionTurnedOn = val;
_isHeatTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
System.Console.WriteLine("Heat :" + _isHeatTurnedOn);
}
public void TurnHeat(bool val)
{
_isHeatTurnedOn = val;
_isAirConditionTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
System.Console.WriteLine("Heat :" + _isHeatTurnedOn);
}
public async void SimulateRoomTemperature()
{
while (_tempSimulator)
{
if (_isAirConditionTurnedOn)
_roomTemperature--;//Decrease Room Temperature if AC is turned On
if (_isHeatTurnedOn)
_roomTemperature++;//Decrease Room Temperature if AC is turned On
System.Console.WriteLine("Temperature :" + _roomTemperature);
if (WhenRoomTemperatureChange != null)
WhenRoomTemperatureChange(_roomTemperature);
System.Threading.Thread.Sleep(500);//Every second Temperature changes based on AC/Heat Status
}
}
}
public class MySweetHome
{
RoomTemperatureController roomController = null;
public MySweetHome()
{
roomController = new RoomTemperatureController();
roomController.WhenRoomTemperatureChange += TurnHeatOrACBasedOnTemp;
//roomController.WhenRoomTemperatureChange = null; //Setting NULL to delegate reference is possible where as for Event it is not possible.
//roomController.WhenRoomTemperatureChange.DynamicInvoke();//Dynamic Invoke is possible for Delgate and not possible with Event
roomController.SimulateRoomTemperature();
System.Threading.Thread.Sleep(5000);
roomController.TurnAirCondition (true);
roomController.TurnRoomTeperatureSimulator = true;
}
public void TurnHeatOrACBasedOnTemp(int temp)
{
if (temp >= 30)
roomController.TurnAirCondition(true);
if (temp <= 15)
roomController.TurnHeat(true);
}
public static void Main(string []args)
{
MySweetHome home = new MySweetHome();
}
}
For people live in 2020, and want a clean answer...
Definitions:
delegate: defines a function pointer.
event: defines
(1) protected interfaces, and
(2) operations(+=, -=), and
(3) advantage: you don't need to use new keyword anymore.
Regarding the adjective protected:
// eventTest.SomeoneSay = null; // Compile Error.
// eventTest.SomeoneSay = new Say(SayHello); // Compile Error.
Also notice this section from Microsoft: https://learn.microsoft.com/en-us/dotnet/standard/events/#raising-multiple-events
Code Example:
with delegate:
public class DelegateTest
{
public delegate void Say(); // Define a pointer type "void <- ()" named "Say".
private Say say;
public DelegateTest() {
say = new Say(SayHello); // Setup the field, Say say, first.
say += new Say(SayGoodBye);
say.Invoke();
}
public void SayHello() { /* display "Hello World!" to your GUI. */ }
public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
}
with event:
public class EventTest
{
public delegate void Say();
public event Say SomeoneSay; // Use the type "Say" to define event, an
// auto-setup-everything-good field for you.
public EventTest() {
SomeoneSay += SayHello;
SomeoneSay += SayGoodBye;
SomeoneSay();
}
public void SayHello() { /* display "Hello World!" to your GUI. */ }
public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
}
Reference:
Event vs. Delegate - Explaining the important differences between the Event and Delegate patterns in C# and why they're useful.: https://dzone.com/articles/event-vs-delegate

How can I change components of a form from within another object?

I got an object, which is called in my form1-window. How can I change anything from the form1-object from within this object, for example a label or a processbar?
It would be a bad (circular) design to give your object a reference to your form. Use an interface or a delegate (callback).
// untested code
class MyObjectClass
{
public delegate void Reportback(int percentage);
public void DoSomething(Reportback callBack) { ...; callback(i*100F/total); ...}
}
class Form1: Form
{
private void reportProgress(int percent) { ...; progressbar1.value = percent; }
void SomeMethod() { myObject1.DoSomething(reportprogress); }
}
Generally speaking, when you find yourself with a need for one object to manipulate the private fields of another, your design needs work.
For instance, an class that's performing some kind of long-running business logic shouldn't be updating a ProgressBar. First, that's not its job. Second, that couples the functioning of the business logic to the implementation details of the user interface.
It's much better if the class simply raises events as it performs its long-running task. For instance, look at this class:
public class BusinessLogic
{
public event EventHandler ProgressChanged;
private int _Progress;
public int Progress
{
get { return _Progress; }
private set
{
_Progress = value;
EventHandler h = ProgressChanged;
if (h != null)
{
h(this, new EventArgs());
}
}
}
}
Whenever any method in this class sets the Progress property, the ProgressChanged event gets raised. In your form, you can instantiate the object with logic like this:
private BusinessLogic Task;
private void Form1_Load(object sender, EventArgs e)
{
Task = new BusinessLogic();
Task.ProgressChanged += Task_ProgressChanged;
}
void Task_ProgressChanged(object sender, EventArgs e)
{
taskProgessBar.Value = ((BusinessLogic) sender).Progress;
}
Now, every time a method in the Task object sets the Progress property, the ProgressBar in the form will get updated.
This is quite a bit more code to write than just having the object update the ProgressBar, sure. But look what you get out of it. If you have to refactor your form into two forms, and move the task to a new form, you don't have to touch the BusinessLogic class. If you move your ProgressBar from being a control on the form to being a ToolStripProgressBar on a ToolStrip, you don't have to touch the BusinessLogic class. If you decide that progress reporting isn't important, you don't have to touch the BusinessLogic class.
Essentially, this approach protects the BusinessLogic class from having to know anything about the user interface. This makes it a lot easier to change both the business logic and the user interface as your program evolves.
I agree with Henk... but anyway, you can modify any item on a form if you change the visibility of the controls, there is even a property for doing this.

Categories