The problem is faced under c# .NET, Visual Studio, Windows Form Application
I have a bunch of checkboxes placed randomly in one form and in one panel.
So, If any checkbox is selected in the form its value is supposed to be added up.
Bottomline: Instead of using plenty of "If-else loops", to evaluate whether its been checked or not. I wanna simplify it using a "for loop ".
Is there any Checkbox group name type feature, which I can use???
I wanna code something like this:
for(int i=0;i<checkboxes.length;i++)
{
string str;
if(chkbox.checked)
{
str+=chkbox.value;
}
}
Where checkboxes is a group name.
You can use a simple LINQ query
var checked_boxes = yourControl.Controls.OfType<CheckBox>().Where(c => c.Checked);
where yourControl is the control containing your checkboxes.
checked_boxes is now an object which implements IEnumerable<CheckBox> that represents the query. Usually you want to iterate over this query with an foreach loop:
foreach(CheckBox cbx in checked_boxes)
{
}
You also can convert this query to a list (List<Checkbox>) by calling .ToList(), either on checked_boxes or directly after the Where(...).
Since you want to concatenate the Text of the checkboxes to a single string, you could use String.Join.
var checked_texts = yourControl.Controls.OfType<CheckBox>()
.Where(c => c.Checked)
.OrderBy(c => c.Text)
.Select(c => c.Text);
var allCheckedAsString = String.Join("", checked_texts);
I also added an OrderBy clause to ensure the checkboxes are sorted by their Text.
CheckBox[] box = new CheckBox[4];
box[0] = checkBox1;
box[1] = checkBox2;
box[2] = checkBox3;
box[3] = checkBox4;
for(int i=0; i<box.length; i++)
{
string str;
if(box[i].checked== true)
{
str += i.value;
}
}
I think this code will work with DotNet4.0. Plz let me know any error occurs. Treat 'box' as regular array.
If all the checkboxes are in a groupbox you can do this:
foreach(Control c in myGroupBox.Controls)
{
if (c is CheckBox)
{
//do something
CheckBox temp = (CheckBox)c;
if(temp.Checked)
//its checked
}
}
Subscribe all checkboxes to one CheckedChanged event handler and build your string when any checkbox checked or unchecked. Following query will build string, containing names of all Form's checked checkboxes:
private void Checkbox_CheckedChanged(object sender, EventArgs e)
{
// this will use all checkboxes on Form
string str = Controls.OfType<CheckBox>()
.Where(ch => ch.Checked)
.Aggregate(new StringBuilder(),
(sb, ch) => sb.Append(ch.Name),
sb => sb.ToString());
// use string
}
I suppose other than subscribing to event CheckedChanged there is no alternative even if it is contained in some panel or form, You have to use if else,
if it would have been web base eg asp.net or php we could use jquery because it gives us the option to loop through each particular event using .each and getting its value
Related
I have a wpf app with 20 Checkboxes.
Is there a function to Safe the number of the checkboxes which are checked in a variable.
If there is an other possibility to use the number without saving it in a variable first, that would help me too.
Thanks!
There's nothing built-in, but a loop or Linq query shouldn't be too hard. If you want all checkboxes on the form, you could just do
int count = 0;
for (var control in parent.Children)
{
if (control is CheckBox && ((CheckBox)control).IsChecked)
{
count++;
}
}
or
int count = parent.Children.OfType<CheckBox>()
.Where(cb => cb.IsChecked)
.Count();
If you have move specific conditions (e.f. checkboxes that have a specific name pattern), then just add that to the if or Where clause.
When I run my form, I just want to get the names of all the text boxes of the active form at run time in a label.
I searched a lot but all I found was something in which they haven't changed the names of text boxes.
var allTexboxes = this.Controls.OfType<TextBox>();
var sortedTextBoxes = allTexboxes
.Where(i => String.IsNullOrEmpty(i.Text))
.OrderBy(i => i.Name)
.ToArray();
Your code example and explanation of what you want is confusing. If you want an array of all textbox names within a form:
string[] GetTexBoxNames()
{
var names =new List<string>();
for each(var c in this.Controls)
{
if(c is TextBox)
{
names.Add(c.name);
}
}
return names.ToArray();
}
The phrase "this" is referring to the form. If you want to do this calculation from oitside the form, replace that keyword with a variable referencing it.
You can also use a lamda expression to get all textbox in an arrayin a single expression..
var textBoxNames = this.Controls
.Where(i => i is TextBox)
.ToArray();
Another thing you might want is a dictionary of all TextBoxes, with their names as the keys. You don't need this unless lookup speed is critical, because you can use a lamda to lookup a textbox in the final array which is slower than a dictionary lookup. You can use a simple for loop to go over every textbox and let them in a dictionary by name.
You probably can edit this code to suit your purpose if I got you wrong. Please clarify and I will update this answer as well.
I have 16 text boxes in my Form whose names are suffixed sequentially from 1 to 16 respectively.
i.e. The 16 test boxes are names TextBox1, 'TextBox2, .... all the way until the 16th one, which is namedTextBox16`.
I would like to read the contents of these 16 text boxes in a loop and modify the ith TextBox's contents or properties based on a certain condition.
How do I do this?
If you use WinForms, easiest way is to store text boxes references in array, in constructor of window:
TextBox[] data = new TextBox[16]{textBox1,textBox2, [...],textBox16};
then you can use for loop to access them.
You can try something like this:
Dictionary<string, string> yourValues = new Dictionary<string, string>();
foreach (Control x in this.Controls)
{
if (x is TextBox)
{
yourValues.Add(((TextBox)x).Name, ((TextBox)x).Text);
}
}
NOTE: On your future question please provide more information and make your question more clear.
i would try to find and modify using Linq:
using System.Linq;
//...
int x = 5; //number of textbox to search
var textbox = this.Controls.OfType<TextBox>().Single(tb => tb.Name.EndsWith(x.ToString()));
textbox.Text = "abc";
In case you have to loop thru all the texboxes in form, you can do something like this:
List<TextBox> textboxes = this.Controls.OfType<TextBox>().ToList();
foreach (TextBox box in textboxes)
{
box.Text = "something";
}
Easiest way according to what you specified is to use Linq.
Let's assume you have 3 TextBoxes :
// 1st -> which is named meTextBox1
// 2nd -> which is named meTextBox2
// 3rd -> which is named meTextBox3
As you can see from above every line differs only by the number ( index .. call it whatever you want ).
Now you can make your base "query" which would look like :
const string TB_NAME = "meTextBox{0}";
And as you can presume right now this will be used inside of string.Format method. Now to retrieve desired TextBox all you have to do is to make Linq statement :
string boxName = string.Format(TB_NAME, 7); // retrieve 7th text box
TextBox tBox = Controls.OfType<TextBox>().FirstOrDefault(tb => tb.Name == boxName);
This example does not consider nested Controls but you can make do this recursively which will retrieve nested Controls:
TextBox ByIndex(int idx, Control parent)
{
TextBox result = null;
string searchFor = string.Format(TB_NAME, idx);
foreach(Control ctrl in parent.Controls)
{
if(!(ctrl is TextBox) && ctrl.HasChildren)
{
result = ByIndex(idx, ctrl);
if( result != null)
break;
}
else if(ctrl is TextBox)
{
if(ctrl.Name = searchFor)
{
result = ctrl as TextBox;
break;
}
}
}
return result;
}
To use above method you can just call it like such :
public class MeForm : Form
{
//.. your code here ..
void meImaginaryMethodToRetrieveTextBox()
{
int meRandomIndex = 7;
TextBox tb = ByIndex(meRandomIndex, this);
// rest of the code...
}
}
Sorry if it has some obvious solution, but I am trying to solve it for hours but could not find a solution.
I use several ComboBoxes in my WindowsFormsApplication to relate ids with names. The problem is that when a user select an item from the combobox list, it works fine, but when he types an item, the SelectedValue property of the combobox is null.
To simulate the problem, I created a from with one button and a combobox.
In my actual application, I populate the comboboxes with data from tables in a sqlserver database, but for simplicity, here I populate it with a list:
public Form1()
{
InitializeComponent();
List<KeyValuePair<short,short>> l = new List<KeyValuePair<short,short>>();
l.Add(new KeyValuePair<short,short>(1,10));
l.Add(new KeyValuePair<short,short>(2,20));
l.Add(new KeyValuePair<short,short>(3,30));
this.comboBox1.DataSource = l;
this.comboBox1.DisplayMember = "Value";
this.comboBox1.ValueMember = "Key";
}
private void button1_Click(object sender, EventArgs e)
{
if (this.comboBox1.SelectedValue == null)
MessageBox.Show("NULL");
else
MessageBox.Show(this.comboBox1.SelectedValue.ToString());
}
For example, when user select the second item (20) from the list and clicks on the button, messagebox shows 2 as it is expected, but if he types the number 20 into the combobox, the SelectedValue is null.
This problem could be solved by changing the style of combobox:
this.comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
But it prevents user to type into the combobox, so I am forced to use the default ComboBoxStyle.DropDown.
Thats because the combo box does not select the item that you have typed. Add this option
comboBox1.AutoCompleteMode = AutoCompleteMode.Suggest;
Then it will select the item when ever it was able to find it.
By default it is set to AutoCompleteMode.None.
(I think) This is mainly designed for suggestions but it can solve your problem here. also if you want to show the suggestions:
comboBox1.AutoCompleteSource = AutoCompleteSource.ListItems;
by default it is set to AutoCompleteSource.None.
https://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.autocompletemode%28v=vs.110%29.aspx
An option that you have is using the EventHandler on the comboBox1.TextChange event that will allow you to personally handle how the text is translated into the different options.
This can be added to the designer (similar to a button).
this.comboBox1.TextChanged += new System.EventHandler(this.UpdateValue);
Then depending on how want to read the results and see if you have a match you can create a converter, use another key/value, or you can do a boring old tryparse as I will show you. You will need the list as a property that you can reference to see if you have found the proper results.
private void UpdateValue(object sender, EventArgs e)
{
short result;
if (short.TryParse(comboBox1.Text, out result))
{
var matches = from val in l where val.Value == result select val.Key;
{
foreach (short m in matches)
this.comboBox1.SelectedValue = m;
}
}
}
Good luck! Let me know if you need more examples with the event handler. Don't forget to vote.
I'm wondering how you can set the selected element of a gridviewcomboboxcolumn.
As a bit of a foreword: I'm using the column with autocomplete mode in order to
have autocomplete functionality, but I also want to add new elements to the list.
It worked so far without a hitch EXCEPT for one situation:
I already have:
T1
T12
T123
In the data source.
Then when I have for example T12 selected and do backspace to select T1
I've got the problem that I need to manually click on T1 in the list AS there is no selection of T1 as there are multiple possibilities shown. Thus when I leave the editor mode without manually selecting T1 I get T12 as selected item.
I want to change this behaviour in such a way that the first found item is pre selected (always). (regardless if it is a new element or a changed to element so to say)
Currently I've already added a custom handler for the cellendedit to add the new value to the list:
private void MainFormGridView_CellEndEdit(object Sender, GridViewCellEventArgs eventArgs)
{
var virtualizedCurrentCell = ((Telerik.WinControls.UI.GridVirtualizedCellElement)(currentCell));
var currentGridviewComboBoxColumn = ((Telerik.WinControls.UI.GridViewComboBoxColumn)(virtualizedCurrentCell.Data));
if (((List<string>)currentGridviewComboBoxColumn.DataSource).IndexOf((string)currentCell.Value) > -1)
{
foundValueInList = true;
}
if (!foundValueInList)
{
((List<string>)currentGridviewComboBoxColumn.DataSource).Add((string)currentCell.Value);
}
}
The column itself is created in this way (bnefore being added to the gridview it is a part of:
GridViewComboBoxColumn newColumn;
newColumn = new GridViewComboBoxColumn();
((GridViewComboBoxColumn)newColumn).DataSource = (from c in entity.myOffer
orderby c.customer
where c.customer!= null
select c.customer)
.Distinct()
.ToList();
((GridViewComboBoxColumn)newColumn).DropDownStyle = Telerik.WinControls.RadDropDownStyle.DropDown;
((GridViewComboBoxColumn)newColumn).AutoCompleteMode = AutoCompleteMode.SuggestAppend;
newColumn.FieldName = "customer";
newColumn.Name = "customer";
newColumn.HeaderText = "Customer";
newColumn.TextAlignment = System.Drawing.ContentAlignment.MiddleCenter;
newColumn.Width = 100;
listOfColumns.Add(newColumn);
this.MainFormGridView.Columns.Add(newColumn);
So the question is there what can I do to select specific items in the dropdownlist AND is the CellEndEdit the correct location for that (as I suspect)?
A possible solution for the problem itself is to forego the usage of the GridViewComboboxcColumn to get a field with autocomplete and instead use a "normal" GridViewTextBoxColumn.
In addition to this change we will need an customized editor which brings in the autocomplete element. One thing of note here is that the height of the cell changes slightly leading to chars being chopped off a bit if you don't have the setting active that rows can grow in size automatically (thus if that is not the case, then you need to increase the row height to at least 30:
Example of how to do this in this case: MainFormGridView.TableElement.RowHeight = 30; )
The creation code for the textbox with autocomplete now changes to the following:
GridViewTextBoxColumn newColumn;
newColumn = new GridViewTextBoxColumn();
newColumn.FieldName = "customer";
newColumn.Name = "customer";
newColumn.HeaderText = "Customer";
newColumn.TextAlignment = System.Drawing.ContentAlignment.MiddleCenter;
newColumn.Width = 100;
this.MainFormGridView.Columns.Add(newColumn);
Like I mentioned before we now need a custom editor for the autocomplete box itself:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Telerik.WinControls.UI;
namespace MyProject
{
class customAutoCompleteBox : RadTextBoxControlEditor
{
protected override Telerik.WinControls.RadElement CreateEditorElement()
{
return new RadAutoCompleteBoxElement();
}
public override void OnKeyDown(System.Windows.Forms.KeyEventArgs e)
{
RadAutoCompleteBoxElement element = this.EditorElement as RadAutoCompleteBoxElement;
if (element.IsAutoCompleteDropDownOpen)
{
return;
}
base.OnKeyDown(e);
}
}
}
Then after this is done we only need to do 2 more steps to get the new autocomplete box to function:
1.) Setting the EditorRequired and CellEditorInitialized events
2.) Writing those events
For 1.) it is quite easy to do:
this.MainFormGridView.CellEditorInitialized += MainFormGridView_CellEditorInitialized;
this.MainFormGridView.EditorRequired += MainFormGridView_EditorRequired;
For 2.) the code here is also quite easy to do. Although I will put in a bit of a foreword here:
element.Delimiter can cause a few problems. Defaultwise one would use ' ' as delimiter there,
BUT if the data itself has many blanks inside that could raise an unexpected behaviour, as
each blank separated data part is seen as one "tag" or autocomplete element. Thus when the row is chosen you can get multiple tags displayed that you can delete one by one. In my case that was unwanted thus I did not use ' ' as separator but instead '\t' as the data does not have tabs inside.
Here is the code for CellEditorInitialized:
void MainFormGridView_CellEditorInitialized(object sender, GridViewCellEventArgs e)
{
if (e.ActiveEditor is customAutoCompleteBox)
{
customAutoCompleteBox editor = (customAutoCompleteBox)e.ActiveEditor;
RadAutoCompleteBoxElement element = (RadAutoCompleteBoxElement)editor.EditorElement;
element.Delimiter = '\t';
element.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
element.AutoCompleteDisplayMember = e.Column.Name;
element.AutoCompleteValueMember = e.Column.Name;
element.AutoCompleteDataSource = (from c in entity.myOffer
orderby c.customer
where c.customer!= null
select c.customer)
.Distinct()
.ToList();
}
}
And now for ViewCellFormatting
void MainFormGridView_EditorRequired(object sender, Telerik.WinControls.UI.EditorRequiredEventArgs e)
{
if (MainFormGridView.CurrentColumn.Name == "customer")
{
e.Editor = new customAutoCompleteBox();
}
}
With this an autocomplete is possible where the original problem does not occur. The only things not so nice here are that one has to press enter 2 times (after the first time the "tags" are shown from the row that was selected, and only the 2nd enter sets the tags. Same for using TAB to move out of the cell). Additionally the combobox is only shown after typing in a char and not already from the beginning.
In total, this solution functions but the behaviour (and appearance) of the autocompletebox is slightly different from the original combobox - autocomplete box.
Edit:
As it seems if you use the delimiter it adds the delimiter at the end, which can cause unwanted results (thus nothing found) if the autocomplete box is shown in an filter. A possible solution is using \0 as a delimiter so that nothing is added to the selected string from the autocomplete box.
Although this also makes it so that ALL chosen elements are treeated as being one single tag.