How do i check if i tem already exist in ToolStripMenuItem.DropDownItems? - c#

I have a ToolStripMenuItem MouseEnter event:
private void recentFilesToolStripMenuItem_MouseEnter(object sender, EventArgs e)
{
for (int i = 0; i < lines.Length; i++)
{
ToolStripMenuItem s = new ToolStripMenuItem(lines[i]);
if (!recentFilesToolStripMenuItem.DropDownItems.ContainsKey(lines[i]))
recentFilesToolStripMenuItem.DropDownItems.Add(s);
}
}
Now I am using ContainsKey but before i tried only with Contains(s)
In both cases it keep adding the items over and over again to the DropDownItems.
Each time i move the mouse and Enter i see the items added again.
In this case lines is array of string contain paths and names of text files.
For example in lines index 0 i see: d:\mytext.txt
The problem is that it keep adding them over again when i enter with the mouse and i want them to be added only once.
First time i see when entering with the mouse:
d:\mytext.txt
e:\test.txt
c:\hello\hellowowrld.txt
Next time when I enter with the mouse I see it twice:
d:\mytext.txt
e:\test.txt
c:\hello\hellowowrld.txt
d:\mytext.txt
e:\test.txt
c:\hello\hellowowrld.txt
Then next time i see the same items 9 times and so on.

There are two ways to do this.
One, is that you create your ToolStripMenuItem like this:
new ToolStripMenuItem(lines[i], (Image)null, (EventHandler)null, lines[i]);
It's that fourth parameter that is the "key" for .ContainsKey(...), not the first parameter.
Two, you can do it this way:
if (!recentFilesToolStripMenuItem.DropDownItems
.Cast<ToolStripMenuItem>()
.Any(x => x.Text == lines[i]))
{
recentFilesToolStripMenuItem.DropDownItems.Add(s);
}
This second way searches the actual text.

Related

Windows application: align ListView items in a group to center of line

I have a windows application in C# and I want to rank people based of their score, into 3 levels; the one with highest score at first level, next 3 highest at second level, and others at third level.
I've implemented this, as shown in picture, using ListView with 3 groups successfully; my question is: can I align items in each group to center? Items are aligned to left
No this is not really possible without owner-drawing the ListView.
The reason is the the ShowGroups property.
If it were false you could calculate the Position for each ListViewItem..
Here is how to modify the position of a ListViewItem:
ListViewItem lvi = listView1.Items[3];
lvi.Position = new Point(lvi.Position.X + 50, lvi.Position.Y);
lvi.Text = "X testing X";
But this will not have an effect if the ListView has ShowGroups = true unfortunately. Nor is calculating the offset a simple task; after all it would differ depending on the number of Items both in a group and in the row.
So you would have to ownerdraw the ListView, which will work but will have the same problems when determining the exact positions.
And centering two items would make the whole layout look jagged and ugly, imo.
Maybe the simplest solution is a workaround: Simply add a dummy item where needed. Its image would be transparent or its ImageIndex = -1; and its text empty or blank. You would insert it into every group with an odd numer of items which is not divisible by the maximum of items in a row. In your case 3. Or perhaps it is enough to check if the group contains only one item..
Here is an example:
void InsertBlankItem(ListView lv, ListViewGroup lvg)
{
ListViewItem lvOld = g.Items[0];
lvg.Items.Remove(lvOld);
ListViewItem lviBlank = new ListViewItem() { Text = " ", ImageIndex = -1 };
lviBlank.Group = lvg;
listView1.Items.Add(lviBlank);
lvg.Items.Insert(1, lvOld);
}
This adds a blank item and moves the first item to the end..:
private void button1_Click(object sender, EventArgs e)
{
foreach (ListViewGroup g in listView1.Groups)
{
if (g.Items.Count == 1) InsertBlankItem(listView1, g);
}
}
Of course now you have a clickable dummy item in your ListView..
If you want to re-order more Items within a group you need to remove them all into a List and re-add them in the new order.

how to replace the values in List index C#?

I am using DataGridView in C# being civil engineer.
I want the values from a particular row. If the same value appears in a row, I want to display a message. For example, if 1 appears multiple time in a row, i want to display a message on every 1.
Here is how I am doing it:
private void button4_Click(object sender, EventArgs e)
{
for (int i = 0; i < dataGridView2.ColumnCount - 1; i++)
{
if (CategoryCLO[i] == 1)
{
MessageBox.Show("Here i am");
}
else
{
MessageBox.Show("I am not");
}
}
}
private void dataGridView2_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex == 1)
{
CategoryCLO.Add(int.Parse(
dataGridView2.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString()));
}
}
Problem:
It works right only one time. If a user replaces a value in a cell in DataGridView, it adds up another value corresponding to the newly added index of list.
Explanation:
The problem is that when user changes value in DataGridView, it got adds up in the list, thus increase the index of list , I want that index of list should be fix to the column index. and any change in particular cell , should change in that particular index rather than adding up.
Question:
I want that value should be placed in the previous index rather than creating new. In short, I want the indexes of list should be fixed to column number. How can I do it? any direction?
Note: Column numbers are variable depending upon the user

Creating a sudoku. Should I use a while statement for this code?

I'm making a sudoku in Windows Form Application.
I have 81 textboxes and I have named them all textBox1a, textBox1b... textBox2a, textBox2b...
I want to make it so that if any of the textboxes, in any of the rows, is equal to any other textbox in the same row, then both will get the background color red while the textboxes are equal.
I tried using this code just for test:
private void textBox1a_TextChanged_1(object sender, EventArgs e)
{
while (textBox1a.Text == textBox1b.Text)
{
textBox1a.BackColor = System.Drawing.Color.Red;
textBox1b.BackColor = System.Drawing.Color.Red;
}
It didn't work, and I don't know where I should put all this code, I know I shouldn't have it in the textboxes.
Should I use a code similar to this or is it totally wrong?
You want to iterate over the collection of text boxes just once, comparing it to those that haven't yet been compared against. If you have your textboxes in an array (let's call it textBoxes), and know which one was just changed (e.g. from the textChanged handler), you could do:
void highlightDuplicates(int i) // i is the index of the box that was changed
{
int iVal = textBoxes[i].Text;
for (int j = 0; j < 82; j++)
{
// don't compare to self
if (i == j) return;
if (textBoxes[j].Text == iVal)
{
textBoxes[i].BackgroundColor = System.Drawing.Color.Red;
textBoxes[j].BackgroundColor = System.Drawing.Color.Red;
}
}
}
If you wanted to get fancier, you could put your data in something like: Dictionary<int, TextBox>, where the key is the value and the TextBox is a reference to the text box with that value. Then you can quickly test for duplicate values with Dictionary.Contains() and color the matching text box by getting its value.
I think your current code would result in an infinite loop. The textboxes' values can't change while you are still in the event handler, so that loop would never exit.
If all of your boxes are named according to one convention, you could do something like this. More than one input can use the same handler, so you can just assign this handler to all the boxes.
The following code is not tested and may contain errors
private void textBox_TextChanged(object sender, EventArgs e){
var thisBox = sender as TextBox;
//given name like "textBox1a"
var boxNumber = thisBox.Name.SubString(7,1);
var boxLetter = thisBox.Name.SubString(8,1);
//numbers (horizontal?)
for(int i = 1; i<=9; i++){
if(i.ToString() == boxNumber)
continue; //don't compare to self
var otherBox = Page.FindControl("textBox" + i + boxLetter) as TextBox;
if (otherBox.Text == thisBox.Text)
{
thisBox.BackColor = System.Drawing.Color.Red;
otherBox.BackColor = System.Drawing.Color.Red;
}
}
//letters (vertical?)
for(int i = 1; i<=9; i++){
var j = ConvertNumberToLetter(i); //up to you how to do this
if(j == boxLetter)
continue; //don't compare to self
var otherBox = Page.FindControl("textBox" + boxNumber + j) as TextBox;
if (otherBox.Text == thisBox.Text)
{
thisBox.BackColor = System.Drawing.Color.Red;
otherBox.BackColor = System.Drawing.Color.Red;
}
}
}
I believe you will be more effective if create an Array (or a List) of Integers and compare them in memory, against compare them in UI (User Interface).
For instance, you could:
1) Create an Array of 81 integers.
2) Everytime the user input a new number, you search for it in that Array. If found, set the textbox as RED, otherwise, add the new value to that array.
3) The ENTER event may be allocated fot the entire Textboxes (utilize the Handles keyword with all Textboxes; like handles Text1.enter, Text2.enter, Text3.enter ... and so forth)
Something like:
int[] NumbersByUser = new int[81];
Private Sub Textbox1.Enter(sender as object, e as EventArgs) handles Textbox1.Enter, Textbox2.Enter, Textbox3.enter ...
int UserEntry = Convert.ToInt32(Sender.text);
int ValorSelecionado = Array.Find(NumbersByUser, Z => (Z == UserEntry));
if (ValorSelecionado > 0) {
Sender.forecolor = Red;
}
else
{
NumbersByUser(Index) = UserEntry;
}
You should have a 2 dimensional array of numbers (could be one dimensional, but 2 makes more sense) let's assume its called Values. I suggest that you have each textbox have a incrementing number (starting top left, going right, then next row). Now you can do the following:
All TextBox Changed events can point to the same function. The function then takes the tag to figure out the position in the 2dim array. (X coordinate is TAG % 9 and Y coordinate is TAG / 9)
In the callback you can loop over the textboxes and colorize all boxes as you like. First do the "check row" loop (pseudo code)
var currentTextBox = ((TextBox)sender)
var x = ((int)currentTextBox.Tag) % 9
var y = ((int)currentTextBox.Tag) / 9
// First assign the current value to the backing store
Values[currentTextBox] = int.parse(currentTextBox.Text)
// assuming variable x holding the column and y holding the row of current box
// Array to hold the status of a number (is it already used?)
bool isUsed[9] = {false, false, ...}
for(int col = 0; col <= 9; i++)
{
// do not compare with self
if(col == x) continue;
isUsed[textBox] = true;
}
// now we have the status of all other boxes
if( isUsed[Values[x,y]] ) currentTextBox.Background = Red else currentTextBox.Background = Green
// now repeat the procedure for the column iterating the rows and for the blocks
I would suggest a dynamic approach to this. Consider each board item as a cell (this would be it's own class). The class would contain a numeric value and other properties that could be useful (i.e. a list of possible values).
You would then create 3 collections of the cells, these would be:
A collection of rows of 9 cells (for tracking each row)
A collection of columns of 9 cells (for tracking each column)
A collection of 3x3 cells
These collections would share references - each cell object would appear once in each collection. Each cell could also contain a reference to each of the 3 collections.
Now, when a cell value is changed, you can get references to each of the 3 collections and then apply a standard set of Sudoku logic against any of those collections.
You then have some display logic that can walk the boards of cells and output to the display (your View) your values.
Enjoy - this is a fun project.

How to set FIFO and palindrome compare?

I have this windows application
1.- So, first when I Add a number it added to listbox1 but not to list 2. I need to be add ed to listo 2 to
2.- I need the numbers be added separately... For example if I add number 202, it split on 2 after 0 after 2
3.- I need add button for FIFO, but I don't know how can I program it.
4.-Finally compare one by one it with listbox1 with listbox2 with polindrome method, and if its palindrome show message box, say "they are polindrome", if not, say "number it's not palindrome.
private void button1_Click(object sender, EventArgs e)
{
int newvalue;
if (int.TryParse(textBox1.Text, out newvalue))
{
numeros.Add(newvalue);
listBox1.Items.Add(textBox1.Text);
}
else
MessageBox.Show("insert a number");
textBox1.Clear();
textBox1.Focus();
}
For dealing with this problem you should keep your main data in memory (List<int>) and manipulate them using different methods and show the result in the listboxes.
Separating your digits can be done this way :
List<int> SeparateDigits(int n)
{
var result = new List<int>();
while(n>0)
{
result.Add(n % 10);
n /= 10;
}
return result;
}
After calling this method you can add the list data to both your listboxes if it's what you want.
(sorry for being late)
Good luck.

Increment through a list on a button list

I've stored a list of colors in my program. I am after an object in my scene to one of the colors in the list. So far, I have done the followings:
if(Input.GetKeyDown(KeyCode.O))
{
for(int i = 0; i < claddingColor.Count; i++)
{
claddingMaterial.color = claddingColor[i];
}
}
This isn't working due to a reason I know (and you can probably spot) but I lack to the verbal fortitude to write it down.
As opposed to have a multiple lines of the following:
claddingMaterial.color = claddingColor[0];
Each tied to different buttons, I like a way I can emulate the above but tie it to a single button press. Thus, if I hit the 0 button 5 times, it will loop through each color stored in the list. If I hit it for a sixth time, it will go back to the first color in the list.
Could someone please help me implement this? Or point me to something that I may learn how to do it for myself?
Define LastColor property as class member:
int LastColor;
In your function use modulo
if(Input.GetKeyDown(KeyCode.O))
{
claddingMaterial.color = claddingColor[(LastColor++) % claddingColor.Count];
}
Note: Depending on the type of claddingColor use Count for a List or Length for Array.
You won't need a for loop
int lastStep = 0;
if(Input.GetKeyDown(KeyCode.O))
{
claddingMaterial.color = claddingColor[lastStep++];
if (lastStep == claddingColor.Count)
lastStep = 0;
}

Categories