How do I trigger an event in the setter of a property? - c#

I have a property by the name "TrendPoint" of type ITrendPoint. I need to raise a "OnTrendPointChanged" event whenever the value of the TrendPoint changes and perform a set of operations.
I've tried the following but can't seem to proceed further:
public class TestClass:ObservablePoint
{
private ITrendPoint trendPoint;
public ITrendPoint TrendPoint{
get{ return trendPoint ;}
set{ this.trendPoint= value;
//Need to Call the event handler
// "OnTrendPointChanged"
}
public void TestJob()
{
//The TrendPoint is being set
// here
TrendPoint=
Services.getTrendPoint();
}
//The event handler
private void
OnTrendPointChanged(object sender,
ValueChangedEventArgs<string> e)
{
switch(e.value):
case "HIGH":
Log("TR HIGH");
case "Low":
Log("TR LOW");
//Other such conditions
.
.
.
}
}
I'm not able to figure out how exactly do I get the eventhandler "OnTrendPointChanged" to execute whenever the value of "TrendPoint" changes. Any help is appreciated!

I'm not clear that there is any point to having an eventhandler in your code at all.
Setting that aside. You don't seem to use sender so that can be null. Maybe you have some code uses that which you're not showing us. In which case you need to pass some instance of whatever sender is going to be in. This is not clear from what you've provided ( naughty ).
So we can pass null, for sender but need a valuechangedeventargs instance to pass.
Something like:
public ITrendPoint TrendPoint{
get{ return trendPoint ;}
set{ this.trendPoint= value;
var vc = new ValueChangedEventArgs<TrendPoint>(this.trendPoint);
OnTrendPointChanged(null, vc);
}
Assuming OnTrendPointChanged is in the same class. Seems to be from what you've provided but maybe it isn't.
If the handler is in some other class then you will need to reference an instance of that, obviously.
How did I know a valuechangedeventargs works like that? I looked it up:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.language.intellisense.valuechangedeventargs-1?view=visualstudiosdk-2022
Hope all this helps.

Related

Best way to call a function in the event of a variable's value is changed?

say I have an int Index = 0;. This value may be changed by the user at any point of the program. When it does, I need to update all my screens to data concerned with that new index value. I have a function for this I just need help figuring out how to call it.
My idea is to create a timer, and on every tick event it checks to see if the value of my variable Index has changed. If yes then execute my function. But this seems really amateur to me. There has to be something more direct correct? I heard of something called "INotifyPropertyChanged" or something like that but I'm having a hard time finding a solid example of how it works.
Any ideas are much appreciated thank you.
You can use an event and subscribe to it then in the handler call the method. You will create the event like so:
public event IndexChangedEventHandler IndexChanged;
public delegate void IndexChangedEventHandler(int newValue);
protected virtual OnIndexChanged(int newValue)
{
if (IndexChanged != null)
IndexChanged(newValue);
}
Then use a property to wrap your index field and call the event inside of it:
private int _index;
public int Index
{
get
{
return _index;
}
set
{
_index = value;
OnIndexChanged(value);
}
}
Then all you would need do to is subscribe to the event like:
IndexedChanged += new IndexChangedEventHandler(IndexChanged_EventHandler);
private void IndexChanged_EventHandler(int newValue)
{
//call your update method here
}

Trigger event on value change C#

I'm trying to monitor a value and when it is changed, to update a text field after performing some calculations with a result.
The value I'm trying to monitor comes from an AGauge property (custom control). I want to update the text field when the AGauge.Value changes.
I've looked at questions such as This One but I don't really understand how this works, or what I need to change to get the result I'm looking for.
Can anyone better explain what I need to do in order for this to work?
The AGuage.Value is a float type, incase your wondering.
Thanks in advance.
Update 1
I have now added the following code to my project:
public class AGuage
{
private float _value;
public float Value
{
get
{
return this._value;
}
set
{
this._value = value;
this.ValueChanged(this._value);
}
}
public void ValueChanged(float newValue)
{
}
}
And can get the ValueChanged to fire using the following:
AGuage n = new AGuage();
n.Value = Pressure_Gauge.Value;
Which fires everytime the Pressure_Gauge.Value is updated.
The issue, or last hurdle, I am facing now is this part:
public void ValueChanged(float newValue)
{
Form1.Pressure_Raw.text = "Working";
}
I want to update the label's text on form1 usingthe above method, however I get an error saying: An object reference is required for the nonstatic field, method, or property.
I'm not sure how to do this, I've read some information about Static properties, but how would I update the label's text value from within this?
Thanks.
This might help. You could add an event and subscribe to it in your form.
For example:
public class AGauge {
// You can either set the Value this way
public float Value {
get {return this.Value;}
set
{
// (1)
// set "Value"
this.Value = value;
// raise event for value changed
OnValueChanged(null);
}
}
// create an event for the value change
// this is extra classy, as you can edit the event right
// from the property window for the control in visual studio
[Category("Action")]
[Description("Fires when the value is changed")]
public event EventHandler ValueChanged;
protected virtual void OnValueChanged(EventArgs e)
{
// (2)
// Raise the event
if (ValueChanged != null)
ValueChanged(this,e);
}
}
public Form1 : Form {
// In form, make your control and add subscriber to event
AGauge ag = new AGauge();
// (3)
ag.ValueChanged += UpdateTextBox;
// (4)
public void UpdateTextBox(object sender, EventArgs e)
{
// update the textbox here
textbox.Text = ag.Value;
}
}
Here's how this works:
At (3) you add a subscriber to the ag.ValueChanged event as described HERE.
When you go to change ag.Value, you get to (1), where Value is changed and OnValueChanged is called. This gets you to (2), where the ValueChanged event is raised. When this happens, all subscribers to that event are "notified" and call their respective methods. So when you get to (2), (4) ends up getting called because "UpdateTextBox" was set as a subscriber to the ValueChanged event. It's a bit tricky, but it is very useful.
Or if you want to continue with how you're trying to do it, you need to do this:
public class AGuage
{
private float _value;
// create object of Form1 for reference
private Form1 form1;
// pass reference to form1 through constructor
public AGauge(Form1 form1)
{
// assign
this.form1 = form1;
}
public float Value
{
get
{
return this._value;
}
set
{
this._value = value;
this.ValueChanged(this._value);
}
}
public void ValueChanged(float newValue)
{
// use the form1 reference
this.form1.Pressure_Raw.Text = "Working";
}
}
And then do this:
// if creating the AGauge object in Form1, pass "this" to the object
AGuage n = new AGuage(this);
I highly recommend you don't do it this way as this breaks the generics rule for OOP. Which means, if you try to use this AGauge control anywhere else other than in Form1, it will not work the same way. I recommend doing it with events like I have described above. It's much more universal.
You need to make your AGauge implement INotifyPropertyChanged and notify the property changing on Value. There's enough information on Google on how to do this and has been discussed hundreds of times in StackOverflow.
Then, you will need to use a Binding to bind your textbox to the AGauge value. Since you need to convert, you'll need to provide formatting and optionally parsing.
This should be something like:
var binding = new Binding("Text", myAgaugeControl, "Value");
binding.Format += BindingFormat;
binding.Parse += BindingParse;
myTextBox.DataBindings.Add(binding);
BindingFormat and BindingParse should be the converters. Format would be for converting the gauge's value to the textbox string. The most simple:
void BindingFormat(object sender, ConvertEventArgs e)
{
e.Value = e.Value.ToString();
}
BindingParse would be the opposite: if the textbox text changes, you need to parse the text and convert it to a value AGauge can understand. I'll let you figure this out.
More information on Binding, Format and Parse
What you need to do is create a custom setter for the Value property. Every time the value is set your code will call your hook method which I called ValueChanged(). In that method you can perform your calculations and then set the text field to the result.
public class AGuage
{
private float _value;
public float Value
{
get
{
return this._value;
}
set
{
this._value = value;
this.ValueChanged(this._value);
}
}
public void ValueChanged(float newValue)
{
// Action to perform on value change
// Update a text field after performing some calculations with a result.
}
}
A nice and clean option is to use Microsoft's Reactive Framework (NuGet "Rx-WinForms"). It lets you work with observables (as opposed to enumerables) in a LINQ-like manner.
Your class would look like this:
public class AGuage
{
private float _value;
private Subject<float> _values = new Subject<float>();
public float Value
{
get { return _value; }
set
{
_value = value;
_values.OnNext(value);
}
}
public IObservable<float> Values
{
get { return _values.AsObservable(); }
}
}
Now you can do things like this:
var aGuage = new AGuage();
var query =
from value in aGuage.Values
where value > 5.0f && value < 20.0f //filtering
select value * 150f + 45.3f; //computation
var subscription =
query.Subscribe(value =>
{
/* do something with the filtered & computed value */
});
aGuage.Value = 2.1f; // query.Subscribe doesn't fire
aGuage.Value = 12.4f; // query.Subscribe DOES fire
aGuage.Value = 202.1f; // query.Subscribe doesn't fire
If you want to shut down the subscription to the values just call subscription.Dispose().

Static object: manage set method

I have a static observableCollection.
It is updated from the UI, using a MVVM approach.
How can I understand when a mod is made? (I need to change the value of a boolean flag when a change is made)
This is my code:
public static event EventHandler serbatoiDisponibiliPerErogatoriChanged;
private static ObservableCollection<TabSerbatoi> p_serbatoiDisponibiliPerErogatori = new ObservableCollection<TabSerbatoi>();
public static ObservableCollection<TabSerbatoi> serbatoiDisponibiliPerErogatori
{
get { return p_serbatoiDisponibiliPerErogatori; }
set
{
p_serbatoiDisponibiliPerErogatori = value;
if (serbatoiDisponibiliPerErogatoriChanged != null)
serbatoiDisponibiliPerErogatoriChanged(null, EventArgs.Empty);
}
}
I have also tried to match a function to the event serbatoiDisponibiliPerErogatoriChanged, but it is never called, because, with the debug, I have seen that it entes in the set method only at the init of the window.
The weird point is that the obeservableCollection is correctly updated, but it never passes in the set method.
How can I do it?
UPDATE:
with the mot's answer, I have done this:
void test(object sender, NotifyCollectionChangedEventArgs e)
{
Debug.WriteLine("test");
}
and
serbatoiDisponibiliPerErogatori.CollectionChanged += test;
but, again, it is never called... it never enters in the "test" function.. why?
The problem is that the collection is not being set again, it is modified in the inside.
If you want to track added/removed elements INSIDE the collection, you can register to the CollectionChanged event.
serbatoiDisponibiliPerErogatori.CollectionChanged += MyEventHandler;

Create an event to watch for a change of variable

Let's just say that I have:
public Boolean booleanValue;
public bool someMethod(string value)
{
// Do some work in here.
return booleanValue = true;
}
How can I create an event handler that fires up when the booleanValue has changed? Is it possible?
Avoid using public fields as a rule in general. Try to keep them private as much as you can. Then, you can use a wrapper property firing your event. See the example:
class Foo
{
Boolean _booleanValue;
public bool BooleanValue
{
get { return _booleanValue; }
set
{
_booleanValue = value;
if (ValueChanged != null) ValueChanged(value);
}
}
public event ValueChangedEventHandler ValueChanged;
}
delegate void ValueChangedEventHandler(bool value);
That is one simple, "native" way to achieve what you need. There are other ways, even offered by the .NET Framework, but the above approach is just an example.
INotifyPropertyChanged is already defined to notify if property is changed.
Wrap your variable in property and use INotifyPropertyChanged interface.
Change the access of the BooleanValue to private and only allow changing it through one method for consistency.
Fire your custom event in that method
.
private bool _boolValue;
public void ChangeValue(bool value)
{
_boolValue = value;
// Fire your event here
}
Option 2: Make it a property and fire the event in the setter
public bool BoolValue { get { ... } set { _boolValue = value; //Fire Event } }
Edit: As others have said INotifyPropertyChanged is the .NET standard way to do this.
Perhaps take a look at the INotifyPropertyChanged interface. You're bound to come across it's use again in future:
MSDN: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
CallingClass.BoolChangeEvent += new Action<bool>(AddressOfFunction);
In your class with the bool property procedure:
public event Action<bool> BoolChangeEvent;
public Boolean booleanValue;
public bool someMethod(string value)
{
// Raise event to signify the bool value has been set.
BoolChangeEvent(value);
// Do some work in here.
booleanValue = true;
return booleanValue;
}
No it is not possible* to get notified about for changes in value of a variable.
You can achieve almost what you want by making the value to be a property of some class and fire events on change as you wish.
*) if your code is debugger for a process you can make CPU to notify you about changes - see data chage breakpoints in Visual Studio. This will require at least some amount of native code and harder to implement correctly for manged code due to hance of objects to be moved in memory by GC.

Getting the previous value of an object at ValueChanged event

I am trying to get the previous value of DateTimePicker when it hits the event ValueChanged. The other possible solution to my problem would be getting whether the user clicked on a value and chose it or it was invoked by some method. My problem is I need to know what caused this event and execute some code only if the previous value was different. I have read this and didn't like the solution to the possible way #2.
So again:
if user clicks
{
execute some code
}
else // if method was invoked
{
do NOT execute
}
OR
if value is NOT the same as previously
{
execute some code
}
else
{
do NOT execute
}
Either of that suits me, but I am unable to find the previous value in the list of available properties nor in EventArgs (which is null :( ). Hope I was clear what I want to achieve. If you ask for the reasons that I need this, it is irrelevant and I cannot edit the other code, just this method.
The ValueChanged-Event, as the name implies, will only be fired when the Value of the DateTimePicker changes.
You do not have to check if the value has changed in your code.
You are stating that you EventArgs is null, but it should be EventArgs.Empty, when used in an unmodified framework.
If you want to do something else with the LastValue you can use a customized DateTimePicker like this.
public class LastDateTimePicker : DateTimePicker {
protected override void OnValueChanged(EventArgs eventargs) {
base.OnValueChanged(eventargs);
LastValue = Value;
IsProgrammaticChange = false;
}
public DateTime? LastValue { get; private set; }
public bool IsProgrammaticChange { get; private set; }
public new DateTime Value {
get { return base.Value; }
set {
IsProgrammaticChange = true;
base.Value = value;
}
}
}
EDIT I have changed my example to met your requirements of checking programmatic changes, as stated in your comment.
The ValueChanged event is fired post validation, after the value has changed. You can't get the value before the change from this event.
If you want to extend the validation of the control then you could use the Validating event.
If you just want to trigger some code after the change then you could write code to store the previous value, somthing like this.
private DateTime oldValue = SomeDateTimePicker.Value;
private SomeDateTimePickerValueChanged(object sender, EventArgs e)
{
if (SomeDateTimePicker.Value != oldValue)
{
//Do Something
}
this.oldValue = SomeDateTimePicker.Value
}

Categories

Resources