Simple switch causes stack overflow - c#

Why this simple code causes fallowing error :
Cannot evaluate expression because the current thread is in a stack overflow state.
private void barButtonPanelVisibleCheck_CheckedChanged(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
switch (barButtonPanelVisibleCheck.Checked)
{
case true:
this.navBarControl.Visible = false;
this.barButtonPanelVisibleCheck.Checked = false;
break;
case false:
this.navBarControl.Visible = true;
this.barButtonPanelVisibleCheck.Checked = true;
break;
}
//or
if (barButtonPanelVisibleCheck.Checked == true)
{
this.navBarControl.Visible = false;
this.barButtonPanelVisibleCheck.Checked = false;
}
else
{
this.navBarControl.Visible = true;
this.barButtonPanelVisibleCheck.Checked = true;
}
}

You are changing Checked from within the Checked handler: Checked value is set, so the handler is called, which sets Checked value etc. and you have an infinite loop.

Since you are trying to change the checked state of your checkbox while you are inside the CheckedChanged event, you raise another CheckedChanged event, and this starts an infinite loop that consume the stack memory until you reach the StackOverflow exception.
Try to stop the recursion on your CheckedChanged event with
private void barButtonPanelVisibleCheck_CheckedChanged(object sender,
DevExpress.XtraBars.ItemClickEventArgs e)
{
try
{
this.barButtonPanelVisibleCheck.CheckedChanged -=
barButtonPanelVisibleCheck_CheckedChanged;
... do your checked changed here
}
finally
{
this.barButtonPanelVisibleCheck.CheckedChanged +=
barButtonPanelVisibleCheck_CheckedChanged;
}
}
Disconnecting the Event handler allows to change the checked state without reentry the event handler, after that, reconnect the event. Probably for this scenarion there is no need to use a try/finally but using finally will ensure that the event is always reconnected in case your code fails with an exception.

When checked state of the control is changed, method barButtonPanelVisibleCheck_CheckedChanged is called. In that method you change the Checked property of that control, which causes call to method barButtonPanelVisibleCheck_CheckedChanged. In that method you change the Checked property of that control.

Related

Webview2 Navigation

Currently in Webview2 browser if navigated to a particular URL as written below
browser.Source = URL;
This triggers NavigatingStarting event asynchronously.
How can I trigger a synchronous call for each source being set to trigger the event?
Problem: I am keeping a bool variable to check for the if navigation triggered inside my application and resetting it at the end for the navigatingstarting event. since it is an asynchronous call it is resetting after the first call without the next call being inside my application.
void SetBrowserUrl(Uri value)
{
m_bInsideNavigateCall = true;
priorsWebBrowser.Source = value;
}
void priorsWebBrowser_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e)
{
if(m_bInsideNavigateCall)
{
e.Cancel = false;
m_bInsideNavigateCall = false; // Reset for next inside call
}
else
{
e.Cancel = true;
}
}
Here the issue is if call SetBrowserUrl twice. Navigate starting cancels the second call made because it is not synchronous
I have created a list of strings.
List<String> insideNavigatingURLS; //Class level variable
Just before calling web-browser to navigate, I add the URL to list.
internalURLs.Add(uri.AbsolutePath.ToLower());
webBrowser.Source = uri;
In the NavigationStarting Event added a check to see if list contains the navigation url if it doesn't then will cancel the request.
void webBrowser_Navigating(object sender, CoreWebView2NavigationStartingEventArgs e)
{
if (!internalUrls.Contains(e.Uri))
{
e.Cancel = true;
}
else
{
internalUrls.Remove(e.Uri);
e.Cancel = false;
}
}
So when back or forward navigation is triggered, the list doesn't contain a URL and the navigation request is cancelled

UWP app drops stack owerflow exception when turning on XAML switch by code C#

I use the IsOn property of toggle switches and when I try to both get, and set the IsOn property of a switch, it just crashes with system.stack overflow exception.
How can solve this? Or can I set the state of toggle switch with other methods?
(the Switch1_Toggled happens by human interaction, before the turnit method)
public void turnit()
{
Switch1.IsOn = true;
}
public void Switch1_Toggled(object sender, RoutedEventArgs e)
{
if(Switch1.IsOn)
{
request = "11";
}
else
{
request = "10";
}
SendRequest();
//ReceiveResponse();
//statusupdater();
turnit();
}
You are encountering an infinite loop. When you toggle the switch via Switch1.IsOn = true;, it will trigger your handler method Switch1_Toggled, which in turn calls turnit(), which in turn...
A stack overflow occurs because there is not enough room in stack memory to store the infinite depth of call heirarchy.
Remove the call to turnit inside the handler and you should be good.

On ASP.NET formview when are the ModeChanged and ModeChanging events raised?

This popped up, when I was trying to find why the OnModeChanging handler wasn't being called when I called the ChangeMode event of my formview.
On the formview's ChangeMode method MSDN page , it is stated that it:
switches the FormView control to the specified data-entry mode
but also that:
the ModeChanged and ModeChanging events are not raised when this method is called
And in the ModeChanged and ModeChanging events pages, it says that they occur:
when the FormView control switches between edit, insert, and read-only mode
after/before the mode changes, respectively.
Can you explain it to me: when are the ModeChanged/ing events raised?
And, is there a way to force these events to be raised?
I think I know why now. I've found an answer in other forum, and though I didn't find the code of FormView, I've found a DetailsView implementation and I think in this case it might be similar.
Basically what I've understood of it, is that the ModeChanged/ing events are raised when command buttons are clicked (Cancel, Edit, Insert, New and Update), i.e. when one doesn't have direct control over these events, and when we use the ChangeMode method, we know that the mode has changed (or will be changed) and it would make no sense of raising an event..
DetailsView ChangeMode:
public void ChangeMode(DetailsViewMode newMode) {
Mode = newMode;
}
DetailsView command handlers:
private void HandleCancel() {
bool isBoundToDataSourceControl = IsBoundUsingDataSourceID;
DetailsViewModeEventArgs e = new DetailsViewModeEventArgs(DefaultMode, true);
OnModeChanging(e);
if (e.Cancel) {
return;
}
if (isBoundToDataSourceControl) {
Mode = e.NewMode;
OnModeChanged(EventArgs.Empty);
}
RequiresDataBinding = true;
}
private void HandleEdit() {
if (PageIndex < 0) {
return;
}
DetailsViewModeEventArgs e = new DetailsViewModeEventArgs(DetailsViewMode.Edit, false);
OnModeChanging(e);
if (e.Cancel) {
return;
}
if (IsBoundUsingDataSourceID) {
Mode = e.NewMode;
OnModeChanged(EventArgs.Empty);
}
RequiresDataBinding = true;
}
private bool HandleInsertCallback(int affectedRows, Exception ex) {
DetailsViewInsertedEventArgs dea = new DetailsViewInsertedEventArgs(affectedRows, ex);
dea.SetValues(_insertValues);
OnItemInserted(dea);
_insertValues = null;
if (ex != null && !dea.ExceptionHandled) {
if (PageIsValidAfterModelException()) {
return false;
}
dea.KeepInInsertMode = true;
}
if (!dea.KeepInInsertMode) {
DetailsViewModeEventArgs eMode = new DetailsViewModeEventArgs(DefaultMode, false);
OnModeChanging(eMode);
if (!eMode.Cancel) {
Mode = eMode.NewMode;
OnModeChanged(EventArgs.Empty);
RequiresDataBinding = true;
}
}
return true;
}
private void HandleNew() {
DetailsViewModeEventArgs e = new DetailsViewModeEventArgs(DetailsViewMode.Insert, false);
OnModeChanging(e);
if (e.Cancel) {
return;
}
if (IsBoundUsingDataSourceID) {
Mode = e.NewMode;
OnModeChanged(EventArgs.Empty);
}
RequiresDataBinding = true;
}
private bool HandleUpdateCallback(int affectedRows, Exception ex) {
DetailsViewUpdatedEventArgs dea = new DetailsViewUpdatedEventArgs(affectedRows, ex);
dea.SetOldValues(_updateOldValues);
dea.SetNewValues(_updateNewValues);
dea.SetKeys(_updateKeys);
OnItemUpdated(dea);
_updateKeys = null;
_updateOldValues = null;
_updateNewValues = null;
if (ex != null && !dea.ExceptionHandled) {
if (PageIsValidAfterModelException()) {
return false;
}
dea.KeepInEditMode = true;
}
if (!dea.KeepInEditMode) {
DetailsViewModeEventArgs eMode = new DetailsViewModeEventArgs(DefaultMode, false);
OnModeChanging(eMode);
if (!eMode.Cancel) {
Mode = eMode.NewMode;
OnModeChanged(EventArgs.Empty);
RequiresDataBinding = true;
}
}
return true;
}
With ChangeMode you are choosing that the control switch to one of it's modes.
When it starts to performing this task, the ModeChanging event is raised (to indicate that it's in progress) (optionally do something here).
Once that task is completed, it raises the ModeChanged event (to indicate that it's done) (optionally do something here).
[Updated]
I see your point. How could you consume the events if they don't get raised.
I'm going to guess at it, that they don't get raised initially because of nothing to do, just perform the changing of the mode.
In either case I guess, it's more of a state change than the raising of events.
[Updated]
I think what we are both saying is that if no one has subscribed to the event (i.e., no one is listening for it), there's no point in raising it.

Determine who fired an event

Background:
In my winforms form, I have a Checked ListView and a "master" checkbox called checkBoxAll.
The behaviour of the master is as follows:
If the master is checked or unchecked, all ListViewItems must change accordingly.
If the user unchecks a ListViewItem, the master must change accordingly.
If the user checks a ListViewItem, and all other ListViewItems are checked aswell, the master must change accordingly.
I have written the following code to mimic this behaviour:
private bool byProgram = false; //Flag to determine the caller of the code. True for program, false for user.
private void checkBoxAll_CheckedChanged(object sender, EventArgs e)
{
//Check if the user raised this event.
if (!byProgram)
{
//Event was raised by user!
//If checkBoxAll is checked, all listviewitems must be checked too and vice versa.
//Check if there are any items to (un)check.
if (myListView.Items.Count > 0)
{
byProgram = true; //Raise flag.
//(Un)check every item.
foreach (ListViewItem lvi in myListView.Items)
{
lvi.Checked = checkBoxAll.Checked;
}
byProgram = false; //Lower flag.
}
}
}
private void myListView_ItemChecked(object sender, ItemCheckedEventArgs e)
{
//Get the appropiate ListView that raised this event
var listView = sender as ListView;
//Check if the user raised this event.
if (!byProgram)
{
//Event was raised by user!
//If all items are checked, set checkBoxAll checked, else: uncheck him!
bool allChecked = true; //This boolean will be used to set the value of checkBoxAll
//This event was raised by an ListViewItem so we don't have to check if any exist.
//Check all items untill one is not checked.
foreach (ListViewItem lvi in listView.Items)
{
allChecked = lvi.Checked;
if (!allChecked) break;
}
byProgram = true; //Raise flag.
//Set the checkBoxAll according to the value determined for allChecked.
checkBoxAll.Checked = allChecked;
byProgram = false; //Lower flag.
}
}
In this example, I use a flag (byProgram) to make sure an event was caused by the user or not, thereby preventing an infinite loop (one event can fire another, which can fire the first one again etc. etc.). IMHO, this is a hacky solution.
I searched around but I couldn't find a MSDN documented method to determine if an User Control Event was directly fired thanks to the user. Which strikes me as odd (again, IMHO).
I know that the FormClosingEventArgs has a field which we can use to determine if the user is closing the form or not. But as far as I know, that is the only EventArg that provides this kind of functionality...
So in summary:
Is there a way (other than my example) to determine if an event was fired directly by the user?
Please note: I don't mean the sender of an event! It won't matter if I code someCheckBox.Checked = true; or manually set someCheckBox, the sender of the event will always be someCheckBox. I want to find out if it is possible to determine whether it was through the user (click) or by the program (.Checked = true).
Aaand also: 30% of the time it took to write this question was to formulate the question and the title correctly. Still not sure if it is a 100% clear so please edit if you think you can do better :)
No, there's no practical way to determine whether the change came from GUI or was done by program (in fact, you could analyze the callstack - but that's not recommended because it's very slow and error-prone).
BTW, there's one other thing you could do instead of setting byProgram. You could remove and add the event handler prior or after, respectively, change your controls:
checkBoxAll.CheckedChanged -= checkBoxAll_CheckedChanged;
// do something
checkBoxAll.CheckedChanged += checkBoxAll_CheckedChanged;
Instead of using the changed event, you could use the clicked event to cascade the change through to the relevant controls. This would be in response to a user click, and not the value being changed programatically.
This is something I come across quite a lot and what I tend to try do is not split it between user interaction vs program interaction - I use more generic code i.e. the UI is being updated and doesn't require any events to be handled. I usually package this up through BeginUpdate/EndUpdate methods e.g.
private int updates = 0;
public bool Updating { get { return updates > 0; } }
public void BeginUpdate()
{
updates++;
}
public void EndUpdate()
{
updates--;
}
public void IndividualCheckBoxChanged(...)
{
if (!Updating)
{
// run code
}
}
public void CheckAllChanged(...)
{
BeginUpdate();
try
{
// run code
}
finally
{
EndUpdate();
}
}

conditional check to wait for favourable condition

i have a condtion if (!e.ComponentUp) ,if its true then i need to wait until it Up what check i can give here
I did this code but its not working
if (!e.ComponentUp)
{
do
{
while (e.ComponentUp);
}
}
Your code cannot work.
First, if the predicate is false, then the while loop will exit immediately. You would need to loop on the negation.
Second, unless it's volatile and being changed asynchronously, the loop won't end.
Third, this sort of polling will max out the CPU.
Use an event.
You could create an event on your Component called something like 'UpChanged' and subscribe to the event. When you come to the code that can only run when the component is in the 'Up' state you could set a flag that indicates your 'task' is waiting for the up state to change. Something like this:
//When you initialize
var e = ...;
e.UpChanged += new EventHandler(Component_UpChanged);
bool waitingForUp = false;
//The code snippet that is waiting for up to be enabled
if (!e.ComponentUp)
waitingForUp = true;
else
DoWorkHere();
//The delegate
void Component_UpChanged(object sender, EventArgs e)
{
if (e.ComponentUp && waitingForUp)
DoWorkHere();
waitingForUp = false;
}
Why don't you use events ? Is that a 3rd party component ?

Categories

Resources