I've got a DataGrid, which is bound to a List: _bhaList.
Now, I've written a method which will allow the user to select an item on the grid, and move it up. And as it moves up, the No. column is updated to show it's current position. However, in this particular case, where I have 3 items, if I choose No. 2, and move it up, it does switch places with No. 1, and those numbers update, but No. 3 will change to 4. If I repeat the process, the new No. 4 will change to 5.
Here's the code that I've attempted:
var oldIndex = grdBha.SelectedIndex;
var newIndex = oldIndex - 1;
var bha = _bhaList[oldIndex];
_bhaList.RemoveAt(oldIndex);
bha.Number = oldIndex;
_bhaList.Insert(newIndex, bha);
for (var i = newIndex + 1; i <= _bhaList.Count; i++)
{
if (i != _bhaList.Count)
{
_bhaList[i].Number += 1;
}
}
I've tried different variations in the for loop, with no success.
I have the feeling that this is going to be something really simple, but my mind just isn't seeing it.
Your problem is that only two items in this case had their "order changed", yet you incremented the number for everybody below the item moved. In this case Bit X/O Sub was 3, but gets incremented to 4.
You know the only two indices involved:
// swap the two
var temp = _bhaList[newIndex];
_bhaList[newIndex] = _bhaList[oldIndex];
_bhaList[oldIndex] = temp;
_bhaList[newIndex].Number = newIndex + 1;
_bhaList[oldIndex].Number = oldIndex + 1;
If your items can only move one spot at a time the loop is unnecessary and can be replaced with the following:
_bhaList[oldIndex].Number++;
You only need to reshuffle/ swap the locations,
When you _bhaList.Insert(newIndex, bha); it will increment the count by 1.
Try only by replacing those two selected indexes.
Your for loop doesn't make sence, you don't need to increase the number of each items. You only need to do this if you add a new item in the list.
var oldIndex = grdBha.SelectedIndex;
var newIndex = oldIndex - 1;
var oldBha = _bhaList[oldIndex];
var newBha = _bhaList[newIndex];
oldBha.Number--;
newBha.Number++;
_bhaList.RemoveAt(oldIndex);
_bhaList.Insert(newIndex, oldBha);
or
_bhaList[oldIndex] = newBha;
_bhaList[newIndex] = oldBha;
by using
_bhaList.RemoveAt(oldIndex);
bha.Number = oldIndex;
_bhaList.Insert(newIndex, bha);
you have moved the item to the new index. .NET will push down all the other elements as required with out the need for you to do so. As such there is no need for the for loop.
To resolve your issue, simply remove the for loop.
Related
I am trying to filter a list of int based on multiples of a specific number, but I am not sure how to do this. I have searched this forum and found nothing related, but apologies in advance if I'm wrong.
Here is my code:
int val = 28;
List<int> divisible = new List<int>();
for (int i = 1; i <= val; i++) {
divisible.Add(i);
}
foreach(var d in divisible)
{
if(val % d == 0)
{
// do something
}
else
{
// get rid of all multiples of the number that "val" is not divisible by
}
}
Basically, this code should create a divisible list from 1 to 28. If val is divisible by one of the numbers in the list, thats fine, but if it falls into else, I want to be able to filter out all multiples of that number out of the current list we are looping through.
The next number that wouldn't be divisible would be 3 in this example, so in the else get rid of 6, 9, 12, ... etc.
Your code is fine, but you're just missing the actual code to remove the item. But there is a caveat: You cannot modify a list when you are looping through it using foreach. There are a couple ways to handle that:
Depending on your requirements, maybe just don't add them in the first place. Move your val % d == 0 condition into the for loop that adds the values, and just don't add the values that are divisible by d.
Make a new list (List<int> toRemove) where you keep track of all the values you need to remove. After you're done the foreach loop, loop through your toRemove list and use divisible.Remove(value) to remove those.
Change your foreach to a for loop, which will allow you to use divisible.RemoveAt(i). But you will have to make sure you don't skip a value on the next iteration of the for loop (since removing a value changes the size of the list).
I agree with Gabriel. You cannot alter a underlying enumeration while traversing it with with foreach. The easiest thing to do would be to convert it to a for loop.
Also in the initial population of your list try using the newer way
var divisible = Enumerable.Range(1, val).ToList();
then do
for(int 0 = 1; i < val; i++)
{
if(val % d == 0)
{
// do something
}
else
{
divisible.RemoveAt(i);
}
}
I am trying to show multiple things in a textbox in my software and its just printing out 1 / 5
I think I got the for loop all mixed up so here is how it looks
var getTopFive = new FirefoxDriver();
getTopFive.Navigate().GoToUrl("https://www.tradingview.com/");
IList<IWebElement> movies = getTopFive.FindElements(By.CssSelector("tbody tr"));
for (int i = 0; i < 1; ++i)
{
activeTextBox.Text = movies[i].Text;
}
This is what I tried and failed with.
I tried adding another
activeTextBox.Text = movies[i].Text;
Which did not work
I also tried adding a second block of the same code showed at the top but with a different name for the int etc.
Then I tried adding a else if below it which gave me another error.
So my question is, how do I make the loop go through all the 5 items instead of just showing the first one which it does by this line of code right here.
for (int i = 0; i < 1; ++i)
{
activeTextBox.Text = movies[i].Text;
}
There are two issues here. The first is your for loop is only going to happen once because for(int i = 0; i < 1; i++).
To loop more than once, you need to change to 1 to something else. If you want it dynamic, use for(int i = 0; i < movies.Count; i++).
The second issue is activeTextBox.Text is being over-written each time you write to it. No matter how many times you repeat the loop or the line, the only thing that text box will show is the last item in the loop.
If you want it to show all items, you need to do something like:
activeTextBox.Text += movies[i].Text + "\n";
The \n will put each movie on a separate line - you could use a hyphen or similar to separate each item.
IList has a property called Count. This property returns the number of elements in the list. Use it in your loop like this to show all movies:
for (int i = 0; i < movies.Count; i++)
{
activeTextBox.Text = movies[i].Text;
}
A second way is to use a foreach loop like this:
foreach (IWebElement WebElement in movies)
{
activeTextBox.Text = WebElement.Text;
}
Remember you are overwriting your text each loop. So in the end your text will be the last item of your loop. If you want to add the names behind each other do it like this (seperated with a minus)
activeTextBox.Text += " - " + movies[i].Text;
or this
activeTextBox.Text += " - " + WebElement.Text
clear the Text before your loop with
activeTextBox.Text.Clear();
Try using this code (don't forget to add using System.Linq;):
activeTextBox.Text = string.Join("; ", movies.Select(x => x.Text));
Explanation:
movies.Select(x => x.Text) takes every IWebElement (movie) and return its Text property. So you end up with a list of movie names instead of IWebElement objects.
Next, you join those movies together into a single string, separated by semicolon. (string.Join("; ", ...))
And then you assign the result to the activeTextBox.
I have a string list and I am continuously adding elements to this list.
I do not want this list to grow beyond 6 elements(index 0 to 5). So once it reaches index[5], I do not want to grow the list, but instead add elements at the start of the list or do something similar to it. At any point, I would be printing the last 3 items added to this list ordered by item last added to this list. I have tried it below but i think it is crappy piece of code. After this piece of code, I would get the list count and print UrlList[UrlList.Count - 1],UrlList[UrlList.Count - 2];,UrlList[UrlList.Count - 3]
Pls help me with it
if (UrlList.Count == 5)
{
var move = UrlList[5];
UrlList.RemoveAt(5);
UrlList.Insert(0, move);
move = UrlList[4];
UrlList.RemoveAt(4);
UrlList.Insert(1, move);
move = UrlList[3];
UrlList.RemoveAt(3);
UrlList.Insert(2, move);
UrlList.Add(uri.ToString());
}
else
{
UrlList.Add(uri.ToString());
}
If you want the latest items to be the last ones in the list, you can use this code:
const int Max_Capacity = 6;
if (UrlList.Count >= Max_Capacity)
UrlList.RemoveAt(0); // <- oldest (first) item should be removed
UrlList.Add(uri.ToString());
...
// Printing out the lastest 3 items:
int start = UrlList.Count <= 3 ? 0 : UrlList.Count - 3;
for (int i = start; i < UrlList.Count; ++i)
Console.Out.WriteLine(UrlList[i]);
I think you better be using % Operator-.
In your case you can use:
UrlList.Insert((UrlList.count%6),move);
I was facing this problem earlier today, and since I could not find a satisfactory solution, I decided to change my class design, and have seperate properties such as Tag 1, Tag 2, Tag 3 etc.
My main problem is the fact that I need to bind a grid to an object that contains a list among other properties and I need to show each item in the list as a separate column which I am unable to do. Hence I am resorting to declaring variables separately. Original question is here...
Now, I'm facing one of the most common design problem that probably every programmer has at some point of time. Here is the code to demonstrate it,
for (int i = 0; i < tags.Length; ++i) // Length not known here.
{
if(i==0){
tag1 = tags[0];
}
else if(i == 1){
tag2 = tags[1];
}
else if(i == 2){
tag3 = tags[2];
}
....
}
Here tags is a string array.
I was wondering if there is a more elegant way to do this. Another thing to note is that the efficiency of this loop decreases as it progresses, since with more iterations it has to check more conditions. If we could remove a condition after it had become true once it would speed up each iteration since we know that each condition will become true only once in all the iterations
Moved answer about DataGridView and using ComponentModel to the correct question:
Displaying a list of object containing a list in a grid view
Briefing
The DataGridView controll supports the ComponentModel namespace so that you can create classes that appear to have properties that don't exist. It is the same mechanism the PropertyGrid uses.
The sample code is in this answer of that question:
https://stackoverflow.com/a/13078735/195417
OLD ANSWER
This was my previous answer, when I didn't realize the real question was about the DataGridView control.
Isn't this the same as setting the values directly:
this.tag1 = tags[0];
this.tag2 = tags[1];
this.tag3 = tags[2];
EDIT: as you sayd you don't know how many variables will be needed, then you need only one, and that is a list:
var list = new List<string>();
for (int i = 0; i < tags.Length; ++i)
{
list.add(tags[i]);
}
If all you want is to copy all values, you can even do this:
var list = new List<string>(tags);
Tell me whether this is what you want or not... maybe I have misunderstood the question.
The whole loop is pointless. But unless the tags array length is always going to be the same, you have to be sure not to go out of bounds...
if(tags.Length >= 1) this.tag1 = tags[0];
if(tags.Length >= 2) this.tag2 = tags[1];
if(tags.Length >= 3) this.tag3 = tags[2];
if(tags.Length >= 4) this.tag4 = tags[3];
if(tags.Length >= 5) this.tag5 = tags[4];
... so on for however many this.tag# you have.
This is essentially the same:
for(int index = 0; index < tags.Length[]; index++){
switch(index){
case 0:
tag1 = tags[0];
break;
// And so on
}
}
In C#, I have an Array of MenuItem. I'm trying to swap the two Objects in index 2 and index 3 of the array without success using the code below:
MenuItem Temp = Items[2];
Items[2] = Items[3];
Items[3] = Temp;
There must be a reason why the second and third lines aren't working in C# which I may not understand yet. Is anyone able to clarify it a bit more? Do I have to go deeper and swap each property in the objects individually?
Edited - Sorry. Looks like I made a mess of the code when trying to clean it up for posting. Corrected now.
The actual code is :
MenuItem TempButton = MenuItems.Items[SelectedButton.CountId];
MenuItems.Items[SelectedButton.CountId] = MenuItems.Items[SelectedButton.CountId + 1];
MenuItems.Items[SelectedButton.CountId + 1] = TempButton;
MenuItems.Items is an array of MenuItem
Looking at the Watch I have placed on MenuItems.Items, nothing happens on Line 2 or 3.
The MenuItems.Items property has get and set functions, which may be causing the issue... Will investigate further...
You are settings Items[2] to Temp, which was Items[2] to begin with, so you are effectively not doing anything. I don't know what SelectedButton.CountId is supposed to be.
But if you just want to swap indices 2 and 3, you can do this:
Item Temp = Items[2];
Items[2] = Items[3];
Items[3] = Temp;
Is SelectedButton.CountId = 2? if so I would try this:
Item Temp = MenuItems.Items[2];
MenuItems.Items[SelectedButton.CountId] = MenuItems.Items[3];
MenuItems.Items[3] = Temp;
Note the last line has a 3 in it.
This would be clearer:
Item Temp = MenuItems.Items[SelectedButton.CountId];
MenuItems.Items[SelectedButton.CountId] = MenuItems.Items[3];
MenuItems.Items[3] = Temp;
I have no idea what SelectedButton.CountId is supposed to be but you're putting Temp right back in the same slot it was to begin with. And MenuItems.Items seems to be a totally different collection from Items.
string[] items = { "one", "two", "three" };
string temp = items[1]; // temp = "two"
items[1] = items[2]; // items[1] = "three"
items[2] = temp; // items[2] = "two"
// items is now
// { "one", "three", "two" }
try:
Item Temp = Items[SelectedButton.CountId];
Items[SelectedButton.CountId] = MenuItems.Items[SelectedButton.CountId+1];
Items[SelectedButton.CountId+1] = Temp;
This should swap in a bubble fashion
I remember running into a similar source of confusion some time ago, with the DataRow.ItemArray property. This property was extremely counterintuitive for the very same reason that the Items property in your example seems so odd.
What was ultimately so confusing was that the property was designed to be copied from and assigned to, just like you normally would with a field of value type (like int, double, etc.). That is, to change the element at index 2, this would not work:
row.ItemArray[2] = "New Value";
The above code would essentially copy the values from the row into a new array, take that copy and set the value at index 2 to "New Value," and then the new array would immediately be out of scope. The way this property was supposed to work was:
object[] items = row.ItemArray;
items[2] = "New Value";
row.ItemArray = items;
Very counterintuitive, in my book (note to library developers: don't do this). But it sounds like this is probably the problem behind the issue you were seeing with your code.
In other words, I think the swapping code you have (now) is correct. The problem lies with whoever had the bright idea of making that Items property behave as if it's a value field.
I had the same problem as I wanted to move elements in a WPF-TreeView up and down. Since none of the answers solved the problem for me here is the best I could find.
private void MoveLayerUp()
{
if(Layers.SelectedItem != null)
{
int index = Layers.Items.IndexOf(Layers.SelectedItem);
if (index > 0)
{
var swap = Layers.Items[index - 1];
Layers.Items.RemoveAt(index - 1);
Layers.Items.Insert(index, swap);
}
}
}
private void MoveLayerDown()
{
if (Layers.SelectedItem != null)
{
int index = Layers.Items.IndexOf(Layers.SelectedItem);
if (index < Layers.Items.Count-1)
{
var swap = Layers.Items[index + 1];
Layers.Items.RemoveAt(index + 1);
Layers.Items.Insert(index, swap);
}
}
}
This solves the problem of assigning elements in the collection. Further it has the advantage that the current seleced item is never touched and stays selected.
Solved the issue. I think I complicated the problem a bit too much.
MenuItems.Items was a property with get/set functions that returns/sets a private ArrayList.
I created a function in the class for MenuItems which swapped the indexes in the private ArrayList. (which used standard swapping code similar to what I tried and what everyone has mentioned in their replies.)
Thanks for everyone's help.