I have dictionary like this :
public Dictionary<string, string> fields
{
get
{
}
set
{
}
}
How can I fire event which will keep listening to this dictionary?
And as soon as something is changed in the event some event handler should be called.
Is it possible to do it without making this dictionary observable?
private int _age;
public event System.EventHandler AgeChanged;
protected virtual void OnAgeChanged()
{
if (AgeChanged != null) AgeChanged(this,EventArgs.Empty);
}
public int Age
{
get
{
return _age;
}
set
{
_age=value;
OnAgeChanged();
}
}
I don't want the above implementation.
You'll need a custom class. Wrap your dictionary in a class and create an event to track when the dictionary changes. You will need to override the existing add / remove etc and when they get called, have them raise your event.
Here's a good question that may help.
.NET ObservableDictionary
Related
I have a third part class object called SomeOnesClass and int property count has only get, I cannot change or extend this class, it doesn't have InotificationChanged implementation, How to get the notification for count value change only with instance of SomeOnesClass.
Try putting SomeOnesClass into another class, use properties to access SomeOnesClass and raise the event in the setter. E.g.
class SomeOnesClassNotification : INotifyPropertyChanged {
public SomeOnesClassNotification(SomeOnesClass someOnesClass) {
this.someOnesClass = someOnesClass;
}
private SomeOnesClass someOnesClass;
private int count;
public int Count {get {return count; }
set {count = value;
NotifyCountChanged();
}
}
void NotifyCountChanged() {
// Do stuff
}
public event PropertyChangedEventHandler PropertyChanged;
}
I'm not too sure of how to implement InotificationChanged, but hopefully this will give you an idea. Note you'd have to use properties or methods to access each of the SomeOnesClass members.
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'm having some issues here, I'm working with a class called Cell and when I create each cell I want to raise an event OnCellCreated which my IGameViewer will attach to eventually. For some weird reason it doesn't work though, now I've bypassed this by instead calling IGameViewer.DisplayCell in the constructor, but it's incredibly strange because it passes the exact same object reference from the constructor and it works, but when I try to do it with my event I will get a null object reference. So does anyone have any ideas?
Here's the code
class Cell
{
public delegate void CellChangedHandler(Cell cell);
#region Properties & Fields
private Mark markType = Mark.Empty;
private IGameViewer viewer;
public static event CellChangedHandler OnCellChanged;
public static event CellChangedHandler OnCellCreated;
public readonly Tuple<int, int> pos;
public Mark MarkType {
get { return markType; }
set
{
// Only allow changes to cells without a mark
if (markType.Equals(Mark.Empty))
{
markType = value;
OnCellChanged(this); //Model -> Viewer & Presenter, both can attach to this event
}
}
}
#endregion
#region Constructors
public Cell(IGameViewer viewer, Tuple<int, int> coords)
{
this.viewer = viewer;
this.pos = coords;
OnCellCreated(this); // <- This causes an object null reference exception to be thrown
viewer.DisplayCell(this); // <- This doesn't, even if I reverse the calling order
}
#endregion
}
Your OnCellCreated event is null, because noone yet subscribed to it. And how can caller do that if you call it already in construcutor. ? One can not subscribe to the event of the instance if the instance is not yet created (you are in constructor)
You can create a CellFactory class and add CellCretaed event to the factory. You ask CellFactory to create Cell instance, and CellFactory after creation of it, raises an event. Naturally you have to subscribe to that event before calling factory method.
Check if there're subscribers for the event whenever raising it:
public Cell(IGameViewer viewer, Tuple<int, int> coords) {
this.viewer = viewer;
...
if (!Object.ReferenceEquals(null, OnCellCreated))
OnCellCreated(this);
...
}
As #Tigran answered, the problem is that no one has yet subscribed to the event. What were you expecting to happen by invoking the event on the constructor?
If you had followed the pattern to implement events in .NET classes this would have never happened.
Change your code to this:
class Cell
{
private Mark markType = Mark.Empty;
private IGameViewer viewer;
public static event EventHandler CellChanged;
public readonly Tuple<int, int> pos;
public Cell(IGameViewer viewer, Tuple<int, int> coords)
{
this.viewer = viewer;
this.pos = coords;
viewer.DisplayCell(this);
}
public Mark MarkType {
get { return markType; }
set
{
// Only allow changes to cells without a mark
if (markType.Equals(Mark.Empty))
{
markType = value;
OnCellChanged();
}
}
}
protected virtual void OnCellChanged()
{
var handler = this.CellChanged;
if (handler)
{
handler(this, EventArgs.Empty);
}
}
}
I followed this tutorial but I couldn't apply what I learned to my project.
I have a LineGraph object (Dynamic Data Display) and I want to create an event that is raised when the thickness of the LineGraph is equal to 0.
How am I supposed to write it following this tutorial ?
Here is how I would do it with a RoutedEvent:
Create a class that derives from LineGraph, let's say CustomLineGraph:
public class CustomLineGraph : LineGraph {
}
Create our routed event like this:
public class CustomLineGraph : LineGraph {
public static readonly RoutedEvent ThicknessEvent = EventManager.RegisterRoutedEvent("Thickness", RoutingStrategy.Bubble, typeof(RoutedEventHandler, typeof(CustomLineGraph));
// .NET event wrapper
public event RoutedEventHandler Thickness
{
add { AddHandler(CustomLineGraph.ThicknessEvent, value); }
remove { RemoveHandler(CustomLineGraph.ThicknessEvent, value); }
}
}
Now we override the StrokeThickness property so we can raise our custom routed event when the value of that property is 0.
public class CustomLineGraph : LineGraph {
public static readonly RoutedEvent ThicknessEvent = EventManager.RegisterRoutedEvent("Thickness", RoutingStrategy.Bubble, typeof(RoutedEventHandler, typeof(CustomLineGraph));
// .NET event wrapper
public event RoutedEventHandler Thickness
{
add { AddHandler(CustomLineGraph.ThicknessEvent, value); }
remove { RemoveHandler(CustomLineGraph.ThicknessEvent, value); }
}
public override double StrokeThickness {
get { return base.StrokeThickness; }
set
{
base.StrokeThickness = value;
if (value == 0)
RaiseEvent(new RoutedEventArgs(CustomLineGraph.ThicknessEvent, this));
}
}
}
We are done !
Personally, I usually avoid creating events, preferring instead to create delegates. If there is some particular reason that you specifically need an event, then please ignore this answer. The reasons that I prefer to use delegates are that you don't need to create additional EventArgs classes and I can also set my own parameter types.
First, let's create a delegate:
public delegate void TypeOfDelegate(YourDataType dataInstance);
Now a getter and setter:
public TypeOfDelegate DelegateProperty { get; set; }
Now let's create a method that matches the in and out parameters of the delegate:
public void CanBeCalledAnything(YourDataType dataInstance)
{
// do something with the dataInstance parameter
}
Now we can set this method as one (of many) handlers for this delegate:
DelegateProperty += CanBeCalledAnything;
Finally, let's call our delegate... this is equivalent to raising the event:
if (DelegateProperty != null) DelegateProperty(dataInstanceOfTypeYourDataType);
Note the important check for null. So that's it! If you want more or less parameters, just add or remove them from the delegate declaration and the handling method... simple.
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; }
}