How to check range in checkedlistbox c# winforms? - c#

I have a checkeboxlist with 100 items. Obviously user can check items one by one as many as he need, but I would like to give to user option check range of items (let's say with Shift hold button). So, user check one of the items (let's say item index 5) and then press and hold shift button and check next item (index 10), so I range of the items should be checked from 5...10
I have not found anything about such implementation, looks like it doesn't exist and no one did such kind of things.
How to do it?

Keep track of your last index:
int lastIndex = -1;
In your form's constructor, wire things up:
public Form1() {
InitializeComponent();
checkedListBox1.CheckOnClick = true;
checkedListBox1.SelectedIndexChanged += CheckedListBox1_SelectedIndexChanged;
checkedListBox1.MouseDown += CheckedListBox1_MouseDown;
}
And then use these methods to change the items in the range:
private void CheckedListBox1_SelectedIndexChanged(object sender, EventArgs e) {
lastIndex = checkedListBox1.SelectedIndex;
}
private void CheckedListBox1_MouseDown(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left && Control.ModifierKeys == Keys.Shift) {
var useIndex = Math.Max(lastIndex, 0);
var x = checkedListBox1.IndexFromPoint(e.Location);
if (x > -1 && x != useIndex) {
if (useIndex > x) {
for (int i = useIndex - 1; i > x; i--) {
checkedListBox1.SetItemChecked(i, !checkedListBox1.GetItemChecked(i));
}
} else {
for (int i = useIndex + 1; i < x; i++) {
checkedListBox1.SetItemChecked(i, !checkedListBox1.GetItemChecked(i));
}
}
}
}
}

Related

Select / Deselect Multiple items in multiple listboxes

I am trying to implement a multiple items select in multiple listboxes. Is this possible?
Requirements:
When user selects an item in ListBox1 - items in ListBox2 and ListBox3 should be selected.
When user deselects and item in ListBox1 - Items in ListBox2 and ListBox2 should be deselected.
I am able to achieve this on LB1.
Same behavior 1 and 2 should repeat for ListBox2 and ListBox3.
I am having difficulty here.
I have the code below - but of course it runs into stackoverflow exception. What am I missing?
private void listBox_1_SelectedIndexChanged_(object sender, EventArgs e)
{
int userSelectedIndex = listBox_1.Items.Count;
if (listBox_1.SelectedIndices.Count > 0)
{
for (int count = 0; count < listBox_1.Items.Count; count++)
{
// Determine if the item is selected.
if (listBox_1.GetSelected(count) == true)
{
if (count <= listBox_2.Items.Count)
listBox_2.SetSelected(count, true);
if (count <= listBox_3.Items.Count)
listBox_3.SetSelected(count, true);
}
else if (listBox_1.GetSelected(count) == false)
{
// Select all items that are not selected.
if (count <= listBox_2.Items.Count)
listBox_2.SetSelected(count, false);
if (count <= listBox_3.Items.Count)
listBox_3.SetSelected(count, false);
}
}
}
}
private void listBox_2_SelectedIndexChanged(object sender, EventArgs e)
{
int userSelectedIndex = listBox_2.Items.Count;
if (listBox_2.SelectedIndices.Count > 0)
{
for (int count = 0; count < listBox_2.Items.Count; count++)
{
// Determine if the item is selected.
if (listBox_2.GetSelected(count) == true)
{
if (count <= listBox_1.Items.Count)
listBox_1.SetSelected(count, true);
if (count <= listBox_3.Items.Count)
listBox_3.SetSelected(count, true);
}
else if (listBox_2.GetSelected(count) == false)
{
// Select all items that are not selected.
if (count <= listBox_1.Items.Count)
listBox_1.SetSelected(count, false);
if (count <= listBox_3.Items.Count)
listBox_3.SetSelected(count, false);
}
}
}
}
This field is used to avoid Stack Overflow Exceptions.
private bool _isUpdating;
I am also using the SelectedValueChanged event instead of SelectedIndexChanged but it should still work, here is the 3 different checkboxes (this could be improved by refactoring how it handles which listbox to update)
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
if (this._isUpdating)
{
//// Prevent Stack Overflow by exiting out
return;
}
var selectedIndexes = this.listBox1.SelectedIndices;
this._isUpdating = true;
this.listBox2.SelectedItems.Clear();
this.listBox3.SelectedItems.Clear();
foreach (int index in selectedIndexes)
{
//// Listbox2
var foundItem = this.listBox2.Items[index];
this.listBox2.SelectedItems.Add(foundItem);
//// Listbox3
var foundItem2 = this.listBox3.Items[index];
this.listBox3.SelectedItems.Add(foundItem2);
}
this._isUpdating = false;
}
private void listBox2_SelectedValueChanged(object sender, EventArgs e)
{
if (this._isUpdating)
{
//// Prevent Stack Overflow by exiting out
return;
}
var selectedIndexes = this.listBox2.SelectedIndices;
this._isUpdating = true;
this.listBox1.SelectedItems.Clear();
this.listBox3.SelectedItems.Clear();
foreach (int index in selectedIndexes)
{
//// Listbox1
var foundItem = this.listBox1.Items[index];
this.listBox1.SelectedItems.Add(foundItem);
//// Listbox3
var foundItem2 = this.listBox3.Items[index];
this.listBox3.SelectedItems.Add(foundItem2);
}
this._isUpdating = false;
}
private void listBox3_SelectedValueChanged(object sender, EventArgs e)
{
if (this._isUpdating)
{
//// Prevent Stack Overflow by exiting out
return;
}
var selectedIndexes = this.listBox3.SelectedIndices;
this._isUpdating = true;
this.listBox1.SelectedItems.Clear();
this.listBox2.SelectedItems.Clear();
foreach (int index in selectedIndexes)
{
//// Listbox1
var foundItem = this.listBox1.Items[index];
this.listBox1.SelectedItems.Add(foundItem);
//// Listbox2
var foundItem2 = this.listBox2.Items[index];
this.listBox2.SelectedItems.Add(foundItem2);
}
this._isUpdating = false;
}
Which as stated previously, avoids the Stack Overflow Exception and ensures that selecting / deselecting an item in the Listbox at a given index will also select the item at the other listboxes index.

C# How to assign i and j in 2D array when i press on a button

I was asked to make a tic tac toe in windows form and i have to use 2D array
I am trying to store 1 in the array for each X and -1 for each 0
then i will add the values in each row ,column and diagonal and check if its 3 or -3
the problem is i don't know how to assign and i and j for each element in the array after i press on a corresponding button
private void storeInboard(int i, int j, object sender, EventArgs e)
{
{
if ((sender as Button).Text == "X")
board[i][j] = 1;
else if ((sender as Button).Text == "O")
board[i][j] = -1;
}
}
here i check for each column by giving its number
private bool checkCol(int col)
{
for (int i = 0; i < 3; i++)
{
rowSum += board[i][col];
if (colSum == 3 || colSum ==-3 )
return true;
else
colSum = 0;
}
return false;
}
checking for winner
private bool checkWinner()
{
return (checkCol(0) || checkCol(1) || checkCol(2) || checkDiag1() || checkDiag2() || checkRow(0) || checkRow(1) || checkRow(2));
}
here is the button click event >> its is assigned for all the buttons
private void button_click(object sender, EventArgs e)
{
if (turn)
{
(sender as Button).Text = "X";
}
else
(sender as Button).Text = "O";
turn = !turn;
turnCount++;
(sender as Button).Enabled = false;
if (checkWinner() && turnCount <=9)
MessageBox.Show("Winner !!!");
else
MessageBox.Show("Tie -.-");
so I just want to know how can i send an i and j for the event storeInboard for each button i click
thanks in advance
This question is not about arrays or some 2D stuff but binding information to winform controls.
You have several ways to do this.
1) In visual studio property panel fill buttons Tag property with an ordinal number one by one from left to right starting with zero. Left-upper button = 0, middle-upper = 1 and so on.
Then in button_click you can do something like:
var tag = int.Parse((string)((Button)sender).Tag);
int colIndex = tag % 3;
int rowIndex = tag / 3;
2) Maybe the buttons are placed in a Panel. Then you can iterate through the children of the parent panel in button_click and see if one equals to sender.
int c = 0;
foreach (var item in parentPanel.Controls)
{
if (item == sender)
break;
c++;
}
if (c<parentPanel.Controls.Count) // found
{
int colIndex = c % 3;
int rowIndex = c / 3;
}
// else -- ugh, something went wrong, maybe not only the buttons have this event
Much more solution is possible.

Remove TabPage from TabControl

So i need to dynamically add and delete some TabPage. User clicked "Show Tab" = storage_pageadded.
private void storage_menuItem_Click(object sender, EventArgs e) {
storage_page.Text = storage_page.Name = "Storage";
main_tabControl.TabPages.Add(storage_page);
main_tabControl.SelectedTab = storage_page;
}
And the when he chooses another page the storage_page has to be removed
private void main_tabControl_SelectedIndexChanged(object sender, EventArgs e) {
for (int i = 0; i < main_tabControl.TabPages.Count; i++) {
if (main_tabControl.TabPages[i].Name.Equals("storage", StringComparison.OrdinalIgnoreCase) && main_tabControl.SelectedTab.Name != "Storage") {
main_tabControl.TabPages.RemoveAt(i);
break;
}
}
}
When i click "Show Tab" page shows up. But when i select other page i see the ArgumentOutOfRangeException leading to Application.Run(new Form_Authentication()); line
How can i do that?
I think the problem is you increase i variable by 1 from 0 to main_tabControl.TabPages.Count
I assume that main_tabControl.TabPages.Count = 10, what is happended if you're removing 7th element? At that time, main_tabControl.TabPages.Count = 4 and i variable = 6. So, i variable is exceed the range of TabPages.
You should to change your code:
private void main_tabControl_SelectedIndexChanged(object sender, EventArgs e) {
for (int i = main_tabControl.TabPages.Count - 1; i >=0 ; i--) {
if (main_tabControl.TabPages[i].Name.Equals("storage", StringComparison.OrdinalIgnoreCase) && main_tabControl.SelectedTab.Name != "Storage") {
main_tabControl.TabPages[i].Dispose();
break;
}
}
}

multiple remove checkedlistbox items

Hi on this site I found how to delete multiple checkedbox objects in a checklistbox
How to delete multiple checked items from CheckedListBox?
But it's not working for me.
My previous partner who handled this project before I did saved something in Global.answer class. I have tried to modify that script like this:
for (int i = checkedListBoxAnswers.Items.Count - 1; i >= 0; i--) {
if (checkedListBoxAnswers.GetItemCheckState(i) == CheckState.Checked)
{
Global.answers.RemoveAt(checkedListBoxAnswers.SelectedIndex);
}
}
It can delete one checkbox correctly, but when I check for two or more checkboxes, it goes wrong...
I wonder how to do it correctly.
this is my delete button
private void buttonDelete_Click(object sender, EventArgs e)
{
if (checkedListBoxAnswers.SelectedIndices.Count < 1)
{
MessageBox.Show(this, "Please select answer to be deleted");
}
else
{
for (int i = checkedListBoxAnswers.Items.Count - 1; i >= 0; i--)
{
if (checkedListBoxAnswers.GetItemCheckState(i) == CheckState.Checked)
{
Global.answers.RemoveAt(checkedListBoxAnswers.SelectedIndex);
}
}
updateCheckListBoxAnswers();
}
}
in-fact here is correct code:
CheckedListBox.CheckedItemCollection checkedItemColl = checkedListBoxAnswers.CheckedItems;
for (int i = checkedItemColl.Count; i > 0; i--)
{
int index = checkedItemColl[i - 1];
checkedListBoxAnswers.Items.Remove(index);
}
Because you using this code
Global.answers.RemoveAt(checkedListBoxAnswers.SelectedIndex);
this will delete only the selected first item in the list, you must pass the index of selected Checked Item ,So it will delete that item only,
This is how you get all checked Item from List:
CheckedListBox.CheckedItemCollection checkedItemColl = checkedListBoxAnswers.CheckedItems;
for (int i = checkedItemColl.Count; i > 0; i--)
{
int index = checkedItemColl[i - 1];
checkedListBoxAnswers.Items.Remove(index);
}
remove comments and test the code. hope you will get benifit from it.
you can try this...
Global.answers.RemoveAt(i);
hie bro i have sample ... you can evolve tray this in your sweet home....
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (e.NewValue == CheckState.Checked)
listBox1.Items.Add(checkedListBox1.Items[checkedListBox1.SelectedIndex]);
if (e.NewValue == CheckState.Unchecked)
listBox1.Items.Remove(checkedListBox1.Items[checkedListBox1.SelectedIndex]);
}
Your are Removing an Object so Parse that Object into Integer
by this way
Convert.ToInt32(Object)
in your case it will be..
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (e.NewValue == CheckState.Checked)
listBox1.Items.Add(checkedListBox1.Items[checkedListBox1.SelectedIndex]);
if (e.NewValue == CheckState.Unchecked)
listBox1.Items.Remove(Convert.ToInt32(checkedListBox1.Items[checkedListBox1.SelectedIndex]));
}

Global array not being accessed correctly

Below is my current code:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public int[] trialArray = new int[10];
public int trialCounter = -1;
private void button1_Click(object sender, EventArgs e)
{
bool button1Click = true;
if (button1Click == true)
{
ITIpanel.Visible = true;
for (int i = 0; i < trialArray.Length; i++) { trialArray[i] = -1; } // Set default value through array
int counter = 0;
Random rnd = new Random();
while (counter < 10 / 2)
{ // Red trials, fill half array
int index = rnd.Next(0, 10 - 1);
if (trialArray[index] == -1) { trialArray[index] = 1; ++counter; } //if unchanged value, change it
}
while (counter < 10)
{
int index = rnd.Next(0, 10);
if (trialArray[index] == -1) { trialArray[index] = 2; ++counter; }
}
}
}
private void ITIpanel_Paint(object sender, PaintEventArgs e)
{
if (ITIpanel.Visible == true)
{
trialCounter += 1;
timer1.Enabled = true;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
ITIpanel.Visible = false;
timer1.Enabled = false;
if (trialArray[trialCounter] == 1) { redstimPanel.Visible = true; }
else { bluestimPanel.Visible = true;}
if (trialCounter == 9) { Application.Exit(); }
}
public int counter = 0;
public event EventHandler Clicked5TimesEvent;
private void OnClicked5TimesEvent()
{ if (Clicked5TimesEvent != null) { Clicked5TimesEvent(this, EventArgs.Empty); } }
private void bluestimPanel_MouseDown(object sender, EventArgs e)
{
//FR requirement
counter++; if (counter % 5 == 0) { redstimPanel.Visible = false; ITIpanel.Visible = true; }
}
private void redstimPanel_MouseDown(object sender, EventArgs e)
{
//FR requirement
counter++; if (counter % 5 == 0) { redstimPanel.Visible = false; ITIpanel.Visible = true; }
}
}
}
As you can see, I am attempting to make a global array with 10 items. On the button click the 10 items are supposed to be altered such that half contain the value 1 and the other half contain the value 2.
Then, on the timer tick, depending on the value in the trialCounter, which determines the part of the array to be accessed, it should display either the redstimPanel or the bluestimPanel.
Therefore, if the 'trialCounter' is equal to 8, and 8 in the TrialArray is equal 1, the 'redstimPanel' should become Visible. Alternatively, if 8 in the 'TrialArray' is equal to 2, the 'bluestimPanel' should become Visible.
This, however, is not working as I would like it to. Thus, there are clearly some issues with my code. Do you all have any suggestions?
You never reset counter, or have the second loop (the one setting the 2s) be the full array.
There is also an error with the random number, rnd.Next(a,b) a - lower bound (inclusive), b - upper bound (exclusive). So it should be rnd.Next(0,10); so you have a chance of populating the last array position.
while (counter < 10 / 2) { // Red trials, fill half array
int index = rnd.Next(0, 10);
if (trialArray[index] == -1) { trialArray[index] = 1; ++counter; } //if unchanged value, change it
}
//Counter on the first loop here is already 5 (it exited the previous loop)
//So allow it to get to 10, and populate the FULL array.
while (counter < 10) {
int index = rnd.Next(0, 10);
if (trialArray[index] == -1) { trialArray[index] = 2; ++counter; }
}
Allow me to give you some tips and some explanations regarding your code:
First of all, you probably wanted that local button1Click variable to know later on whether the button has been clicked or not. For that to work, you should place it outside that function, otherwise it's never going to be used, and will be true with every button click, something like this:
bool button1Click = false;
private void button1_Click(object sender, EventArgs e)
{
if (!button1Click)
{
When you have a condition, you want the code to decide, whether an expression is true or false you may omit the part "== true" because it doesn't add anything new.
You have two whiles. Your idea was to run the counter until 5, with the first piece of code, and then from 5 to 10 the second piece of code. Now let me try to explain what is actually going on. The counter will go on until 5 filling 1s at random indices. Then at 5, the expression in the while will become false and it breaks out from the loop. Since the second while has the very same expression, it simply avoids it and goes on. One of the many solutions would be to have an if in the loop like this:
while (counter < 10)
{
if (counter<5)
{
// fill red
}
else
{
// fill blue
}
}
The way you fill up the values in your array. Have you thought about what's going to happen when the same index will be generated several times? It means it'll overwrite the previous value while certain index will remain -1.

Categories

Resources