check if linq operation is null before execution C# - c#

I have a Win-form with 60 Radio-buttons. I want to get the Text from the checked radio-buttons with this code:
private void button1_Click_1(object sender, EventArgs e)
{
string[] boxes = new string[30];
string[] names = new string[30];
for (int i = 1; i < boxes.Length; i++)
{
var label = this.Controls.Find("lb" + i, true)[0];
var panelcontr = this.Controls.Find("panel" + i, true)[0] as Panel;
var panels = panelcontr;
var p = panels.Controls.OfType<RadioButton>()
.FirstOrDefault(r => r.Checked).Text;
boxes[i] += p;
names[i] += label.Text;
tobeWritten += names[i] + boxes[i] + ",";
textBox1.Text = "Anamnese(" + tobeWritten + ")";
}
}
It works totally fine but the problem is, when just one radio-box is unchecked I get a warning during Debug. I know why the Warning appears but I want the Program not to stop.
What I'm asking is: Is it possible to create a MessageBox which appears, when I haven't checked a radioButton which e.g. says "You have to assign every button". I click the "OK"-Button and I am able to check the unchecked Button.
I tried with the suggestions from an other question at StackOverflow but no success because the function panels.Controls.OfType<RadioButton>() gets executed before the query.

You get a NullReferenceException here if there is no checked RadioButton:
var p = panels.Controls.OfType<RadioButton>()
.FirstOrDefault(r => r.Checked).Text;
Because FirstOrDefault returns null since RadioButton is a reference type. Then you can't access it's Text property. So how to avoid that?
Store the result and check if it's null before you use it:
RadioButton firstCheckedRadioButton = panels.Controls.OfType<RadioButton>()
.FirstOrDefault(r => r.Checked);
if(firstCheckedRadioButton != null)
{
string text = firstCheckedRadioButton.Text;
// ...
}

Your issue is here:
var p = panels.Controls.OfType<RadioButton>()
.FirstOrDefault(r => r.Checked).Text;
If the result of the FirstOrDefault call is null, the Text call will throw a null reference exception. You can avoid this by splitting up the calls, so that you call FirstOrDefault, check whether the result is null, and then call Text only once you know the result is not null.

Would it help to replace
var p = panels.Controls.OfType<RadioButton>()
.FirstOrDefault(r => r.Checked).Text;
with
var ch = panels.Controls.OfType<RadioButton>()
.FirstOrDefault(r => r.Checked);
if (ch == null)
{
// show message box and break;
}
var p = ch.Text;

It works now with this code:
private void button1_Click_1(object sender, EventArgs e)
{
string[] boxes = new string[30];
string[] names = new string[30];
for (int i = 1; i < boxes.Length; i++)
{
var label = this.Controls.Find("lb" + i, true)[0];
var panelcontr = this.Controls.Find("panel" + i, true)[0] as Panel;
var panels = panelcontr;
var radiobutton = panels.Controls.OfType<RadioButton>()
.FirstOrDefault(r => r.Checked);
if(radiobutton==null)
{
MessageBox.Show("Check all Buttons!");
break;
}
boxes[i] += radiobutton.Text;
names[i] += label.Text;
tobeWritten += names[i] + boxes[i] + ",";
textBox1.Text = "Anamnese(" + tobeWritten + ")";
}
}

Related

C# Checkbox-Dialog How to uncheck

I have a Windows Forms Dialog in C# which shows Checkboxes for each Element in a Dictionary. The Dialog returns a List with all selected Elements(Checkboxes). However I noticed that if I select a Checkbox and then uncheck it again, the Element is still in the returned List of Selected Elements.
How can I fix this?
My Dialog looks like this:
public SelectDialog(Dictionary<string, string> Result)
{
int left = 45;
int idx = 0;
InitializeComponent();
for (int i = 0; i < Result.Count; i++)
{
CheckBox rdb = new CheckBox();
rdb.Text = Result.Values.ElementAt(i).Equals("") ? Result.Keys.ElementAt(i) : Result.Values.ElementAt(i);
rdb.Size = new Size(100, 30);
this.Controls.Add(rdb);
rdb.Location = new Point(left, 70 + 35 * idx++);
if (idx == 3)
{
idx = 0; //Reihe zurücksetzen
left += rdb.Width + 5; // nächste Spalte
}
rdb.CheckedChanged += (s, ee) =>
{
var r = s as CheckBox;
if (r.Checked)
this.selectedString.Add(r.Text);
};
}
}
//Some more Code
}
As per the comment:
You need to remove the items from the list if the raised event is unchecked, I think you have to check for already added items to avoid duplicates, and remove the items if exists. so the handler would be like this:
rdb.CheckedChanged += (s, ee) =>
{
var r = s as CheckBox;
var itemIndex = this.selectedString.IndexOf(r.Text)
if (r.Checked && itemIndex == -1)
this.selectedString.Add(r.Text);
else if(!r.Checked && itemIndex != -1)
{
this.selectedString.RemoveAt(itemIndex);
}
};

Comparing TextBox values without arrays. C#

I have a basic program with 26 TextBoxes named textBox1 to textBox26 and a button. The button currently gives a value of 1,x or 2 to each TextBox. I also want it to compare the values of a TextBox and the one with a name contaning a number 13 greater than the last without using an array or multiple if/else statements. For example I want to compare textBox1 with textBox14. I currently have this code:
Random r = new Random();
int ran;
int x;
int y;
private void button1_Click(object sender, EventArgs e)
{
foreach (Control b in this.Controls.OfType<TextBox>())
{
ran = r.Next(1, 4);
if (ran == 1)
{
b.Text = "1";
}
else if (ran == 2)
{
b.Text = "x";
}
else if (ran == 3)
{
b.Text = "2";
}
x = b.TabIndex;
y = x + 13;
var box = (TextBox)this.Controls.Find("textBox" + x.ToString());
var box1 = (TextBox)this.Controls.Find("textBox" + y.ToString());
box.Text = box1.Text;
}
}
This gives the the error message:
There is no argument given that corresponds to the required formal parameter 'search Children' of 'Control.ControlCollection.Find(string, bool)'
on the lines with:
var box = (TextBox)this.Controls.Find("textBox" + x.ToString());
var box1 = (TextBox)this.Controls.Find("textBox" + y.ToString());
Your specific error is because you're not providing a value for the argument (as the error states...):
var box = (TextBox)this.Controls.Find("textBox" + x.ToString(), false);
Use false, as in my example, or true depending on your needs. Do you want the search to include controls (i.e. children) that are nested inside the controls you are searching?

Use i in variable name

So I have this kind of code (I'm assigning values to XAML elements
), which begs for a "for" loop.
Day1d.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(1));
Day2d.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(2));
Day3d.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(3));
Day4d.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(4));
Day1t.Text = "°" + (myWeatherForecast.forecastlist[1].temp).ToString();
Day2t.Text = "°" + (myWeatherForecast.forecastlist[2].temp).ToString();
Day3t.Text = "°" + (myWeatherForecast.forecastlist[3].temp).ToString();
Day4t.Text = "°" + (myWeatherForecast.forecastlist[4].temp).ToString();
But all my attempts to include "i" in variable name failed miserably. Is there a way to achieve this?
You can create a loop where you iterate over the instances:
int counter = 1; // are you sure it shouldn't start at 0?
foreach (TextBox tb in new TextBox[] { Day1d, Day2d, Day3d, Day4d })
{
tb.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(counter));
counter++;
}
counter = 1;
foreach (TextBox tb in new TextBox[] { Day1t, Day2t, Day3t, Day4t })
{
tb.Text = "°" + (myWeatherForecast.forecastlist[counter].temp).ToString();
counter++;
}
You can't compose the name of the variable using another variable. The way to do this would be to create a List and then iterate over that List
var textBoxes1 = new List<TextBox> { Day1d, Day2d, Day3d, Day4d }
var textBoxes2 = new List<TextBox> { Day1t, Day2t, Day3t, Day4t }
foreach (var textbox in textBoxes1)
{
var index = textBoxes1.IndexOf(textBox) + 1;
textbox.Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(index));
}
foreach (var textbox in textBoxes2)
{
var index = textBoxes2.IndexOf(textBox) + 1;
textbox.Text = "°" + (myWeatherForecast.forecastlist[index].temp).ToString();
}
NOTE: You can solve this in different ways:
using arrays instead of lists
keeping your own counter, instead of doing IndexOf
using a for loop, instead of a foreach
Which one is better is mostly based on opinion (although my method is not the fastest, but it doesn't matter if you only have 4 items)
You can use FindName assuming you are using WPF.
Try:
for (int i = 1; i < 5; i++)
{
((TextBox)this.FindName("Day" + i + "d")).Text = string.Format("{0:dd/MM}", DateTime.Today.AddDays(i));
((TextBox)this.FindName("Day" + i + "t")).Text = "°" + (myWeatherForecast.forecastlist[i].temp).ToString();
}

Getting CheckBoxList Item values

I have a CheckBoxList which I'm populating with data. When I attempt to retrieve the checked items from the list I can only grab the item ordinal, I cannot get the value.
I've read that you can use Items[i].Value however when I try to do this I get an error stating that there is no extension method 'value'.
Here's the code I'm using to try and grab the information (note the GetItemText(i) actually only gives me the item position, not the text for the item)
private void btnGO_Click(object sender, EventArgs e)
{
for (int i = 0; i < chBoxListTables.Items.Count; i++)
{
if (chBoxListTables.GetItemChecked(i))
{
string str = chBoxListTables.GetItemText(i);
MessageBox.Show(str);
//next line invalid extension method
chBoxListTables.Items[i].value;
}
}
}
This is using .Net 4.0
Any thoughts would be appreciated...thanks
This ended up being quite simple. chBoxListTables.Item[i] is a string value, and an explicit convert allowed it to be loaded into a variable.
The following code works:
private void btnGO_Click(object sender, EventArgs e)
{
for (int i = 0; i < chBoxListTables.Items.Count; i++)
{
if (chBoxListTables.GetItemChecked(i))
{
string str = (string)chBoxListTables.Items[i];
MessageBox.Show(str);
}
}
}
Try to use this.
for (int i = 0; i < chBoxListTables.Items.Count; i++)
{
if (chBoxListTables.Items[i].Selected)
{
string str = chBoxListTables.Items[i].Text;
MessageBox.Show(str);
var itemValue = chBoxListTables.Items[i].Value;
}
}
The "V" should be in CAPS in Value.
Here is another code example used in WinForm app and runs properly.
var chBoxList= new CheckedListBox();
chBoxList.Items.Add(new ListItem("One", "1"));
chBoxList.Items.Add(new ListItem("Two", "2"));
chBoxList.SetItemChecked(1, true);
var checkedItems = chBoxList.CheckedItems;
var chkText = ((ListItem)checkedItems[0]).Text;
var chkValue = ((ListItem)checkedItems[0]).Value;
MessageBox.Show(chkText);
MessageBox.Show(chkValue);
to get the items checked you can use CheckedItems or GetItemsChecked. I tried below code in .NET 4.5
Iterate through the CheckedItems collection. This will give you the item number in the list of checked items, not the overall list. So if the first item in the list is not checked and the second item is checked, the code below will display text like Checked Item 1 = MyListItem2.
//Determine if there are any items checked.
if(chBoxListTables.CheckedItems.Count != 0)
{
//looped through all checked items and show results.
string s = "";
for (int x = 0; x < chBoxListTables.CheckedItems.Count; x++)
{
s = s + (x + 1).ToString() + " = " + chBoxListTables.CheckedItems[x].ToString()+ ", ";
}
MessageBox.Show(s);//show result
}
-OR-
Step through the Items collection and call the GetItemChecked method for each item. This will give you the item number in the overall list, so if the first item in the list is not checked and the second item is checked, it will display something like Item 2 = MyListItem2.
int i;
string s;
s = "Checked items:\n" ;
for (i = 0; i < checkedListBox1.Items.Count; i++)
{
if (checkedListBox1.GetItemChecked(i))
{
s = s + "Item " + (i+1).ToString() + " = " + checkedListBox1.Items[i].ToString() + "\n";
}
}
MessageBox.Show (s);
Hope this helps...
//Simple example code:
foreach (var item in YourCheckedListBox.CheckedItems)
{List<string>.Add(item);}
You can try this:-
string values = "";
foreach(ListItem item in myCBL.Items){
if(item.Selected)
{
values += item.Value.ToString() + ",";
}
}
values = values.TrimEnd(','); //To eliminate comma in last.
Instead of this:
CheckboxList1.Items[i].value;
Try This:
CheckboxList1.Items[i].ToString();
It worked for me :)
Try to use this :
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < chBoxListTables.Items.Count; i++)
if (chBoxListTables.GetItemCheckState(i) == CheckState.Checked)
{
txtBx.text += chBoxListTables.Items[i].ToString() + " \n";
}
}
You can initialize a list of string and add those items that are selected.
Please check code, works fine for me.
List<string> modules = new List<string>();
foreach(ListItem s in chk_modules.Items)
{
if (s.Selected)
{
modules.Add(s.Value);
}
}
This will do the trick for you:
foreach (int indexChecked in checkedListBox1.CheckedIndices)
{
string itemtxt = checkedListBox11.Items[indexChecked];
}
It will return whatever string value is in the checkedlistbox items.

Accessing dynamically created checkbox in c#

I am creating a few checkboxes when I open a form with the following code:
private void OpenFolder_Load(object sender, EventArgs e)
{
int i = 0;
foreach (string file in filesToOpen)
{
Label lbl = new Label();
lbl.Text = Path.GetFileNameWithoutExtension(file);
lbl.Width = 200;
lbl.Height = 25;
lbl.AutoEllipsis = true;
lbl.Location = new System.Drawing.Point(10, 40 + 25 * i);
this.Controls.Add(lbl);
string checkName = "check" + i;
CheckBox check = new CheckBox();
check.Checked = true;
check.AccessibleName = checkName;
check.Location = new System.Drawing.Point(340, 40 + 25 * i);
check.CheckedChanged +=new EventHandler(check_CheckedChanged);
this.Controls.Add(check);
CheckBoxes.Add(check);
i++;
}
and I am trying to check the state of the checkboxes everytime one changes to toggle my OK button (the user can validate only if there are a certain number of the checkboxes checked)
here is the code I use, but it fails as I am not able to target the checkboxes:
private void check_CheckedChanged(Object sender, EventArgs e)
{
for (int i = 0; i < filesToOpen.Count(); i++)
{
string tbarName = "tbar" + i;
string checkName = "check" + i;
CheckBox ckb = this.Controls.OfType<CheckBox>()
.Where(c => c.AccessibleName.Equals(checkName)) as CheckBox;
TrackBar tkb = this.Controls.OfType<TrackBar>()
.Where(t => t.AccessibleName.Equals(tbarName)) as TrackBar;
//TrackBar tkb = this.Controls.Find(tbarName, false).First() as TrackBar;
//CheckBox ckb = this.Controls.Find(checkName, false).First() as CheckBox;
if (ckb.Checked == true)
{
//do stuff
}
}
}
what am I doing wrong/really wrong?
Given that you add the checkboxes to your own list:
CheckBoxes.Add(check);
it would be simpler to loop over that rather than trying to find the control associated with the file:
foreach (var checkBox in CheckBoxes)
{
if (checkbox.Checked)
{
// Do stuff...
}
}
However, you shouldn't need to use a separate list. This line is wrong:
CheckBox ckb = this.Controls.OfType<CheckBox>()
.Where(c => c.AccessibleName.Equals(checkName)) as CheckBox;
Where returns a IEnumerable<CheckBox> but you are trying to cast it directly to a CheckBox which will return null. What you should have is:
CheckBox ckb = this.Controls.OfType<CheckBox>()
.Where(c => c.AccessibleName.Equals(checkName)).First();
You will still need to check to see if ckb is null (just in case there is nothing on the list) but this should return you the control you are looking for.
Check the type of "this" and then check its Controls collection - your checkboxes are probably a few iterations down the tree.
You'd need some kind of recursive find controls function such as the one found in this article
Iterating over all the checkboxes with every check is not required and is readlly hard processing work. Instead when creating you always know in what state you've created those - so just keep the count of "Checked" checkboxes. When a checkbox being checked increment the count, and when one unchecked - take out 1 from the count. And later have a check: "if (count == requiredCount) {//Logic here}"
So the code will look like:
private int checkedCount;
private void check_CheckedChanged(Object sender, EventArgs e)
{
this.checkedCount += (sender as CheckBox).Checked?1:-1;
if(this.checkedCount == requiredCount)
{
//do stuff
}
}
Good luck with development.

Categories

Resources