This seems to be basics of the language, but I do not understand how is this accomplished in .Net. I have a member variable in a class, say a bool _isCommitted. I want something to happen whenever _isCommitted is true. Something like this:
//Whenever _isCommitted == true()
{
Foo()
}
Basically like an event, but here it is my variable. How to? Many thanks..
This is normally done through properties and a backing private field. You need to ensure you only ever access through the property.
private bool _isCommitted;
public bool IsCommitted
{
get { return _isCommitted; }
set
{
if(value)
{
//do something
}
_isCommitted = value;
}
}
At the most basic level, you can create an event in your class:
public delegate void MyHandler(bool b);
public event MyHandler CommittedChanged;
Now people can subscribe to your event like so:
public void SomeHandlerMethod(bool b) { ... }
...
someInstance.CommittedChanged += SomeHandlerMethod;
someInstance.CommittedChanged += ASecondHandlerMethod;
someInstance.CommittedChanged += x => { /* inline handler using lambda */ };
A user can unregister his event handler this way:
someInstance.CommittedChanged -= SomeHandlerMethod;
And wherever you decide to change your variable, you will follow it up with:
if (CommittedChanged != null) CommittedChanged(_isCommitted);
This will call everyone who has registered a function with your event.
Having said this, there are plenty of improvements that you can do. First, make _isCommitted into a property, and do the event callback in its setter. This way, you won't forget to call the handlers.
public IsCommitted {
get { return _isCommitted; }
set {
_isCommitted = value;
if (CommittedChanged != null) CommittedChanged(_isCommitted);
}
}
Read more about events here.
This is enough to get you going. However, if you delve further into the C# framework, you will find a standardized way of using this event framework inside of the System.ComponentModel namespace. Sepcifically, the interface INotifyPropertyChanged, which ties neatly into a more generic event system that also plays well with some of Microsoft's own technologies, such as WPF, allowing GUI elements to pick up on changes to your class automatically. Read more about INotifyPropertyChanged here.
You basically need PropertyChangedEvent PropertyChangedEventHandler Delegate
I think C# properties is what you need.
private bool _isCommitted;
public bool IsCommitted
{
get { return _isCommitted; }
set { if(value){/*DO SOMETHING HERE*/}
_isCommitted = value; }
}
Related
I have the following class, which has one public event called LengthChanged:
class Dimension
{
public int Length
{
get
{
return this.length;
}
set
{
if (this.length != value)
{
this.length = value;
this.OnLengthChanged ();
}
}
protected virtual void OnLengthChanged()
{
var handler = this.LengthChanged;
if (handler != null)
{
handler (this, System.EventArgs.Empty);
}
}
public event System.EventHandler LengthChanged;
private int length;
}
I would like to be able to register/unregister handlers for this event in a method called Observer, which does not know anything about the Dimension class. I have come up with two scenarios, none of which are really satisfying:
Define an interface ILengthChanged with the LengthChanged event, then make sure Dimension implements ILengthChanged. Then I have to provide one implementation of the Observer method for every interface I define. This by no way generic enough. I'd really want to be able to simply pass in a reference to a System.EventHandler event.
Use System.Action<System.EventHandler> callbacks for registering and unregistering the event handler in the Observer method, just like that:
class Foo
{
public void Observer(System.Action<System.EventHandler> register,
System.Action<System.EventHandler> unregister)
{
register (this.MyEventHandler);
// keep track of the unregister callback, so that we can unregister
// our event handler later on, if needed...
}
private void MyEventHandler(object sender, System.EventArgs e)
{
...
}
}
which would then be invoked like this:
Foo foo = ...;
Dimension dim = ...;
foo.Observer (x => dim.LengthChanged += x, x => dim.LengthChanged -= x);
and which, when executed, will indeed end up wiring the LengthChanged event with the internal event handler MyEventHandler. But this is not very elegant. I would have loved to be able to write this instead:
Foo foo = ...;
Dimension dim = ...;
foo.Observer (dim.LengthChanged);
but I've no idea how this could be achieved. Maybe I am missing something really obvious here? I guess that some dynamic magic could do the trick, somehow, but this would not enforce compile-time type checking: I don't want the users of Observer to pass in references to events which do not satisfy the System.EventHandler event signature.
Unfortunately there isn't really a way of doing this. Events aren't first class citizens in .NET in general - although F# tries to promote them there.
Either pass in the subscribe/unsubscribe delegate or using a string indicating the name of the event. (The latter is often shorter, but obviously less safe at compile-time.)
Those are the approaches which Reactive Extensions takes - if there were a cleaner way of doing it, I'm sure they would be using that :(
You can create a custom accessor.
public event EventHandler NewEvent
{
add { Dimension.LengthChanged += value; }
remove { Dimension.LengthChanged -= value; }
}
Please see the documentation.
Event is not supposed to be passed into another method. However, you can pass delegate into another method. Perhaps, what you are looking for are just a simple public delegate instead of event.
If you change your event to this
public System.EventHandler LengthChanged;
You can simply pass the LengthChanged to Observer like this
Foo foo = ...;
Dimension dim = ...;
foo.Observer (dim.LengthChanged);
In my script attached to my controllers I want to be able to reference the child object that the controller is holding at the time, but I’m not sure how.
Any idea how to do this, would I need to tag the objects or something along those lines?
One way to do it, which is something I've done before at least, is to use System events.
You make two events in your controllers:
event EventHandler OnPickedUp;
event EventHandler OnLetGo;
If you manage to get something within range of picking it up, you fire off the event OnPickekUp
public class MyVRController
{
public event EventHandler OnPickedup;
public event EventHandler OnLetGo;
private bool HasObject = false;
...
private void SuccessfullyPickedUp(GameObject pickedUpGO)
{
if(OnPickedUp != null)
{
HasObject = true;
OnPickedUp(pickedUpGO, null);
}
}
...
private void OnLetGo()
{
if(OnLetGo != null)
{
HasObject = false;
OnLetGo(this, null);
}
}
...
}
Then whatever needs to care about the fact that you picked something up or you dropped something, can do this:
public class MyGameManager
{
public void Start()
{
// However you reference the controllers, do it here.
myRightVRController.OnPickedUp += SomeFunc1;
myRightVRcontroller.OnLetGo += SomeFunc2;
myLeftVRController.OnPickedUp += SomeFunc3;
myLeftVRController.OnLetGo += SomeFunc4;
// The rest of your initialization...
}
}
If you want you can specify what controller the event came from in the EventArgs that can be passed (currently passing null).
Hope this helps!
Interface-Events can be Implemented explicit. For example we are able to pass
delegates to another Event.
Here the TestHandler-Event is wrapped (not sure if its the right term) by the SomeHandler-Event to Implement the ISomeHandleable-Interface.
public delegate void HandlerDelegate();
public interface ISomeHandleable
{
event HandlerDelegate SomeHandler;
}
public class Test : ISomeHandleable
{
event HandlerDelegate ISomeHandleable.SomeHandler
{
add { TestHandler += value; }
remove { TestHandler -= value; }
}
public event HandlerDelegate TestHandler;
public void Fire() => TestHandler?.Invoke();
}
I have just recently seen, that we are also able to Implement ISomeHandleable.SomeHandleras follows:
event HandlerDelegate ISomeHandleable.SomeHandler
{
add { }
remove { }
}
But I have not yet found any documentation and possible usecases to this, and I also dont understand what it does.
I only know, delegates can still be added to ISomeHandleable.SomeHandler but the Event cannot be invoked by the Class Test anymore.
But as you can define Events with empty Accessors, what does it do and how is it meant to be used?
I have a memorystream object which is to be updated a particular time interval.
When a update occurs on the memorystream object the event should be created & raised.
Then there should be a event handler to handle the raised event.
Please suggest any code or sample for ref.
Thanks in advance.
Do you know event's logic at all?
If so, Create an event in the class where your memory stream will be updated.
When updating it, raise the event.
At the class' consumer register the event.
And, basically, that's it?
Maybe your doubt are events in general. For that i'd suggest you to read MSDN, e.g.
There are a couple ways you could go about this.
The easiest way would be that suggested by the guy that just beat me to the punch and instead of calling MemoryStream.Write() directly, write a method in your application that invokes MemoryStream.Write() and then invokes an event that you declare yourself outside the MemoryStream objeect.
In the more exotic but more concise corner, you could be daring and inherit a class from MemoryStream where you add an event property and override the Write() method (or whichever method(s) you call to do the writing) to invoke the base class Write() method and then raise the event. Some may pupu this approach and it could be less than ideal or problematic depending on how you are using MemoryStream, but it would do the job you want and keep you from having to raise the event yourself every time you write.
A good sample about registering and raising custom events can be found at http://www.switchonthecode.com/tutorials/csharp-snippet-tutorial-custom-event-handlers
Update: The link is broken, I used archive.org to quote from there (Changed event raising part to avoid race condition):
using System;
namespace CustomEvents
{
public class Car
{
public delegate void OwnerChangedEventHandler(string newOwner);
public event OwnerChangedEventHandler OwnerChanged;
private string make;
private string model;
private int year;
private string owner;
public string CarMake
{
get { return this.make; }
set { this.make = value; }
}
public string CarModel
{
get { return this.model; }
set { this.model = value; }
}
public int CarYear
{
get { return this.year; }
set { this.year = value; }
}
public string CarOwner
{
get { return this.owner; }
set
{
this.owner = value;
// To avoid race condition
var ownerchanged = this.OwnerChanged;
if (ownerchanged != null)
ownerchanged(value);
}
}
public Car()
{
}
}
}
I got a scenario like this
Class Parent
{
Property A;
}
Class A
{
Property X
}
How can I get a PropertyChangedNotification on Property A when X changes? I don’t want to refer ‘Parent’ in class A or any kind of event which spoils my decoupling. What I basically want is to make the Parent.IsDirty==true. This is a very simplified version of my story, I got tens of classes like Parent, so I am looking for some generic way to handle this.
Please note that this is not the actual code. I got all INotifyPropertyChanged implementation. I am just wondering any easy mechanism like RaisePropertyChanged("A.X")
You can try to register the propertychanged event in the parent class. In the constructor you can subribe to the event:
public Parent()
{
A.OnPropertyChanged += OnAPropertyChanged;
}
void OnAPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "X")
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("A"))
}
hope this helps...
I don't know if this is the best practice but:
what about something like this:
private Movie movie;
public Movie Movie
{
get { return movie; }
set
{
var oldProperties = typeof(Movie).GetProperties();
foreach (var property in oldProperties)
{
if (property.GetValue(movie).GetHashCode() != value.GetType().GetProperty(property.Name).GetValue(value).GetHashCode())
{
RaisePropertyChanged(property.Name);
}
}
movie = value;
}
}
surely you can take it outside to an external helper that take the 2 objects and the event handler