Terminal.Gui
Terminal.Gui copied to clipboard
I am using combobox control, when I delete characters It throws the same error **IndexOutOfRangeException**
I am using combobox control, when I delete characters It throws the same error IndexOutOfRangeException
Originally posted by @ttool22 in https://github.com/gui-cs/Terminal.Gui/issues/1250#issuecomment-1211739635
@ttool22 I have moved the discussion to a new issue because the one you posted in is about scroll view. So while the Exception is the same (IndexOutOfRangeException) the root cause is likely to be different.
I've created a new console project with a combo box and it is working fine in 1.7.2
using Terminal.Gui;
Application.Init();
var w = new Window();
ComboBox combobox1 = new ComboBox();
combobox1.SetSource(new List<string> { "cow", "dog", "fish" });
combobox1.Width = 10;
combobox1.Height = 4;
w.Add(combobox1);
Application.Run(w);
Application.Shutdown();
Can you provide more information about how your use case varies from the above?
- Do you have any event handlers?
- Do you ever change the source of the combo box? (e.g. from another Thread or in a callback)
One thing that might help is if you can get a stack trace. The easiest way to do this is to add an Exception handler to the main loop. To do that you can swap Application.Run(myWindow)
to use the overload:
Application.Run(myWindow, (e) =>
{
MessageBox.ErrorQuery("Badness", e.ToString(), "Ok");
return false;
}
);
If you implement the above block you should get an error box instead of a hard crash:
Example error message shown by registering an Exception callback
Yes, I have event handler for refreshing time every second. I call eventhandler for refreshing time in OpenSelectedItem
timer.Elapsed += RefreshMatchTime
;
timer.Start();
static void RefreshMatchTime(object sender, ElapsedEventArgs e) { MatchTime.Text = DateTime.Now.Second.ToString(); Application.Refresh(); }
Ok thanks for the info. I think I am able to reproduce your error. Here is my repro:
using System.Timers;
using Terminal.Gui;
Application.Init();
var w = new Window();
ComboBox combobox1 = new ComboBox();
combobox1.SetSource(new List<string> { "cow", "dog", "fish" });
combobox1.Width = 10;
combobox1.Height = 4;
w.Add(combobox1);
// I have changed this to every 100th of a second to make the Exception manifest faster
var timer = new System.Timers.Timer(10);
timer.Elapsed += (s, e) => {
combobox1.Text = DateTime.Now.Second.ToString();
Application.Refresh();
};
timer.Start();
Application.Run(w, (e) =>
{
MessageBox.ErrorQuery("Badness", e.ToString(), "Ok");
return false;
}
);
Application.Shutdown();
The solution is to always use Application.MainLoop.Invoke
to update UI properties. Please can you try updating your RefreshMatchTime
method to use invoke:
var timer = new System.Timers.Timer(100);
timer.Elapsed += (s, e) => {
Application.MainLoop.Invoke(()=> { combobox1.Text = DateTime.Now.Second.ToString(); });
};
Make sure to get rid of your call to Application.Refresh();
too.
After applying the fix (MainLoop.Invoke)
@ttool22 let me know if my suggestion works. Alternatively if you haven't understood what I have said or how to implement it please say and I will try to rephrase.
If you do get it working make sure to close the issue as resolved
@tznind
Unfortunately it doesn't work
Can you share more of your code please? including the bit you updated with Application.MainLoop.Invoke
timer.Elapsed += RefreshMatchTime;
timer.Start();
static void RefreshMatchTime(object sender, ElapsedEventArgs e)
{
try
{
string matchTime = string.Empty;
Constants.Seconds = Constants.Seconds + 1;
matchTime = Constants.Minutes + " : " + (Constants.Seconds).ToString();
Application.MainLoop?.Invoke(() =>
{
Constants.MatchTime.Text = matchTime;
Application.Refresh();
});
}
catch (Exception ex)
{
}
}
I call it inside
ComboboxControl.OpenSelectedItem += async (ListViewItemEventArgs control) =>
{
//code above
}
}
You didn't call it inside ComboboxControl.OpenSelectedItem, When I click on item in Combobox I start refresh time every second then I remove characters from combo, then error is thrown "IndexOutOfRangeEdxception"
Remove Application.Refresh();
from the code because the Application.MainLoop?.Invoke
already will update the UI Thread.
I have updated and changed the assignment to be a Label rather than the combo box as I assume you are using. It is still working as intended with no Exception.
The differences I can see vs your code are:
- I only create one timer (regardless of how many times user confirms selection)
- I don't call
Application.Refresh
(as @BDisp said)
using System.Timers;
using Terminal.Gui;
Application.Init();
var w = new Window();
Label matchTime = new Label();
matchTime.Width = 20;
matchTime.Height = 1;
matchTime.Y = 6;
ComboBox combobox1 = new ComboBox();
combobox1.SetSource(new List<string> { "cow", "dog", "fish" });
combobox1.Width = 10;
combobox1.Height = 4;
w.Add(combobox1);
w.Add(matchTime);
System.Timers.Timer? timer = null;
/*I've added async keyword here because you have it in your code but it has no effect*/
combobox1.OpenSelectedItem += async (ListViewItemEventArgs control) =>
{
// do not create multiple timers
if(timer == null)
{
timer = new System.Timers.Timer(10);
timer.Elapsed += (s, e) =>
{
Application.MainLoop.Invoke(() => { matchTime.Text = DateTime.Now.Second.ToString(); });
};
}
timer.Start();
};
Application.Run(w, (e) =>
{
MessageBox.ErrorQuery("Badness", e.ToString(), "Ok");
return false;
}
);
Application.Shutdown();