Returning value after invoking event in C# - c#

I am working on a project, where I have to invoke a method when a value gets below a certain threshold. This event then writes some information to the user.
I have decided to put it in the setter, as it should be displayed when the user tries to get information.
The problem is that I still want to get something afterwards (as it is a getter), but I get stackoverflow and I can see that the getter is called many times. I thought this was weird, since the .invoke should only invoke the event and then move on. So how can i move further from the invoke, instead of having it go back to the beginning of the setter every time it is called,
This is the current setter:
get
{
if (_balance <= BalanceThreshold)
UserBalanceNotification.Invoke(this,BalanceThreshold);
return _balance;
}
And this is the general event:
public delegate void UserBalanceNotification(User user, int balanceThreshold);
As this is a more general question I doubt more code snippet would support it

Related

Problem with adding with ++ operator, what can I do?

So, I as trying to create an "Open world exploration" game in C# WinForms, And while coding the mining, (which works just fine), I encountered a problem with saving the number of broken blocks to the inventory (a label). Basically, for every block player breaks, it gets added to the inventory as inventoryWrite.Text = $"Grass: {grassHolder}, Rock: {rockHolder}";.
Now, the thing is, sometimes, even though I use the ++ operator, it adds up to 4 to the inventory. I'm citing the code below.
private void Remove(object sender, EventArgs e, PictureBox itm)
{
if (itm.BorderStyle == BorderStyle.FixedSingle)
{
if (itm.Tag.Equals("grass") && items.Contains(itm))
{
grassHolder++;
itm.Tag = "";
}
if (itm.Tag.Equals("rock") && items.Contains(itm))
{
rockHolder++;
itm.Tag = "";
}
if (itm.Tag.Equals("dio") && items.Contains(itm))
{
dioHolder++;
itm.Tag = "";
}
this.Controls.Remove(itm);
items.Remove(itm);
}
}
I update the inventory in a public loop, don't worry about that (interval is 1ms). But I don't think that's the problem, since I tried putting it in the Remove() function, and nothing seemed to change.
I've even double locked the if statement, but nothing! It still adds more than 1. Can anybody tell me how to solve this? Thank you a lot.
EDIT:
As a reply to Ronald's comment, the if statement is called ONLY when the block is selected. ONLY once when the method is called.
There are too many points to cover in a comment and so I've had to enter an answer.
In itself the ++ operator is not the issue and will always behave as it should, but as someone reviewing a small piece of code the following points crop up.
grassHolder, rockHolder, dioHolder appear to have
accessibility beyond this function and so could be altered
elsewhere.
Function void Remove(object sender, EventArgs e, PictureBox itm) appears to be an event handler and yet there is no locking mechanism to ensure that the externally accessible parameters are not changed or used elsewhere whilst the function code is executed. Specifically items which is appears to be a collection of sorts and is used both in logic to determine whether parameters in (1) are incremented, but also has its contents changed within the function.
From comments made it would appear that this logic is run in
response to user interaction, maybe by use of a mouse button or key
event. Is this base event de-bounced to ensure that multiple
triggers aren't handled?
Your statement "saving the number of broken blocks to the inventory (a label)." Implies that you are storing game data within the UI. This should be avoided as it ties game data directly to the UI implementation and therefore makes it difficult to alter the game, but also ties any handling of game data directly to the UI thread.
Recommended actions:
Ensure that the parameters in question are not accessed and altered
elsewhere causing the issue seen.
Utilize a lock(x) statement to ensure that items is not changed
whilst this function is being executed. More information here
De-bounce the mouse button or key click that triggers this function
to ensure that multiple events aren't triggered. This is performed
by placing a minimum time between event triggers. A minimum time
period of say 150ms would be a good starting point. This would equate to a reasonably quick, conscious user action, but be slower than multiple events triggered by partial/poor switch contact. Incidentally this is especially true on touch screen interfaces.
Consider controlling access to global parameters through use of
access functions. For example
int IncrementRockHolder(){ rockHolder++;} Although implementation may appear onerous, they can greatly help with debugging as call stack information is then available showing what code is calling the function and thus making the change.
Implement a game engine class to control access to game data and implement game logic. This
would allow you to unit test game functionality whilst also freeing
it from UI implementation and restrictions.

Stack overflow exception without infinite loop (as far as I can tell)

I have a stack overflow error, and I'm fairly sure I don't have any kind of infinite recursion (at least I've stared at the error for a few hours now and I can't imagine how its looping infinitely).
Here is the code:
public decimal? Amount
{
get
{
if (!string.IsNullOrEmpty(_savedWork.Amount))
return decimal.Parse(_savedWork.Amount);
else
return null;
}
set
{
if (value.HasValue)
{
_savedWork.Amount = value.Value.ToString();
Percent = null;
}
else
_savedWork.Amount = "";
OnPropertyChanged("Amount");
}
}
#Note I have a string housed in a nullable decimal, that's why I'm converting it. Please don't make me go into why I'm doing this.
the line savedWork.Amount = value.Value.ToString() is where I get the error.
Basically I'm thinking that my stack is just too small (or my code is too big I suppose). I basically run this code twice, and it works when in one form, but not when I make another form and place it in there, so I think the difference between these 2 forms is tipping the stack.
Is there a way to identify what I'm doing wrong? I want to find out what part of the code is taking up a too much or is persisting too long etc.
I've done some research about how the stack/heap work and I know about PerfMon.exe, but as far as I know it only works for the heap. Is there a similar tool that I can use for the stacks my program is running?
I found this post about 2 tools called windbg and cdb but I can't find much about how to install/use them. Are these tools the right way to go?
Alternatively if there is an infinite loop or something that would be great.
Edit
here is the code requested for the Amount Property (its autogenerated by EntityFramework) as I said in the comments, the step into doesn't even reach here. I really do think my stack limit is just being reached.
public global::System.String Amount
{
get
{
return _Amount;
}
set
{
OnAmountChanging(value);
ReportPropertyChanging("Amount");
_Amount = StructuralObject.SetValidValue(value, true);
ReportPropertyChanged("Amount");
OnAmountChanged();
}
}
Final Edit
Ok so Meta-Knight's answer showed me that I did indeed have an infinite loop. I had an event handler subscribed to the PropertyChanged event of the DisplayTypeOfInvestment (the class that the Amount Property belongs to). The handler looked like this:
void DisplayTypeOfInvestmentList_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
_typeOfInvestmentFormSavedWork.TypeOfInvestment.Clear();
foreach (DisplayInvestmentFund d in _displayInvestmentFundList)
{
_typeOfInvestmentFormSavedWork.TypeOfInvestment.Add(d.SavedWork);
}
OnPropertyChanged("TypeOfInvestmentFormSavedWork");
}
The TypeOfInvestmentFormSavedWork is a completely different class that contains in it it's own version of the SavedWork class that we see that is used an the Amount property. The point of this method was to update this TypeOfInvestmentFormSavedWork property to the new value of _savedWork when the Amount property changes. For some reason this is triggering the DisplayTypeOfInvestment viewmodel's PropertyChanged. I didnt figure it out but I changed the method to look like this:
void DisplayTypeOfInvestmentList_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "Amount" || e.PropertyName == "Percent")
{
_savedWork.TypeOfInvestment.Clear();
foreach (DisplayInvestmentFund d in _displayInvestmentFundList)
{
_savedWork.TypeOfInvestment.Add(d.SavedWork);
}
OnPropertyChanged("CurrentWork");
}
}
The if statement stops the weird properties being changed in the DisplayInvestmentFund when the Add method is called.
I realise this answer doesnt make much sense, but for me to explain this in full detail would take a very long time. I also realise that this probably means my code is bad. I'm not sure what to do about that. Thanks for the help guys.
My guess is that you're assigning to Amount in one of the event handlers that OnPropertyChanged calls.
Another possibility is that you have code in the setter of SavedWork.Amount that calls YourClass.Amount again.
But why don't you just debug it? Just step through the code in the Visual Studio debugger.
The stack trace should also be useful. With endless recursion you typically get a repeating sequence of methods. If my guess is correct the repeated part will be something like:
MyClass.set_Amount
MyClass.OnPropertyChanged
OtherClass.myClass_amount_changed
Is the class of which Amount member of the same type as _savedWork?
Because there could be this loop:
1) You assign a value to Amount
2) Before the value is set, you assign a value to _savedWork.Amount
3) Before the value of _savedWork.Amount is set, the line is triggered again
4) Before the value of _savedWork._savedWork.Amount is set...
5) Before the value of _savedWork._savedWork._savedWork.Amount is set...
And this goes to infinity and beyond.
There must be a recursive call to the Amount setter somehow. You could debug it by "stepping into" the properties instead of stepping over. If you set VS so that it doesn't step into properties, you can still put a breakpoint inside your setters to simulate a "step into". As for VS not stepping into .edmx files, as CodeInChaos mentioned, maybe the class is tagged with a DebuggerStepThrough attribute.
Is _savedWork an object of the same type as the Amount property you listed? Because that will give you a stack overflow error! In that case, you need to find a way to talk about Amount without invoking the getter and setter.

Difference between Events and Methods

I have some confusion regarding Events. What are the basic differences between C# Events and Methods?
A method is simply code contained within a class to implement a piece of functionality. All code in C# is contained within methods.
As for events, well, suppose you had a simple class which implemented a counter (lets call it the Counter object). Now suppose you wanted to let other objects unrelated to Counter know when the count reached 100. How would you do it?
A logical way would be to allow the other objects to specify one of their own methods they want to be called when the count reaches 100. Each object could then, individually, tell the Counter object which method they want to be called. The Counter object saves this list of methods and, when the count reaches 100, calls each of the saved methods in turn.
This is the how Events work - the Counter class contains an event member (called say, CounterIs100) which other object instances link one of their own methods to. When the Counter object detects that it has has reached 100, it invokes the CounterIs100 member which, automatically, calls all the methods currently linked to it, thus notifying each object in turn that the count has indeed reached 100.
If no objects have linked a method to the CounterIs100 event member, it will be null, so there is no need for the Counter object to invoke the event member.
class Counter
{
// this is the count field used to save the current count value
private int count;
// this is the event member which holds all the methods other objects have specified
public event CounterIs100Delegate CounterIs100;
// This is a method. It invokes the CounterIs100 event member if anyone has subscribed to it
protected void OnCounterIs100()
{
// see if anyone has subscribed (linked) their method to this event
if (CounterIs100 != null)
{
// invoke the event - this will call all subscribed methods
CounterIs100();
}
}
// This is a method. It increments the counter variable stored by this object
public void Increment()
{
count++;
// if the count is 100, invoke the event
if (count == 100)
OnCounterIs100();
}
}
// This is a delegate. It is used to define a template for other objects wishing to
// subscribe to the CounterIs100 event. The methods other objects link to the
// CounterIs100 event must match this declaration (although the name can be changed)
public delegate void CounterIs100Delegate();
// This is a class, unrelated to Counter, but uses its events
class SiteHits
{
Counter hitCounter = new Counter();
public SiteHits()
{
// We want to know when the number of site hits reaches 100.
// We could monitor this ourselves, but we know the Counter class already
// does this, so we just link our method to its event
hitCounter.CounterIs100 += this.WhenSiteHitsReaches100;
}
public void PageRequested()
{
// someone has requested a page - increment the hit counter
Console.WriteLine("We've been hit!");
hitCounter.Increment();
}
// this is the method we want called when the CounterIs100 event occurs.
// note that the return value and parameters match CounterIs100Delegate above.
public void WhenSiteHitsReaches100()
{
Console.WriteLine("Woohoo! We've reached 100 hits!");
}
}
C# Events are a specific form of delegates. If you have programmed in other languages, like C++, you could compare a delegate to a function ("method") pointer - it points to some code in memory. When you call the pointer as a method, you actually call the method at the address the pointer points to.
This is necessary to provide decoupling between the caller and the callee - so you don't have to have all methods ready when you publish code that calls them (which, wouldn't be possible - the Forms controls developers can't possibly know the code that needs to be called when a Button is pressed). You call the pointer, and the other developer sets it to an appropriate memory address later.
P.S. delegates and Events however, have other advantages over plain function pointers - you can be sure that it will point to a good-looking method, taking the correct number and type of arguments and returning the correct type.
An event in C# is a way for a class to provide notifications to clients of that class when some interesting thing happens to an object.
http://msdn.microsoft.com/en-us/library/aa645739%28v=vs.71%29.aspx
A method is a code block containing a series of statements. In C#, every executed instruction is done so in the context of a method.
http://msdn.microsoft.com/en-us/library/ms173114%28v=vs.80%29.aspx
An event in .net is a pair of methods, one for "Add" and one for "Remove", each of which accepts a delegate. Typically, the "Add" method will take the passed-in delegate and add it to either a list of delegates or a MulticastDelegate; passing a delegate to the "Remove" event which was previously passed to the "Add" method should remove that delegate from the list. If one doesn't request otherwise, both C# and vb.net will by default automatically create "Add" and "Remove" events which will behave as indicated above.
This is from MSDN:
An event in C# is a way for a class to provide notifications to clients of that class when some interesting thing happens to an object.
http://msdn.microsoft.com/en-us/library/aa645739%28v=vs.71%29.aspx
A method is a code block containing a series of statements. In C#, every executed instruction is done so in the context of a method.
http://msdn.microsoft.com/en-us/library/ms173114%28v=vs.80%29.aspx

How to completely remove all items for an event which is static

I have a class, Plotter, which has a static event (declared public static event MouseEventHandler MultiCursorMouseMove for those wondering how I have a static event).
It emulates a graphical plot and our current application displays about 30-40 of them. The purpose of the event is to draw a cursor across all displayed graphs to indicate the value for the graph at the time the mouse cursor is pointing at.
The problem I'm running into is that, because the Plotter instances have this static event, they refuse to die. As best I can tell looking at them in a memory profiler, every instance of a Plotter (as well as the Form which contains them) is being held in memory by an EventHandler tied to this MultiCursorMouseMove event. I have coded set up which runs the Dispose method on each of the Plotter instances, which includes removing the delegate from MultiCursorMouseMove, but it doesn't seem to be doing any good. According to what I can see via the debugger, Plotter.MultiCursorMouseMove registers as null, but these instances still aren't getting collected and, best as I can tell via the profiler, all of the instances continue to exist due to MultiCursorMouseMove.
So, the question I have is, is there any way to explicitly state "remove all delegates associated with this event"?
I figure that way I'll be sure I got rid of all of them, not to mention it will simplify things compared to my current code which, during the Dispose method, cycles through all of the controls on the tab and runs Dispose on all of the Plotter objects it finds.
To be perfectly open, I submitted this question last week but after saying it was solved, I found another issue. I tried editing the question, but it seems to have fallen out of public view.
So, the question I have is, is there any way to explicitly state
"remove all delegates associated with this event"?
Have you tried explicitly setting "MultiCursorMouseMove" to null?
You could expand your event syntax to track add/remove calls to find out those objects which didn't not unsubscribe:
public static event MouseEventHandler MultiCursorMouseMove
{
add
{
}
remove
{
}
}
You could also follow Weak event pattern, or the one described by J. Richter. Weak handlers are based on weak references, which don't block GC.
And, at last, you could use hard-core Reflection approach to clean array of delegates in static MouseEventHandler object.

PropertyChanged affecting several properties

I have a situation where I have a couple of variables who's values depend on each other like this:
A is a function of B and C
B is a function of A and C
C is a function of A and B
Either value can change on the UI. I'm doing the calculation and change notification like this:
private string _valA;
private string _valB;
private string _valC;
public string ValA
{
get { return _valA; }
set
{
if (_valA != value)
{
_valA = value;
RecalculateValues("ValA"); //Here ValB and ValC are calculated
OnPropertyChanged("ValA");
}
}
}
public string ValB
{
get { return _valB; }
set
{
if (_valB != value)
{
_valB = value;
RecalculateValues("ValB"); //Here ValA and ValC are calculated
OnPropertyChanged("ValB");
}
}
}
(...)
private void RecalculateValues(string PropName)
{
if (PropName == "ValA")
{
_valB = TotalValue * _valA;
OnPropertyChanged("ValB");
_valC = something * _valA
OnPropertyChanged("ValC");
}
else
(...)
}
I'm calling the calculation method on the setter of the changed variable, calculating the values for _valB, _valC (for example) and then calling PropertyChanged for these ones.
I do it like this because of the dependencies between the variables, like this i can control which variable gets calculated with the correct values. I also thought about triggering the PropertyChanged for the other variables and perform the calculation on the getter of the variables but i would have to know which property changed before and use that value...not sure if it's the best/simplest solution.
Is this a good way to do this? I don't like the idea of performing this on the setter block, but at the time I can't see any better way to do it.do you see any other (better or cleaner solution)?
Another issue I have is using IdataErrorInfo for validation/presenting error info to the UI.The thing is the this[columnName] indexer gets called at the end of the setter and I needed to validate the values before the calculation, so that if the value inputted is not valid the calculation would not happen.I'm seriously considering abandoning IDataErrorInfo and simply calling my validation method before the calculation(s) occurs. Is there any way to explicitly calling it or right after the value attribution?
NOTE: ValidationRules are not an option because I need to call validation logic on another object from my ViewModel.
Its alright to call your Validation and Calculation in Setter, as long as it does not block the thread and goes into heavy cpu intensive calculations. If you have simple 5 to 10 math based statements without involving complex loops, its alright.
For databinding and WPF, this is the only way, However there is one more implementation called IEditableObject which has BeginEdit, CancelEdit and EndEdit, where you can do your calculation and validation on "EndEdit" function.
In BeginEdit, you can save your all values in temp storage, in CancelEdit you can bring back all values from temp and fire PropertyChaged event for all values those were modified and in EndEdit, you can finally update all variables and fire PropertyChanged for all those are updated.
IEditableObject will be best for performance wise, but it may not display new values until it was cancelled or ended, however to display instantly the only way to do is the way you are doing it.
In case of heavy cpu usage, you can invoke another thread to do calculation and set variables and at the end you can fire PropertyChanged, but yes technicaly you are just doing same thing while setting value in setter but asynchronously.
Since you can evoke NotifyPropertyChanged from anywhere in the class, one way to simplify this is to have your Calculate method fire the NotifyPropertyChanged for all three variables. I use this trick when I have complex calculations with multi-dependencies. Sometimes you'll still want to fire the event in the Setter: in that case I use a flag field to disable the event when I am updating the property from within the Calculations so that the event is not fired twice.

Categories

Resources