i'm making a workbook creator in C#.net ( using visual studio )
the book is build from the text part and the question part.
all the answers for the question are inside the text and the user need to click on the right answer. if he's right then the word become green and if he's wrong it become red.
i'm creating the clickeable text with LINKBUTTON, i gave the link button CssStyle class and after the user clicking the word i want to change the class for this link to a different class.
this is the code i using for creating the linksbutton:
public void createQusetion(Panel lefttext, Panel question, string text, string
questionText, string answer)
{
string[] Qbuttonstext = text.Split(' ');
_numberWords = Qbuttonstext.Length;
for (int i = 0; i < _numberWords; i++)
{
LinkButton answerButton = new LinkButton();
if (Qbuttonstext[i] == answer)
{
answerButton.ID = "answer" + i;
}
else
{
answerButton.ID = "word" + i.ToString();
}
answerButton.Text = Qbuttonstext[i].ToString() + " ";
answerButton.CssClass = "textbuttonB4";
answerButton.Click += new EventHandler(checkAnswer);
lefttext.Controls.Add(answerButton);
}
}
and for the checking the question:
private void checkAnswer(object sender, System.EventArgs e)
{
for (int i = 0; i < _numberWords; i++)
{
if (((Control)sender).ID.ToString() != null)
{
if (((Control)sender).ID.ToString() == "answer" + i.ToString())
{
((Control)sender).CssClass = "textbuttonRight";
}
else
{
((Control)sender).CssClass = "textbuttonwrong";
}
}
}
}
the VS2010 giving me misatake for the : ((Control)sender).CssClass .
what is the right way?
You can do a type-independent control this way. It will run for all controls have Id and CssClass Properties.
private void checkAnswer(object sender, System.EventArgs e)
{
var cssClass = sender.GetType().GetProperty("CssClass");
var id = sender.GetType().GetProperty("ID").GetValue(sender, null);
for (int i = 0; i < _numberWords; i++)
{
if (id!=null)
{
if (id.ToString() == "answer" + i.ToString())
{
cssClass.SetValue(sender, "textbuttonRight", null);
}
else
{
cssClass.SetValue(sender, "textbuttonRight", null);
}
}
}
}
Related
I am trying to create a TextBox based on the selection on ComboBox dynamically based on the following steps:
First step (Select a source from ComboBox):
Second step (Textbox should appear based on ComboBox.SelectedValue):
Last step (A new ComboBox should appear below):
I have created a createTextBox function using the following code:
public void createTextBox(int numPassenger)
{
TextBox[] passengerBoxes = new TextBox[numPassenger];
for (int u = 0; u < passengerBoxes.Count(); u++)
{
passengerBoxes[u] = new TextBox();
}
int i = 0;
foreach (TextBox txt in passengerBoxes)
{
string name = "passenger" + i.ToString();
txt.Name = name;
txt.Text = name;
txt.Location = new Point(244, 32 + (i * 28));
txt.Visible = true;
this.Controls.Add(txt);
i++;
}
}
Is there a way that I can modify my current function to adapt to the mentioned steps? Additionally, how can I find the dynamically created TextBox?
You can try the following code:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
createTextBox(sender as ComboBox);
}
private void createTextBox(ComboBox cmb)
{
TextBox passengerBoxes = new TextBox();
string name = cmb.Text;
if (Controls.Find(name, true).Length == 0)
{
passengerBoxes.Name = name;
passengerBoxes.Text = name;
int textBoxCount = GetTextBoxCount();
passengerBoxes.Location = new Point(244, 32 + (textBoxCount * 28));
passengerBoxes.Visible = true;
this.Controls.Add(passengerBoxes);
if (cmb.Items.Count != 1)//last item remaining then we should not create new combo box
{
ComboBox newCombo = new ComboBox
{
Location = new Point(cmb.Location.X, 32 + ((textBoxCount + 1) * 28))
};
foreach (string str in cmb.Items)
if (cmb.Text != str)
newCombo.Items.Add(str);
newCombo.SelectedIndexChanged += comboBox1_SelectedIndexChanged;
this.Controls.Add(newCombo);
}
}
else
MessageBox.Show("Textbox Already for the selected source " + name);
}
private int GetTextBoxCount()
{
int i = 0;
foreach (Control ctl in this.Controls)
{
if (ctl is TextBox) i++;
}
return i;
}
I want to change the background of some labels depending on what is written on a text file:
private void Form3_Load(object sender, EventArgs e)
{
string[] words = new string[7];
StreamReader read = new StreamReader(path);
while(!read.EndOfStream)
{
string line = read.ReadLine();
words = line.Split(';');
if(words[6] == "no")
{
//-----What I have to write here---
}
}
read.Close();
}
There are over 50 labels named "lbl101","lbl102","....","lbl150"
try it:
if(words[6] == "no")
{
int count = 150;
for (int a = 1 ; a < count; a++)
{
Label currentLabel = (Label)this.Controls.Find("lbl"+a,true)[0];
//change color of currentLabel
}
}
There's the working solution:
private void Form3_Load(object sender, EventArgs e)
{
int count = 101;
string[] words = new string[7];
StreamReader read = new StreamReader(pathRooms);
while(!read.EndOfStream)
{
string line = read.ReadLine();
words = line.Split(';');
if (words[6] == "no")
{
Label currentLabel = (Label)this.Controls.Find("lbl" + count, true)[0];
currentLabel.BackColor = Color.Yellow;
}
count = count + 1;
}
read.Close();
}
You can iterate all over them using OfType<T>() method on Controls collection of form like:
if(words[6] == "no")
{
foreach(var label in this.Controls.OfType<Label>().Where(x=>x.Name.Contains("lbl")))
{
label.Text = "Some Text";
}
}
This will only work on the labels that are direct child of form, labels nested inside other user controls or nested panels will not be affected, for that you have to do it recursively.
Loop through the Controls collection of the form checking for Label objects. Then, amend accordingly as per the specified value.
1.) Create a List with all the labels.
Label lbl101 = new Label();
Label lbl102 = new Label();
...
List<Label> labels = new List<Label>()
{
lbl101,
lbl102
...
};
2.) If your words[] string is the name of the color you can write:
if(words[6] == "no")
{
System.Drawing.Color myColor = System.Drawing.ColorTranslator.FromHtml(words[..]);
foreach(Label l in Labels)
{
l.BackColor = myColor;
}
}
So I have a button, where if you click it, it adds "Candy" to a listbox, how do I make it so, if another item with the same name is being added, instead of adding it in a new line, update the first line to show x2, 3, 4, etc. Is that possible or would I have to make another Listbox and match the index? I've tried the following with another listbox and an int variable.
private void btnCandy_Click(object sender, EventArgs e)
{
lstProducts.Items.Add("Candy");
foreach (var item in lstProducts.Items)
{
if (item.ToString() == "Candy")
{
++Productcount;
lstQuantity.Items.Add(Productcount);
if (Productcount > 1)
{
lstQuantity.Items.Insert(lstProducts.Items.IndexOf("Candy"), Productcount);
}
}
}
}
using System.Text.RegularExpressions;
Use:
private void btnCandy_Click(object sender, EventArgs e)
{
string query = "Candy";
bool isExist = false;
for (int i = 0; i < lstProducts.Items.Count; i++)
{
var s = lstProducts.Items[i].ToString();
if (s.StartsWith(query))
{
if (s == query)
{
lstProducts.Items[i] = query + "x2";
isExist = true;
break;
}
else
{
// Escape your plain text before use with regex
var pattern = Regex.Escape(query);
// Check if s has this formnat: queryx2, queryx3, queryx4, ...
Match m = Regex.Match(s, "^" + pattern + #"x(\d+)$");
if (m.Success)
{
lstProducts.Items[i] = query + "x" + (Int32.Parse(m.Groups[1].Value) + 1);
isExist = true;
break;
}
}
}
}
if (!isExist) lstProducts.Items.Add(query);
}
Note:
\d mean any digit (0 - 9)
I'd try to iterate through listbox items and if I find "Candy" then take that index and update title.
private void btnCandy_Click(object sender, EventArgs e)
{
bool found = false;
foreach (var item in lstProducts.Items)
{
if (item.ToString().StartsWith("Candy"))
{
// update item title
found = true;
break; // no need to continue
}
}
if(!found)
{
lstProducts.Items.Add("Candy");
}
}
this way you are not going to add duplicates
Here is some pseudo-code to help you. Add this to your button click event:
int i = 0;
foreach (string item in listbox1.Items)
{
If (item == textbox1.text) //textbox1.text contains the string such as 'candy'
{
i++;
listbox1.Items.Remove(item);
listbox1.Items.Add(textbox1.text + " " + i.ToString());
}
}
You may have to reset the counter as needed.
I have a combobox filed with the name of dataGridView columns, can I change the text of displayed items in the comboBox to any text I want ?
for (int i = 0; i < dataGridView1.Columns.Count; i++)
{
if (dataGridView1.Columns[i].ValueType == typeof(string) &&
i != 6 &&
i != 7 &&
i != 8 &&
i != 9)
comboBox1.Items.Add(dataGridView1.Columns[i].Name);
}
comboBox1.SelectedIndex = 0;
I hope this helps you:
combobox.Items[combobox.FindStringExact("string value")] = "new string value";
The FindStringExact method returns the index of an specific item text, so this can be a better way to change the text of a Combobox item.
Note: This works fine on C#.
If the value you want to use is not suitable as the text in a combobox, I usually do something like this:
public class ComboBoxItem<T> {
public string FriendlyName { get; set; }
public T Value { get; set; }
public ComboBoxItem(string friendlyName, T value) {
FriendlyName = friendlyName;
Value = value;
}
public override string ToString() {
return FriendlyName;
}
};
// ...
List<ComboBoxItem<int>> comboBoxItems = new List<ComboBoxItem<int>>();
for (int i = 0; i < 10; i++) {
comboBoxItems.Add(new ComboBoxItem<int>("Item " + i.ToString(), i));
}
_comboBox.DisplayMember = "FriendlyName";
_comboBox.ValueMember = "Value";
_comboBox.DataSource = comboBoxItems;
_comboBox.SelectionChangeCommitted += (object sender, EventArgs e) => {
Console.WriteLine("Selected Text:" + _comboBox.SelectedText);
Console.WriteLine("Selected Value:" + _comboBox.SelectedValue.ToString());
};
Try this:
ListItem item = comboBox1.Items.FindByText("<Text>");
if (item != null)
{
item.Text = "<New Text>";
}
May be instead of changing the text it would be simple to remove the item from a particular index and insert new item at same index with new text
You can simply change combo box items text by :
my_combo.Items [i_index] = "some string";
The best way you can do that is in this way:
ui->myComboBox->setItemText(index,"your text");
I have a CheckedListBox that has X number of items. These items are placed there at runtime. These items are supposed to represent reports that can be displayed in the DataGridView. What I need to do now is display the record count for each report in parenthesis right next to the report name. I tried, not for too long, to edit the actual name of the item but couldn't find out how to do it. So then, I brute forced it. Saved the items to an array, cleared the items, appended the record counts to each item in the array, created new items. Well, this has caused issues because now it's not retaining my checks and the reason why is because whenever I generate the reports, I clear the items and recreate them. Well, rather than doing another foreach loop to save the checked status, does anyone know of a way to change the text of existing items in a CheckedListBox?
Here is the code I currently have:
In the MainForm.Designer.cs:
this.clbReports.Items.AddRange(new object[] {
"Report 1",
"Report 2",
"Report 3",
"Report 4",
"Report 5",
"Report 6",
"Report 7",
"Report 8",
"Report 9",
"Report 10",
"Report 11"});
And it looks like:
And I want it to look like (but there won't all be 0's):
Here is the SelectedIndexChanged function:
private void clbReports_SelectedIndexChanged(object sender, EventArgs e)
{
string strCheckBox = clbReports.SelectedItem.ToString();
bool bShowAllIsChecked = clbReports.GetItemChecked(clbReports.FindString("Show All Error Reports"));
bool bSelected = clbReports.GetItemChecked(clbReports.FindString(strCheckBox));
int nIndex = -1;
if (strCheckBox.Contains("Show All Error Reports"))
{
foreach (string str in _strReports)
{
if (!str.Contains("Show All Error Reports") && !str.Contains("Show Tagged Records"))
{
nIndex = clbReports.FindString(str);
if (nIndex > -1)
{
clbReports.SetItemChecked(nIndex, bSelected);
}
}
}
}
else
{
if (strCheckBox.Contains("Show All Error Reports") || bShowAllIsChecked)
{
foreach (string str in _strReports)
{
nIndex = clbReports.FindString(str);
if (nIndex > -1)
{
clbReports.SetItemChecked(nIndex, false);
}
}
}
nIndex = clbReports.FindString(strCheckBox);
if (nIndex > -1)
{
clbReports.SetItemChecked(nIndex, bShowAllIsChecked ? true : bSelected);
}
}
string[] strCheckedItems = new string[clbReports.CheckedItems.Count];
clbReports.CheckedItems.CopyTo(strCheckedItems, 0);
List<string> checkBoxReportFilter = new List<string>();
foreach (ReportRecord obj in this._lstReportRecords)
{
foreach (string str in strCheckedItems)
{
if (str.Contains(obj.Description))
{
checkBoxReportFilter.Add(obj.PartID.ToString());
}
}
}
try
{
if (checkBoxReportFilter.Count == 0 && clbReports.CheckedItems.Count > 0)
{
throw new NullReferenceException();
}
_strReportFilter = String.Join(",", checkBoxReportFilter.ToArray());
}
catch (NullReferenceException)
{
_strReportFilter = "-1";
}
generateReport();
}
And here is the code where I am clearing the items, getting the report counts and creating the new items.
_lstReportRecords = _dataController.ReportList;
bool[] bChecked = new bool[clbReports.Items.Count];
int nCounter = 0;
foreach (string str in _strReports)
{
foreach (string str2 in clbReports.SelectedItems)
{
bChecked[nCounter] = str2.Contains(str);
}
nCounter++;
}
clbReports.Items.Clear();
nCounter = 0;
foreach (string str in _strReports)
{
int nCount = _lstReportRecords.Where<ReportRecord>(delegate(ReportRecord rr) {
return rr.Description == str;
}).Count();
string newReport = str + " (" + nCount + ")";
clbReports.Items.Add(newReport);
clbReports.SetItemChecked(nCounter, bChecked[nCounter]);
nCounter++;
}
Please tell me there is an easier way to do this. I tried doing foreach loops through the clbReports.Items but it wants me to cast it to a string (errored on me when trying to cast to a CheckBox) so I couldn't change the value. And even if I could cast it to a CheckBox, I have a feeling it will give me the error that Enumeration has failed because the list has been changed (or however they word it). Any and all help is welcome. Thanks.
Edit: Please know that the Report X are just so that the actual report names aren't displayed to keep it generic. However, in the code, I just copied and pasted so the Show All Error Reports and Show All Tagged Records are reports I need to check.
The right ( == most simple and most direct) answer and solution is:
this.clbReports.Items[nIndex] = "new text of the item"
yes, those items are of type "object". No, nobody minds that, string is an object too ;)
If I were you, I'd try to give the INotifyPropertyChanged Interface a go.
You Shouldn't mess with events unless necessary. this will mean you can't use the designer to create the items, but as far as I've understood, it's a runtime-modified list anyway...
In detail:
• Create A Class (e.g.'Foo') that Implements INotifyPropertyChanged (Basically this will tell any listener that the text property has changed). This class will hold the names of all entries.
• create an ObservableCollection and bind your CheckedListBox to that Collection. In WinForms you will have to create a DataBindingSource and plug your Collection to one end and the ComboBox to the other end.
• Any change made to the collection will be visible in the control.
HTH
Sebi
In order to change the items in a ListBox (or a CheckedListBox), you should change these items' ToString() result.
The easiest solution would be to create a "Holder" class, which has a reference to the report it represents. Then the Holder class' ToString() method should be something like this:
public override string ToString()
{
return String.Format("{0} ({1})", BaseStr, MyReport.RecordCount);
}
If you change MyReport.RecordCount somehow (because a report's record count changes), you can just call clbReports.Refresh(), and it'll automatically show the new value.
I think this way you don't even need the temporary array solution in the second code block; however, I'd like to suggest an alternative way of getting the item's checked state.
You can iterate through the clbReports.CheckedIndices, and fill your bChecked array with true values only for indices in that array.
Well, due to time constraints I tried something else. I went with a ListView where CheckBoxes = true and View = List. I also removed Show All Error Reports and Show Tagged Records to checkboxes outside of the list. This made it a lot easier to do the functions I wanted. Here is the new code.
MainForm.Designer.cs
//
// cbTaggedRecords
//
this.cbTaggedRecords.AutoSize = true;
this.cbTaggedRecords.Location = new System.Drawing.Point(151, 9);
this.cbTaggedRecords.Name = "cbTaggedRecords";
this.cbTaggedRecords.Size = new System.Drawing.Size(106, 17);
this.cbTaggedRecords.TabIndex = 3;
this.cbTaggedRecords.Text = "Tagged Records";
this.cbTaggedRecords.UseVisualStyleBackColor = true;
this.cbTaggedRecords.CheckedChanged += new System.EventHandler(this.ShowTaggedRecords_CheckChanged);
//
// cbAllErrorReports
//
this.cbAllErrorReports.AutoSize = true;
this.cbAllErrorReports.Location = new System.Drawing.Point(6, 9);
this.cbAllErrorReports.Name = "cbAllErrorReports";
this.cbAllErrorReports.Size = new System.Drawing.Size(102, 17);
this.cbAllErrorReports.TabIndex = 2;
this.cbAllErrorReports.Text = "All Error Reports";
this.cbAllErrorReports.UseVisualStyleBackColor = true;
this.cbAllErrorReports.CheckedChanged += new System.EventHandler(this.ShowAllErrorReports_CheckChanged);
//
// listView1
//
this.listView1.CheckBoxes = true;
listViewItem1.StateImageIndex = 0;
listViewItem2.StateImageIndex = 0;
listViewItem3.StateImageIndex = 0;
listViewItem4.StateImageIndex = 0;
listViewItem5.StateImageIndex = 0;
listViewItem6.StateImageIndex = 0;
listViewItem7.StateImageIndex = 0;
listViewItem8.StateImageIndex = 0;
listViewItem9.StateImageIndex = 0;
this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
listViewItem1,
listViewItem2,
listViewItem3,
listViewItem4,
listViewItem5,
listViewItem6,
listViewItem7,
listViewItem8,
listViewItem9});
this.listView1.Location = new System.Drawing.Point(6, 29);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(281, 295);
this.listView1.TabIndex = 1;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.List;
this.listView1.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.listView_ItemChecked);
MainForm.cs
private void listView_ItemChecked(object sender, ItemCheckedEventArgs e)
{
if (e != null)
{
int nLength = e.Item.Text.IndexOf("(") - 1;
string strReport = nLength <= 0 ? e.Item.Text : e.Item.Text.Substring(0, nLength);
if (e.Item.Checked)
{
_lstReportFilter.Add(strReport);
}
else
{
_lstReportFilter.Remove(strReport);
}
}
List<string> checkBoxReportFilter = new List<string>();
foreach (ReportRecord obj in this._lstReportRecords)
{
foreach (string str in _lstReportFilter)
{
if (str.ToLower().Contains(obj.Description.ToLower()))
{
checkBoxReportFilter.Add(obj.PartID.ToString());
}
}
}
try
{
if (checkBoxReportFilter.Count == 0 && listView1.CheckedItems.Count > 0)
{
throw new NullReferenceException();
}
_strReportFilter = String.Join(",", checkBoxReportFilter.ToArray());
}
catch (NullReferenceException)
{
_strReportFilter = "-1";
}
if (!bShowAll)
{
generateReport();
}
}
private void ShowAllErrorReports_CheckChanged(object sender, EventArgs e)
{
bShowAll = true;
foreach (ListViewItem lvi in listView1.Items)
{
lvi.Checked = ((CheckBox)sender).Checked;
}
_lstReportFilter.Clear();
bShowAll = false;
generateReport();
}
private void ShowTaggedRecords_CheckChanged(object sender, EventArgs e)
{
bool bChecked = ((CheckBox)sender).Checked;
if (bChecked)
{
if (!_lstReportFilter.Contains("Show Tagged Records"))
{
_lstReportFilter.Add("Show Tagged Records");
}
}
else
{
_lstReportFilter.Remove("Show Tagged Records");
}
listView_ItemChecked(null, null);
}
Code to add counts to CheckBoxes
_lstReportRecords = _dataController.ReportList;
int nTotalCount = 0;
foreach (ListViewItem lvi in listView1.Items)
{
int nCount = _lstReportRecords.Where(rr => lvi.Text.Contains(rr.Description)).Count();
nTotalCount += nCount;
lvi.Text = (lvi.Text.Contains("(") ? lvi.Text.Substring(0, lvi.Text.IndexOf("(") + 1) : lvi.Text + " (") + nCount.ToString() + ")";
}
cbAllErrorReports.Text = (cbAllErrorReports.Text.Contains("(") ? cbAllErrorReports.Text.Substring(0, cbAllErrorReports.Text.IndexOf("(") + 1) : cbAllErrorReports.Text + " (") + nTotalCount.ToString() + ")";
int nTaggedCount = _lstReportRecords.Where(rr => rr.Description.Contains("Tagged")).Count();
cbTaggedRecords.Text = (cbTaggedRecords.Text.Contains("(") ? cbTaggedRecords.Text.Substring(0, cbTaggedRecords.Text.IndexOf("(") + 1) : cbTaggedRecords.Text + " (") + nTaggedCount.ToString() + ")";
Thank you all for your help and ideas.