How to do this in c#? - c#

I have a List of MyClass and in the main page I have 10 controls which will display the information about that list of Items. What I want is to check the count of the items in the List and then make the excess controls invisible. Now I'm using this code but is there an easier way of doing this?
if (myList.Count > 0)
{
Control1.MyClassInfo = myList[0];
if (myList.Count > 1)
{
Control2.MyClassInfo = myList[1];
if (myList.Count > 2)
{
// and like that till 10
}
else
{
Control3.Visible = false;
Control4.Visible = false;
// till 10
}
}
else
{
Control2.Visible = false;
Control3.Visible = false;
// till 10
}
}
else
{
Control1.Visible = false;
Control2.Visible = false;
Control3.Visible = false;
// and then till 10
}

Well, just add your controls in a list (ordered).
Something like that
var controlList = new List<Control>{ Control1, Control2, Control3 /*etc*/};
var count = myList.Count;
for (var i = 0; i < controlList.Count; i++) {
controlList[i].Visible = count > i;
}

You could create a list of your controls
List<Control> MyControls = new List<Control>{Control1, Control2,..,Control10};
and then
foreach(var C in MyControls)
C.Visible=false;
for(int i=0; i<myList.Count; i++)
C[i].Visible=true;

EDIT: for the more advanced coders here, this technique is called the Composite Pattern.
Basically, that's it. But you can improve on that basic concept in two ways:
1) use a collection
List<Control> _controls1to10;
Put your controls into that collection and write a method like this:
private void setVisibility(List<Control> _controls, bool visible)
{
foreach (Control c in _controls1to10)
{
c.Visible = visible;
}
}
This will make things easier.
2) use boolean expressions instead of nested ifs, like this:
bool hasElements = myList.Count > 0;
bool hasMoreThan1 = myList.Count > 1;
// ... and so on
This means that you have master switches at the top and use them in the following code. This is a fantasy example to clear the concept but does not apply to your code:
bool isEditable = User.LoggedIn && SystemState.Maintenance == false && item.Count > 0;
editButton.Visible = isEditable;
dropList.Visible = !isEditable;

Related

Trying to change an element in a Collection

I'm trying to modify this code. I need to check for a value in a specific element of FilteredCheckObservable and if true, change the value of another part of that element.
Basically something like
if (FilteredCheckObservable items.Lang = 'ENG')
{items.check = newcheckname;}
Then this will update the sourceGroups Collection.
if (string.IsNullOrEmpty(departmentLine.LineID) || string.IsNullOrEmpty(departmentLine.LineName))
continue;
bool discovered = false;
foreach (var group in sourceGroups)
{
if (!group.Key.Line.IsEqual(departmentLine))
continue;
group.Key.IsDiscovered = true;
discovered = true;
group.Key.ScheduleStatusCount = group.CountGroupItem;
break;
}
if (discovered == false)
{
var _ScheduleItemObservable = new ScheduleItemObservable(departmentLine, MainViewViewModel, Shift.ToString());
var item = new Grouping<ScheduleItemObservable, FilteredCheckObservable>(_ScheduleItemObservable);
if (IsShiftValid)
{
item.Key.Shift = Shift.ToString();
item.Key.IsHistoryEnabled = true;
}
sourceGroups.Add(item);
}
for (int index = 0; index < sourceGroups.Count; index++)
{
if (sourceGroups[index].Key.IsDiscovered == true)
{
foreach (var group in sourceGroups)
{
foreach (FilteredCheckObservable items in group)
{
if (items.Lang_ID == LanguageService.Instance.LanguageType.ToString())
{
sourceGroups.Clear();
sourceGroups.Add(item);
}
}
}
}
}
Welcome Travis,
I would wager the guilty culprit is your foreach loop.
https://stackoverflow.com/a/759985/3403999
You aren't allowed to modify a collection inside of a foreach loop.
I don't know if your collection has an indexer, but if it does, you can convert to a for loop:
for (int i = 0; i < sourceGroups.Count; i++)
{
var group = sourceGroups[i];
// The rest of your code.
I could be wrong. You do say you are trying to modify some existing code. Is it some code that is online? Maybe you could link to it to provide a full context.
Based on your new snippet, you need two for loops:
for (int index = 0; index < sourceGroups.Count; index++)
{
if (sourceGroups[index].Key.IsDiscovered == true)
{
//foreach (var group in sourceGroups)
for (int j = 0; j < sourceGroups.Count; j++)
{
var group = sourceGroups[j];
foreach (FilteredCheckObservable items in group)
{
if (items.Lang_ID == LanguageService.Instance.LanguageType.ToString())
{
sourceGroups.Clear();
sourceGroups.Add(item);
}
}
}
}
}
^ Although that might still be a bad loop. Primarily because you have sourceGroups.Clear();.
What you might be better off doing is creating an internal collection called say 'results'. Do your loop looking for your conditions, and if they meet, add that item to the results collection.
Once your loops terminate, then call sourceGroups.Clear(), and then sourceGroups.AddRange(results). If sourceGroups doesn't have an AddRange, then one final loop of:
foreach (var group in results) { sourceGroups.Add(group); }

how to check error conditions c#

I have group of conditions like
foreach
{
Condition a
condition b
}
So I am validating the values based on conditions.I am facing the problem: for example I have list of items like {1,2,3,4}. So I have a condition like if item 1 is fail then item 2,3,4 should be fail.
if item 2 is fail then item 3,4 should be fail and so on.
I am trying in below code.
foreach (SagaData item in lstPrm)
{
PriceDetail prevPrice = null;
PriceDetail currentPrice = null;
PriceDetail nextPrice = null;
bool bHasError = false;
int iPriceMasterId = 0;
int iPriceTypeId = 0;
string sMprCurrencyType = null;
string sPublisherCurrencyType = null;
int? iExpirationCalendarId = 0;
string sPRMMessage = string.Empty;
//a) If Change Indicator = C or A and Price = 0.00: Cannot change price value to zero.
if ((item.ChangeIndicator == 'C' || item.ChangeIndicator == 'A') && item.PostingPrice == 0)
{
bHasError = true;
sPRMMessage = "FAILURECannot change price value to zero";
}
//b) If Change Indicator = D and Price > 0.00: Invalid deactivation.
if ((item.ChangeIndicator == 'D') && (item.PostingPrice > 0) && (!bHasError))
{
bHasError = true;
sPRMMessage = "FAILUREInvalid deactivation";
}
so i have if condition a fail for item 1 then how should i keep maintain the error for next iteration.
Thanks for the help. if you want more info plz let me know.
You can go through your Collection with a simple for loop and use an ErrorArray:
bool[] bHasError = new bool[lstPrm.Count];
for (int i = 0; i < lstPrm.Count; i++)
{
...
bHasError[i] = true;
...
}
or you can define bHasError BEFORE the foreach if one error is enough for you to consider.

Iterating Through TextBoxes to Check If Empty WPF

I'm attempting to iterate through all the textboxes in my WPF window to see if they are empty, and if they are, the method should set a bool to true.
private void checkTextBoxes(DependencyObject obj)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
if (obj is TextBox && ((TextBox)obj).Text == null)
{
isTextBoxEmpty = true;
}
}
}
isTextBoxEmpty is my bool that has been defined outside of the method. I call the method using:
checkTextBoxes(this);
But the bool always returns false no matter what I do, even if all the text boxes are empty.
Try to change this :
((TextBox)obj).Text == null)
To this :
(String.IsNullOrEmpty((TextBox)obj).Text))
The result you got possibly because TextBox's Text is never null, it is empty string ("") by default, thats what I think, just possibly.
Outside of any syntax errors this should give you the result you expect; This only returns true if ALL textboxes are blank
private void checkTextBoxes(DependencyObject obj)
{
var trueforall = true;
var atleastone = false;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
if (obj is TextBox)
{
if(!atleastone){ atleastone = true;}
trueforall &= string.IsNullOrWhiteSpace(((TextBox)obj).Text);
if (!trueforall) { break; }
}
}
isTextBoxEmpty = trueforall && atleastone;
}

Sorting a DropDownList?

I'm curious as to the best route (more looking towards simplicity, not speed or efficiency) to sort a DropDownList in C#/ASP.NET - I've looked at a few recommendations but they aren't clicking well with me. this drop down is giving me list in alphabetical order. But I have to sort out randomly.
Note:I do not have control over how the data comes into the DropDownList - I cannot modify the SQL.
public void populateLocationList()
{
DataTable dt_locations = (DataTable)daa_addresses.GetDataByEventLocations(int_eventid);
if (dt_locations != null && dt_locations.Rows.Count > 0)
{
// Populate locations dropdown menu
// Bind locationsList instead of dt_locations
ddl_locations.DataTextField = "Key";
ddl_locations.DataValueField = "Value";
ddl_locations.DataSource = RemoveDuplicateLocations(dt_locations);
ddl_locations.DataBind();
string location = "";
// Set the selection based upon the query string
if (Request.QueryString["loc"] != null)
{
location = Request.QueryString["loc"];
locationLbl.Text = Request.QueryString["loc"];
locationID.Value = "-1";
}
if (dt_locations.Rows.Count == 1)
{
location = ddl_locations.Items[0].Text;
locationLbl.Text = location;
}
// Set location in drop down list
int int_foundlocation = 0;
bool foundLocation = false;
foreach (ListItem lsi_item in ddl_locations.Items)
{
if (lsi_item.Text.ToLower().Trim() == location.ToLower().Trim())
{
int_foundlocation = ddl_locations.Items.IndexOf(lsi_item);
foundLocation = true;
break;
}
}
ddl_locations.SelectedIndex = int_foundlocation;
if (ddl_locations.Items.Count == 1)
{
// Make location label visible.
locationLbl.Visible = true;
ddl_locations.Visible = false;
}
else
{
locationLbl.Visible = false;
ddl_locations.Visible = true;
}
//* defualt location S for short courses *//
if (!IsPostBack && !foundLocation)
{
ListItem s = ddl_locations.Items.FindByText("S");
int index = 0;
if (s != null)
{
index = ddl_locations.Items.IndexOf(s);
}
ddl_locations.SelectedIndex = index;
ddl_locations.DataBind();
}
}
}
I have to sort out randomly.
You'd have to shuffle rows, probably with something close to this code (borrowed from #configurator's answer):
internal static class Extensions
{
internal static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
T[] elements = source.ToArray();
// Note i > 0 to avoid final pointless iteration
for (int i = elements.Length - 1; i > 0; i--)
{
// Swap element "i" with a random earlier element it (or itself)
int swapIndex = rng.Next(i + 1);
yield return elements[swapIndex];
elements[swapIndex] = elements[i];
// we don't actually perform the swap, we can forget about the
// swapped element because we already returned it.
}
// there is one item remaining that was not returned - we return it now
yield return elements[0];
}
}
Assuming that RemoveDuplicateLocations returns a DataTable the binding part of your code should be changed to:
ddl_locations.DataSource = RemoveDuplicateLocations(dt_locations)
.AsEnumerable()
.Shuffle(new Random())
.CopyToDataTable();

Object reference not set to an instance of an object exception when assigning a list to a listbox

I wrote the following method to load a list box with values that have not been loaded already but I am getting an Object reference not set to an instance of an object exception when assigning the following. Any information would be helpful. Thanks.
lbxCabinetName.Items.Add(cabinetsCurrentNotUsed[i].ToString());
// Defined outside a method
List<string> cabinetsCurrentNotUsed;
// Set value in the constructor
cabinetsCurrentNotUsed = new List<string>();
Here is the whole procedure.
private void selectCabinetToAdd()
{
// Loop through all server and form cabinet types to see if there are matches
for (int x = 0; x < opticalFile.serverCabinetNames.Count; x++)
{
bool cabinetExists = false;
for (int i = 0; i < opticalFile.CabinetValues.Count; i++)
{
if (opticalFile.serverCabinetNames[x].ToString() == opticalFile.CabinetValues[i].ToString())
{
cabinetExists = true;
}
}
// Add cabinets not used to cabinetsCurrentNotUsed List
if (!cabinetExists)
{
cabinetsCurrentNotUsed.Add(opticalFile.serverCabinetNames[x].ToString());
}
}
// Send cabinetsCurrentNotUsed List to list box
for (int i = 0; i < cabinetsCurrentNotUsed.Count; i++)
{
lbxCabinetName.Items.Add(cabinetsCurrentNotUsed[i].ToString());
}
}
You are trying to add a null to the listbox.
Insted of
for (int i = 0; i < cabinetsCurrentNotUsed.Count; i++)
{
lbxCabinetName.Items.Add(cabinetsCurrentNotUsed[i].ToString());
}
use
foreach (string s in cabinetsCurrentNotUsed)
{
if(s != null)
lbxCabinetName.Items.Add(s);
}
NOTE
This part is not relavant to the question. But in your inner for loop after setting cabinetExists = true; you can break out of the inner loop (if atleast one condition is met you can make sure the cabinetExists is true. you don't have to check for the rest of the items in the inner loop)
EDIT
private void selectCabinetToAdd()
{
foreach (string sc in serverCabinetNames)
{
bool cabinetExists = false;
foreach (string cv in CabinetValues)
{
if (sc == cv)
{
cabinetExists = true;
break;
}
}
if (!cabinetExists)
{
cabinetsCurrentNotUsed.Add(sc);
}
}
foreach (string ccnu in cabinetsCurrentNotUsed)
{
if (ccnu != null)
lbxCabinetName.Items.Add(ccnu);
}
}
Also if your listBox can be null, make sure you check that first before populating the listbox.
if(lbxCabinetName != null)
{
selectCabinetToAdd();
}
EDIT 2
Dynamically adding control
ListBox lbxCabinetName = new ListBox();
lbxCabinetName.Location = new System.Drawing.Point(10, 55);
lbxCabinetName.Size = new System.Drawing.Size(130, 95);
this.Controls.Add(lbxCabinetName);
Strings are nullable so at some point you must be doing something similar to:
cabinetsCurrentNotUsed.Add(null);
Either that or as dbaseman said it is possible lbxCabinetName is null but I'm betting that isn't the case.
As an aside, it's not really a problem but if you're using a generic list of strings the ToString() call isn't necessary. You can just do this:
lbxCabinetName.Items.Add(cabinetsCurrentNotUsed[i]);

Categories