I have a checkBox in my Windows application called "Continuous". When user checks this and clicks "Process" button, application will process all the items in the listBox. However if user does not check this box it will only process the first one in the list.
In my Process method I want to write an if condition to check the checkBox checked and execute the foreach loop otherwise execute just the first item.
Here is my code
private void btnProcess_Clicl()
{
bool bDone = false;
while(!bDone)
{
LoadList(); //This will load the list from database into listBox
if(listBox.items.Count > 0)
{
ProcessList();
}
if(!chkBox.Checked)
bDone = true;
}
}
I've implement the foreach loop to process list in ProcessList() method. Is there anyway to avoid executing LoadList() method from executing if the user checks continuous checkBox? LoadList() will populate the listBox from database.
do something like this
if( chkBox.Checked )
ProcessList();
else
ProcessOne();
Write the functions to do what you want
update
to avoid duplicating the processing code you could do something like
public void ProcessList()
{
foreach( var item in list )
ProcessOne( item );
}
Factoring is your friend.
void ProcessList(int start, int count) {
for (int i=start; i < start + count; i++) {
ProcessItem(i);
}
}
void ProcessItem(int i) { // your code here
}
private void btnProcess_Click() {
if (IsContinuous) {
ProcessList(0, list.Count);
}
else {
ProcessItem(0);
}
}
private bool IsContinuous { get { return chkBox.Checked; } }
This will work for you but I don't especially like it since I think Process should be part of the list data structure itself and not my UI. Model (and View) and Control should be separate (if possible).
Boolean doAllItems = chkBox.Checked;
foreach(Object something in collection)
{
DoWork(something);
if(!doAllItems)
break;
}
Related
Im using a multi-select ListView in C# .NET 4.5
The issue occurs when selecting multiple items (ie. Shift + End or Shift + Click, etc.) These are just a few examples of many different mouse/keyboard combinations for multi-selecting of course..
This is my event handler for when selecting items in a list:
private void lvTitles_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
MessageBox.Show(e.Item.Text.ToString());
//MessageBox just for testing I am actually running a SQL query here
}
My problem is that if I select 500 items the event is triggered 500 times. The intent is to get that last item the user selected (via keyboard/mouse combinations mentioned above), on and do something with it ... in my case I need to run a SQL query against it.
If I click first on item 0 in the listview it is ok to run the query, then when you shift+end it highlights all the rest, and I want it to run the query only on the last item selected. Instead it is running on every item in between.
EDIT: On another note, the event triggers as it unselects as well, in which case it really shouldn't do anything when deselecting.
Have you considered performing the action on a button press instead? That way they can also use Ctrl-Click to select any individual items they want?
Otherwise what you would have to do is wait a certain amount of time before firing the action, known as debouncing, you can read a more about debouncing here: https://stackoverflow.com/a/4517995/984780
I created a class you can use for debouncing:
public class Debounce {
private Action _action;
private bool _isThreadRunning;
private Thread _thread;
private DateTime _runAt;
private double _waitSeconds;
private Debounce(double waitSeconds, Action action) {
_action = action;
_waitSeconds = waitSeconds;
}
private void Invoke() {
_runAt = DateTime.Now.AddSeconds(_waitSeconds);
lock(this) {
if(!_isThreadRunning) {
_isThreadRunning = true;
_thread = new Thread(() => {
while(true) {
Thread.Sleep(100);
lock(this) {
if(DateTime.Now > _runAt) {
_action();
_isThreadRunning = false;
_thread = null;
break;
}
}
}
});
_thread.Start();
}
}
}
private static Dictionary<Action, Debounce> __debounces;
private static Dictionary<Action, Debounce> _debounces {
get {
if(__debounces == null) {
__debounces = new Dictionary<Action, Debounce>();
}
return __debounces;
}
}
public static void Run(double waitSeconds, Action action) {
Debounce debounce;
if(!_debounces.TryGetValue(action, out debounce)) {
debounce = new Debounce(waitSeconds, action);
_debounces.Add(action, debounce);
}
debounce._waitSeconds = waitSeconds;
debounce.Invoke();
}
}
Then you can change your code to this:
private void lvTitles_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
Debounce.Run(5, () => MessageBox.Show(e.Item.Text.ToString()));
}
This should work no matter how they select items, it will run your code 5 seconds after their last selection action.
I just wrote this class and did a quick test, a more thorough test would be advised. In any case hopefully it's enough to get the idea.
Best method to listen when checkbox is enabled / disabled (in Unity Editor) ?
I want to enable and disable while running/playing scene
Maybe possible to toggle once and Editor could wait when i click again?
I don't need every update scan list..
My code:
void Update () {
checkboxStatus(visibleLocations, locationsList);
}
public void checkboxStatus(bool checkboxEnabled, List<GameObject> list)
{
if (list.Count > 0)
{
foreach (var item in list)
{
if (checkboxEnabled)
{
item.GetComponentInChildren<MeshRenderer>().enabled = true;
}
else
{
item.GetComponentInChildren<MeshRenderer>().enabled = false;
}
}
}
}
You could simply store and compare the previous value. You could optionally also add pre-processors in order to make the Update method only exist in the editor but later in a build only use the method call (see Platform dependent compilation) like
#if UNITY_EDITOR
private bool _lastVisibleLocations;
private void Update ()
{
if(visibleLocations != _lastVisibleLocations)
{
checkboxStatus(visibleLocations, locationsList);
_lastVisibleLocations = visibleLocations;
}
}
#endif
public void checkboxStatus(bool checkboxEnabled, List<GameObject> list)
{
// You can skip the check for Count here
// if there are no elements then foreach simply will do nothing anyway
foreach (var item in list)
{
// your if-else here was a bit redundant
// you can directly use the value of checkBoxEnabled
item.GetComponentInChildren<MeshRenderer>().enabled = checkBoxEnabled;
}
}
If it is only for the Editor you could even move it from Update into OnValidate so it is only checked if something actually was changed via the Inspector.
Im using a multi-select ListView in C# .NET 4.5
The issue occurs when selecting multiple items (ie. Shift + End or Shift + Click, etc.) These are just a few examples of many different mouse/keyboard combinations for multi-selecting of course..
This is my event handler for when selecting items in a list:
private void lvTitles_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
MessageBox.Show(e.Item.Text.ToString());
//MessageBox just for testing I am actually running a SQL query here
}
My problem is that if I select 500 items the event is triggered 500 times. The intent is to get that last item the user selected (via keyboard/mouse combinations mentioned above), on and do something with it ... in my case I need to run a SQL query against it.
If I click first on item 0 in the listview it is ok to run the query, then when you shift+end it highlights all the rest, and I want it to run the query only on the last item selected. Instead it is running on every item in between.
EDIT: On another note, the event triggers as it unselects as well, in which case it really shouldn't do anything when deselecting.
Have you considered performing the action on a button press instead? That way they can also use Ctrl-Click to select any individual items they want?
Otherwise what you would have to do is wait a certain amount of time before firing the action, known as debouncing, you can read a more about debouncing here: https://stackoverflow.com/a/4517995/984780
I created a class you can use for debouncing:
public class Debounce {
private Action _action;
private bool _isThreadRunning;
private Thread _thread;
private DateTime _runAt;
private double _waitSeconds;
private Debounce(double waitSeconds, Action action) {
_action = action;
_waitSeconds = waitSeconds;
}
private void Invoke() {
_runAt = DateTime.Now.AddSeconds(_waitSeconds);
lock(this) {
if(!_isThreadRunning) {
_isThreadRunning = true;
_thread = new Thread(() => {
while(true) {
Thread.Sleep(100);
lock(this) {
if(DateTime.Now > _runAt) {
_action();
_isThreadRunning = false;
_thread = null;
break;
}
}
}
});
_thread.Start();
}
}
}
private static Dictionary<Action, Debounce> __debounces;
private static Dictionary<Action, Debounce> _debounces {
get {
if(__debounces == null) {
__debounces = new Dictionary<Action, Debounce>();
}
return __debounces;
}
}
public static void Run(double waitSeconds, Action action) {
Debounce debounce;
if(!_debounces.TryGetValue(action, out debounce)) {
debounce = new Debounce(waitSeconds, action);
_debounces.Add(action, debounce);
}
debounce._waitSeconds = waitSeconds;
debounce.Invoke();
}
}
Then you can change your code to this:
private void lvTitles_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
Debounce.Run(5, () => MessageBox.Show(e.Item.Text.ToString()));
}
This should work no matter how they select items, it will run your code 5 seconds after their last selection action.
I just wrote this class and did a quick test, a more thorough test would be advised. In any case hopefully it's enough to get the idea.
I have a function like this:
foreach (ListViewItem item in getListViewItems(listView2)) //for proxy
{
if (reader.Peek() == -1)
{
break;
}
lock (reader)
{
line = reader.ReadLine();
}
//proxy code
List<string> mylist = new List<string>();
if (item != null)
{
for (int s = 0; s < 3; s++)
{
if (item.SubItems[s].Text != null)
{
mylist.Add(item.SubItems[s].Text);
}
else
{
mylist.Add("");
}
}
}
else
{
break;
}
//end proxy code
//some other code including the threadpool
}
and the delegate code:
private delegate ListView.ListViewItemCollection GetItems(ListView lstview);
private ListView.ListViewItemCollection getListViewItems(ListView lstview)
{
ListView.ListViewItemCollection temp = new ListView.ListViewItemCollection(new ListView());
if (!lstview.InvokeRequired)
{
foreach (ListViewItem item in lstview.CheckedItems)
{
temp.Add((ListViewItem)item.Clone());
}
return temp;
}
else
{
return (ListView.ListViewItemCollection)this.Invoke(new GetItems(getListViewItems), new object[] { lstview });
}
}
EDIT:
I wanna replace that foreach loop in the main function with a conditional function:
if (reader.Peek() == -1)
{
break;
}
lock (reader)
{
line = reader.ReadLine();
}
if (use_proxy == true)
{
mylist2 = get_current_proxy();
}
//some other code including the threadpool
private List<string> get_current_proxy()
{
//what shall I add here?
}
How can I make that function do the same as foreach loop but using for loop? I mean getting the proxies one by one ...
I see multiple questions revolving around an idea of scraping a website for emails then spamming. You have very cool tools for that already, no need for a new one.
Anyway - I don't understand your question, and it seems that I'm not the only one here, but the thing you'll have to KNOW before anything else is:
Having ANYTHING in Windows run in multiple threads will ultimately have to be synchronized when you do Invoke() which HAVE TO wait until it all passes through ONE thread and that's the one that holds a message loop. So you can try to read from or write to ListView from multiple threads, but to do each read/write you'll have to Invoke() (you probably tried it directly and BAAAAM) and every Invoke() has only ONE hole to go through, and all your threads will have to wait their turn.
Next: having ListView to be a CONTAINER for your data is so BAD I can't even comment any further. Consider something as a
class MyData
{
public string Name;
public string URL;
// ...
}
and
List<MyData> _myData;
to hold your data. You'll be able to access it from multiple threads, if you take care of some low-key sync issues.
Lastly, how come you ask us questions about .net C# programming if you don't even know the syntax. Well, it's rhetorical, ...
Here's the code I have:
private void ClearSearchResults()
{
foreach (Control X in panel1.Controls)
{
panel1.Controls.Remove(X);
}
}
The problem is, when I run this method, only a single item is deleted, then if I click on a button again so the method can run again, another is deleted.
If I have 10 control in my panel, I'd have to click the "Delete" button on my program many times for all the control to be deleted.
What can I do in this case?
You, in general, can't remove from a collection while iterating an enumerable generated from it. Instead of using foreach, the typical approach is to use a for loop working backwards:
private void ClearSearchResults()
{
for(int i=panel1.Controls.Count-1;i>=0;--i) {
panel1.Controls.RemoveAt(i);
// or
// Control X = panel1.Controls[i];
// panel1.Controls.Remove(X);
}
}
However, in this case, just use clear:
panel1.Controls.Clear();
Does this work for you?
private void ClearSearchResults()
{
panel1.Controls.Clear();
}
Edited to emphasize the CKret comment.
I believe you are changing the IEnumareble when you remove an item from it while iterating it.
Try to use a simple for loop instead of a foreach.
For a start you shouldn't edit the IEnumerable collection within a foreach loop. You should be using a for loop or a while.
I.e.
private void ClearSearchResults()
{
while (panel1.Controls.Count > 0)
{
panel1.Controls.RemoveAt(0);
}
}
or just use:
panel1.Controls.Clear();
Maybe this:
panel1.Controls.Clear()
As I don't know the kind of panel you use, you can generally call panel1.Controls.Clear
private void ClearSearchResults()
{
foreach (Control X in panel1.Controls)
{
panel1.Controls.Remove(X);
}
if (panel1.Controls.Count > 0)
{
ClearSearchResults();
}
}
int n;
n = panel1.Controls.Count-1;
for (int i = 0; i <= n; i++ )
{
Control c = panel1.Controls[0];
panel1.Controls.Remove(c);
}
Actually you can't use Remove because it breaks the iterator so simple solution would be something like this :
var controls = in c from panel1.Controls select c;
foreach(Controls _control in controls)
{
panel1.Controls.Remove(_control);
}
but of course you don't want to stick to Loop then go ahead and use panel1.Controls.Clear()
while (panel1.Controls.Count != 0)
{
foreach (Control c in panel1.Controls)
{
panel1.Controls.Remove(c);
}
}
Another way !