Better solution replacing the foreach loop or refining it - c#

this.entityModel.Entities is a source to my datagrid(agdatagrid).
I have kept AutoGenerateColumns="False".
i have 6 columns in my agdatgrid
i want 6th column to be visible depending on the data of that column..ie., if any row of that column contains the data then it should be visible and if none of the row contains the data for that column it should be invisible.
So i have written a foreach loop but it takes more time to get ui loaded if the data is large. so is there any other way ?
foreach (BrowserEntity _browseEntity in this.entityModel.Entities)
{
if (_browseEntity.State != null && this.entityModel.Entities.Count>0)
{
this.grid.DataSource = this.entityModel.Entities;
this.grid.Columns[6].Visible = true;
break;
}
else
{
this.grid.DataSource = this.entityModel.Entities;
this.grid.Columns[6].Visible = false;
}
}

First look at the logic of what you're writing. You're checking whether the count of a collection is greater than zero inside a loop that iterates over it; this will always return true as the loop will not run if the collection contains anything. So what you're actually writing is this, when code that either always returns true or which cannot execute is removed:
foreach (BrowserEntity _browseEntity in this.entityModel.Entities)
{
if (_browseEntity.State != null)
{
this.grid.DataSource = this.entityModel.Entities;
this.grid.Columns[6].Visible = true;
break;
}
}
So you're assigning the data source a number of times, and never setting Visible to false, whereas I think what you're actually trying to write is something like this:
// bind the grid but hide column 6
this.grid.DataSource = this.entityModel.Entities;
this.grid.Columns[6].Visible = false;
// if there is any state then show column 6
foreach (BrowserEntity _browseEntity in this.entityModel.Entities)
{
if (_browseEntity.State != null)
{
this.grid.Columns[6].Visible = true;
break;
}
}
Alternatively, using Linq, this could be written as the following, which achieves the same thing but is much clearer:
this.grid.DataSource = this.entityModel.Entities;
this.grid.Columns[6].Visible = this.entityModel.Entities.Any(e => e.State != null);

I'm not an expert on this...but why are you resetting the DataSource every time?
bool isColumnVisible = false;
this.grid.DataSource = this.entityModel.Entities;
foreach (BrowserEntity _browseEntity in this.entityModel.Entities)
{
if (_browseEntity.State != null && this.entityModel.Entities.Count>0)
{
isColumnVisible = true;
break;
}
}
this.grid.Columns[6].Visible = isColumnVisible;
I think this should be faster...at least I hope so.

I'm not a silverlight developer, but why do you check for "this.entityModel.Entities.Count>0" in the foreach loop? I would assume the count is always >0 when you enter the loop, isn't it?

Related

If you never hit this line of code, do something

Okay, well let's say I have a variable list of items. It can be any number of items. Each item can be either 0,1,2,3, or 4. So I make a loop.
foreach(item in allitems)
{
if (item == 0) continue;
do stuff for items 1-4.
}
Let's say that every single item it goes through is 0. Well what if I want to execute a specific line of code in that case? Of course I could do something like
int count = 0
foreach(item in allitems)
{
if (item == 0) {count++; continue;}
do stuff for items 1-4.
}
if(count == allitems.Count())
{
do stuff
}
But I always felt cheap using count variables to do something like this. Is there any thing I can do that doesn't feel like duct-taping a solution together?
There's no need to use a count here - just keep a flag which is set if you get past the check, rather than within the check:
bool anyNonZeroItems = false;
foreach(item in allitems)
{
if (item == 0)
{
continue;
}
anyNonZeroItems = true;
// Whatever else
}
if (!anyNonZeroItems)
{
// Everything was 0 (or the collection was empty)
}
You can use Enumerable.All to check if all items in a List satisfy a condition.
in this case something like
if (allItems.All(i => i == 0) {
//do stuff
}
Incidentally in your example you have (if item = 0) and this should be if (item == 0)
What you currently have is perfectly acceptable. I use that kind of pattern all the time.
One thing I would suggest is making count into a bool unless there's an actually a difference between when count == 11 andcount > 1`
This is a pretty common problem, but you propose an odd solution. Why not just use a boolean to indicate state?
bool branchExecuted = false;
foreach(item in allitems)
{
if (item == 0)
{
branchExecuted = true;
continue;
}
//do stuff for items 1-4.
}
if(!branchExecuted)
{
//do stuff if we never hit that line
}
Using this instead of a LINQ / convenience function to operate on the list will only cost you a single boolean and you only have to iterate over your list once.

C# foreach statement

I need some help with a for each statement, basically what happens is when a user edits a value within a cell, my foreach will apply this to all cells within the datagrid and change the value of them all, i need my foreach statement to work by iterating through the datagrid but only change the selected row that has been edited
try
{
//loop through each of the rows in the dgv
foreach (DataGridViewRow row in dgvDetials.SelectedRows)
{
int intQtyInsp = 0;
//if quantity inspected is empty:
if (row.Cells[2].Value.ToString() == "")
{
//quantity inspected is 0. Prevents null value errors:
intQtyInsp = 0;
}
intQtyInsp =
Int32.Parse(dgvDetials.CurrentRow.Cells[2].Value.ToString());
if (intQtyInsp < 0) // checks the cell for a negative value
{
intQtyInsp = 0; // if cells is negative submits value as Zero
}
else
{
//sets quantity inspected to value entered
intQtyInsp = Int32.Parse(row.Cells[2].Value.ToString());
}
if (intQtyInsp == 0) //if quantity inspected is 0. Ignore row.
{
}
else //else gather details and insert row as production.
{
area = dtArea2.Rows[0]["area_code"].ToString();
inspDate = dtpInspectionDate.Value.ToString("MM/dd/yyyy");
inspShift = cbShift.Text;
partNo = row.Cells[0].Value.ToString();
// dieCode = row.Cells[0].Value.ToString();
dieCode = "";
machine = "";
qtyInsp = intQtyInsp;
qtyInspRecorded = Int32.Parse(row.Cells[5].Value.ToString());
comment = "";
//machine = row.Cells[3].Value.ToString();
if (qtyInspRecorded == 0)
{
SQLMethods.insertProduction(area,
inspDate,
inspShift,
partNo,
dieCode,
qtyInsp,
comment,
machine);
}
else
{
SQLMethods.updateProduction(area,
inspDate,
inspShift,
partNo,
dieCode,
(qtyInspRecorded + qtyInsp),
comment,
machine);
}
}
}
retrieveData(); //reset values
}
catch (Exception ex)
{
MessageBox.Show(
"Error instering production values. Processed with error: "
+ ex.Message);
}
First of all, I would simplify the code here a little by splitting it into several methods that may be called from the For-loop. That would make it easier to read, and thereby easier to help you too. Just to provide an example, the following:
if (intQtyInsp < 0) // checks the cell for a negative value
{
intQtyInsp = 0; // if cells is negative submits value as Zero
}
else
{
//sets quantity inspected to value entered
intQtyInsp = Int32.Parse(row.Cells[2].Value.ToString());
}
could be replaced with something like:
int intQtyInsp = SetQuantityInspected();
Then that method could contain the if-structure. Repeat this for other parts of the code in the loop too. Trust me, this will make your life easier.
Also, it seems as if the result of this section is never used; the value of intQtyInsp is overwritten right afterwards!:
if (row.Cells[2].Value.ToString() == "")
{
//quantity inspected is 0. Prevents null value errors:
intQtyInsp = 0;
}
As for your question: I'm not sure how you would get the id of the row that is currently being edited. (If possible (?), it might be getter to loop through the table / data source behind the datagrid?).
In any case, what you need to do is something like the following inside your loop:
if(IsCurrentlyEditedRow(row)){
...
// (all the stuff currently in the body of your loop goes here)
...
}
Now you can implement the method IsCurrentlyEditedRow() to return True or False depending on whether or not the id of the current row is the the same as that of the one you are editing.
Sorry if this is not a very specific and detailed answer, hope it is of some use anyway.

ComboBox.ObjectCollection doesn't update if the new value's string representation is case-insensitively equal to the current value

If I try to change a value in a ComboBox's Items, it will only actually update if the new value is different from the current value after a case-insensitive compare.
Let's make a ComboBox with one item:
ComboBox cboBox = new ComboBox();
cboBox.Items.Add("Apple");
The following code will make the ComboBox still show "Apple", even though the string should look different:
cboBox.Items[0] = "APPLE";
And the naive workaround that I've been using, which will make it display correctly:
cboBox.Items[0] = "";
cboBox.Items[0] = "APPLE";
I wanted to figure out how this was happening, so I dug around with a reflector and found this. This is the ComboBox.ObjectCollection.SetItemInternal method that gets called when you try to modify a value:
internal void SetItemInternal(int index, object value)
{
...
this.InnerList[index] = value;
if (this.owner.IsHandleCreated)
{
bool flag = index == this.owner.SelectedIndex;
if (string.Compare(this.owner.GetItemText(value), this.owner.NativeGetItemText(index), true, CultureInfo.CurrentCulture) != 0)
{
this.owner.NativeRemoveAt(index);
this.owner.NativeInsert(index, value);
if (flag)
{
this.owner.SelectedIndex = index;
this.owner.UpdateText();
}
if (this.owner.AutoCompleteSource == AutoCompleteSource.ListItems)
{
this.owner.SetAutoComplete(false, false);
return;
}
}
else
{
if (flag)
{
this.owner.OnSelectedItemChanged(EventArgs.Empty);
this.owner.OnSelectedIndexChanged(EventArgs.Empty);
}
}
}
}
That true in string.Compare is telling it to ignore the case of the string. Why was this method chosen for deciding whether or not to update the value? And why didn't they expose the case sensitivity?
Is there an alternative way to update an item in an ObjectCollection so that I don't have to guess whether or not it actually gets updated?
EDIT: I should note that the DropDownStyle is set to DropDownList: this is a read-only ComboBox that occasionally needs to be updated due to actions elsewhere in the program.
Try this, add a SelectedIndexChanged event, and inside it put:
int index = cboBox.SelectedIndex;
if (index - 1 >= 0) {
cboBox.SelectedIndex = index - 1;
cboBox.SelectedIndex = index;
}
else if (index + 1 < cboBox.InnerList.Count) {
cboBox.SelectedIndex = index + 1;
cboBox.SelectedIndex = index;
}
This is probably as "naive" as your work around, but maybe worth a try?
After submitting a report to the MSDN, it was marked as "by-design" and nothing more, so that's that.

Update List element at specified list item position

I am trying to do this:
foreach (Settings sets in MySets)
{
if (sets.pName == item.SubItems[2].Text)
{
var ss = new SettingsForm(sets);
if (ss.ShowDialog() == DialogResult.OK)
{
if (ss.ResultSave)
{
sets = ss.getSettings();
}
}
return;
}
}
But since the sets spawned variable is readonly, I cant override it.
I would also like to do something like this
foreach (Settings sets in MySets)
{
if(sets.pName == someName)
sets.RemoveFromList();
}
How can I accomplish this? Lists have a very nice Add() method, but they forgot the rest :(
You can use:
MySets.RemoveAll(sets => sets.pName == someName);
to remove all the items that satisfy a specific condition.
If you want to grab all the items satisfying a condition without touching the original list, you can try:
List<Settings> selectedItems = MySets.FindAll(sets => sets.pName == someName);
foreach loops don't work here as trying to change the underlying list will cause an exception in the next iteration of the loop. Of course, you can use a for loop and manually index the list. However, you should be very careful not to miss any items in the process of removing an item from the list (since the index of all the following items will get decremented if an element is removed):
for (int i = 0; i < MySets.Count; ++i) {
var sets = MySets[i]; // simulate `foreach` current variable
// The rest of the code will be pretty much unchanged.
// Now, you can set `MySets[i]` to a new object if you wish so:
// MySets[i] = new Settings();
//
// If you need to remove the item from a list and need to continue processing
// the next item: (decrementing the index var is important here)
// MySets.RemoveAt(i--);
// continue;
if (sets.pName == item.SubItems[2].Text)
{
var ss = new SettingsForm(sets);
if (ss.ShowDialog() == DialogResult.OK)
{
if (ss.ResultSave)
{
// Assigning to `sets` is not useful. Directly modify the list:
MySets[i] = ss.getSettings();
}
}
return;
}
}
You can't do it in a 'regular' for loop?

C# DataRow Empty-check

I got this:
DataTable dtEntity = CreateDataTable();
drEntity = dtEntity.NewRow();
Then I add data to the row (or not).
Lots of code, really don't know if there's anything inside the row.
Depends on the input (i am importing from some files).
I'd like to do something like:
if (drEntity`s EVERY CELL IS NOT EMPTY)
{
dtEntity.Rows.Add(drEntity);
}
else
{
//don't add, will create a new one (drEntity = dtEntity.NewRow();)
}
Is there some nice way to check if the DataRow's every cell is empty?
Or I should foreach, and check them one by one?
A simple method along the lines of:
bool AreAllColumnsEmpty(DataRow dr)
{
if (dr == null)
{
return true;
}
else
{
foreach(var value in dr.ItemArray)
{
if (value != null)
{
return false;
}
}
return true;
}
}
Should give you what you're after, and to make it "nice" (as there's nothing as far as I'm aware, in the Framework), you could wrap it up as an extension method, and then your resultant code would be:
if (datarow.AreAllColumnsEmpty())
{
}
else
{
}
I created an extension method (gosh I wish Java had these) called IsEmpty as follows:
public static bool IsEmpty(this DataRow row)
{
return row == null || row.ItemArray.All(i => i is DBNull);
}
The other answers here are correct. I just felt mine lent brevity in its succinct use of Linq to Objects. BTW, this is really useful in conjunction with Excel parsing since users may tack on a row down the page (thousands of lines) with no regard to how that affects parsing the data.
In the same class, I put any other helpers I found useful, like parsers so that if the field contains text that you know should be a number, you can parse it fluently. Minor pro tip for anyone new to the idea. (Anyone at SO, really? Nah!)
With that in mind, here is an enhanced version:
public static bool IsEmpty(this DataRow row)
{
return row == null || row.ItemArray.All(i => i.IsNullEquivalent());
}
public static bool IsNullEquivalent(this object value)
{
return value == null
|| value is DBNull
|| string.IsNullOrWhiteSpace(value.ToString());
}
Now you have another useful helper, IsNullEquivalent which can be used in this context and any other, too. You could extend this to include things like "n/a" or "TBD" if you know that your data has placeholders like that.
I prefer approach of Tommy Carlier, but with a little change.
foreach (DataColumn column in row.Table.Columns)
if (!row.IsNull(column))
return false;
return true;
I suppose this approach looks more simple and cleaner.
public static bool AreAllCellsEmpty(DataRow row)
{
if (row == null) throw new ArgumentNullException("row");
for (int i = row.Table.Columns.Count - 1; i >= 0; i--)
if (!row.IsNull(i))
return false;
return true;
}
I know this has been answered already and it's an old question, but here's an extension method to do the same:
public static class DataExtensions
{
public static bool AreAllCellsEmpty(this DataRow row)
{
var itemArray = row.ItemArray;
if(itemArray==null)
return true;
return itemArray.All(x => string.IsNullOrWhiteSpace(x.ToString()));
}
}
And you use it like so:
if (dr.AreAllCellsEmpty())
// etc
You could use this:
if(drEntity.ItemArray.Where(c => IsNotEmpty(c)).ToArray().Length == 0)
{
// Row is empty
}
IsNotEmpty(cell) would be your own implementation, checking whether the data is null or empty, based on what type of data is in the cell. If it's a simple string, it could end up looking something like this:
if(drEntity.ItemArray.Where(c => c != null && !c.Equals("")).ToArray().Length == 0)
{
// Row is empty
}
else
{
// Row is not empty
}
Still, it essentially checks each cell for emptiness, and lets you know whether all cells in the row are empty.
DataTable.NewRow will initialize each field to:
the default value for each DataColumn (DataColumn.DefaultValue)
except for auto-increment columns (DataColumn.AutoIncrement == true), which will be initialized to the next auto-increment value.
and expression columns (DataColumn.Expression.Length > 0) are also a special case; the default value will depend on the default values of columns on which the expression is calculated.
So you should probably be checking something like:
bool isDirty = false;
for (int i=0; i<table.Columns.Count; i++)
{
if (table.Columns[i].Expression.Length > 0) continue;
if (table.Columns[i].AutoIncrement) continue;
if (row[i] != table.Columns[i].DefaultValue) isDirty = true;
}
I'll leave the LINQ version as an exercise :)
AFAIK, there is no method that does this in the framework. Even if there was support for something like this in the framework, it would essentially be doing the same thing. And that would be looking at each cell in the DataRow to see if it is empty.
I did it like this:
var listOfRows = new List<DataRow>();
foreach (var row in resultTable.Rows.Cast<DataRow>())
{
var isEmpty = row.ItemArray.All(x => x == null || (x!= null && string.IsNullOrWhiteSpace(x.ToString())));
if (!isEmpty)
{
listOfRows.Add(row);
}
}
Maybe a better solution would be to add an extra column that is automatically set to 1 on each row. As soon as there is an element that is not null change it to a 0.
then
If(drEntitity.rows[i].coulmn[8] = 1)
{
dtEntity.Rows.Add(drEntity);
}
else
{
//don't add, will create a new one (drEntity = dtEntity.NewRow();)
}
To delete null and also empty entries Try this
foreach (var column in drEntitity.Columns.Cast<DataColumn>().ToArray())
{
if (drEntitity.AsEnumerable().All(dr => dr.IsNull(column) | string.IsNullOrEmpty( dr[column].ToString())))
drEntitity.Columns.Remove(column);
}

Categories