I have a Windows form on which I put a flow layout panel. I also have a class that reads a local database and returns the corresponding values. Depending on the user input via a button(s) the panel gets filled with other buttons. The amount of these buttons depends on the values in the local database. The buttons are displayed correctly and with the correct information, but the order in which they are displayed is alphabetical even though the data-table, from the database class, is ordered in the correct way (via the numerical value of the "ID" column from the database).
I have also added a data-grid view to check and there the items are displayed in the correct way. I have tried to add a for-each loop but that just seems to randomize the order of the buttons.
Does anybody know how I can get the buttons to be displayed in the correct way, so that the button with the lowest "ID" value gets displayed first.
Here is the code for displaying the buttons:
//set the datagridview with the correct values/names. Order works perfectly
dataGridView_AttackName.DataSource = db.attackIDName(attackCategory, taughtOn);
DataTable dt = db.attackIDName(attackCategory, taughtOn);
//sort datable again because doesnt work from db class
dt.DefaultView.Sort = "ID";
dt.DefaultView.ToTable();
int horizontal = 0;
int vertical = 0;
Button[] buttonArray = new Button[dt.Rows.Count];
for (int items = 0; items < buttonArray.Length; items++)
{
buttonArray[items] = new Button();
buttonArray[items].Size = new Size(150, 50);
buttonArray[items].Location = new Point(horizontal, vertical);
buttonArray[items].Name = string.Format("Button_{0}", dt.Rows[items]["ID"].ToString());
buttonArray[items].Text = dt.Rows[items]["Name"].ToString();
buttonArray[items].Click += btn_msg;
if ((items + 1) < buttonArray.Length)
{
vertical += 50;
}
flowLayoutPanel_AttackName.Controls.Add(buttonArray[items]);
}
//get the correct ID value from the button name and try to order it that way
foreach (Button b in flowLayoutPanel_AttackName.Controls)
{
string name = b.Name;
string subname = name.Substring(name.IndexOf("_") + 1);
int i = Convert.ToInt32(subname);
flowLayoutPanel_AttackName.Controls.SetChildIndex(b, i);
}
I have searched around on this site but couldn't find anything that worked.
You've correctly sorted the DefaultView by the ID, but then haven't used the results!
You need to replace, for example, dt.Rows[items]["Name"]with dt.DefaultView[items].Row["Name"]. You then don't need the statement dt.DefaultView.ToTable().
Full code is below:
dt.DefaultView.Sort = "ID";
int horizontal = 0;
int vertical = 0;
Button[] buttonArray = new Button[dt.Rows.Count];
for (int items = 0; items < buttonArray.Length; items++)
{
buttonArray[items] = new Button();
buttonArray[items].Size = new Size(150, 50);
buttonArray[items].Location = new Point(horizontal, vertical);
buttonArray[items].Name = string.Format("Button_{0}", dt.DefaultView[items].Row["ID"].ToString());
buttonArray[items].Text = dt.DefaultView[items].Row["Name"].ToString();
buttonArray[items].Click += btn_msg;
if ((items + 1) < buttonArray.Length)
{
vertical += 50;
}
flowLayoutPanel_AttackName.Controls.Add(buttonArray[items]);
}
Related
I create TextBoxes dynamically, one for each column in a table(DataGridView). Every time I select a row in Table a text Box should have the value of the primaryKey row. First time it works, but after that the TextBox Text is not changing. But if I put a MessageBox to print the textbox.Text it printed it right, but not displayed it. When I tried the same thing with textboxes that aren't created dynamically I didn't have this problem.
for (int i = 0; i < columns_number; i++)
{
textBoxes[i] = new TextBox();
labels[i] = new Label();
labels[i].Text = childTable.Columns[i].Name;
labels[i].Location = new Point(x_point - 100, y_point);
textBoxes[i].Location = new Point(x_point, y_point);
this.Controls.Add(labels[i]);
this.Controls.Add(textBoxes[i]);
y_point = y_point + 30;
}
textBoxes[number].Text = selectedRow.Cells[vaterPrimaryKey].Value.ToString();
textBoxes[number].Refresh();
Use the below code to find the textboxs and use them the way you want :
string textboxName = "textboxes" + number.ToString
TextBox mytextbox = this.Controls.Find(textboxName, true).FirstOrDefault() as TextBox;
mytextbox.Text = selectedRow.Cells[vaterPrimaryKey].Value.ToString();
I'm making a small project to answer questions. I have 2 questions:
How do I remove the answers dynamically?
How can I move the answers up and down i.e: reorganise them?
It will look something like this and when I click on the button ( which says "A..." on the image) it will delete the Radio button and text-box respectively.
Each item(radio-button, text-box, button) is in a list and I was thinking that a click on the button will remove the items from the lists, those that are in same position/index.
The way I add those items is like this (it might help).
if (contar < 10)
{
contar++;
radioButtons.Add(new MetroFramework.Controls.MetroRadioButton());
btnRmv.Add(new MetroFramework.Controls.MetroButton());
for (int i = 0; i < radioButtons.Count; i++)
{
Textboxes.Add(new MetroFramework.Controls.MetroTextBox());
Textboxes[i].Height = 20;
Textboxes[i].Width = 580;
Textboxes[i].Anchor = (System.Windows.Forms.AnchorStyles.Top);
Textboxes[i].Location = new System.Drawing.Point(txtPergunta.Location.X - 25, txtPergunta.Location.Y+txtPergunta.Height+ i * 25);
PanelCentro.Controls.Add(Textboxes[i]);
BtnAdd.Location = new System.Drawing.Point(BtnAdd.Location.X, Textboxes[i].Location.Y + 25);
radioButtons[i].Anchor = (System.Windows.Forms.AnchorStyles.Top);
radioButtons[i].Location = new System.Drawing.Point(Textboxes[i].Location.X - 20, Textboxes[i].Location.Y);
PanelCentro.Controls.Add(radioButtons[i]);
btnRmv[i].Height = 20;
btnRmv[i].Width = 20;
btnRmv[i].Anchor = (System.Windows.Forms.AnchorStyles.Top);
btnRmv[i].Text = "delete";
btnRmv[i].Location = new System.Drawing.Point(Textboxes[i].Location.X + Textboxes[i].Width + 20, Textboxes[i].Location.Y);
PanelCentro.Controls.Add(btnRmv[i]);
btnRmv[i].Click += RemoverResposta;
}
}
I was using a for loop to delete the items but it never deleted the correct items (i.e: the items in the same position of the button I clicked), it deleted all.
I am attempting to dynamically create a bar chart in C# based on the following datatable (which will change, hence the need for dynamic creation).
Here's the datatables that I'm reading from currently:
(people of the future: these images contained work stuff and I don't want to get fired, so I've removed them =O )
The top table is where I add the series (s24, s26, s27) data. The second table is where I slim it down and add the "Total" series.
So here are the columns that I'm trying to chart from:
Config - this is where I want to get my individual series: ie: s24, s26, s27, etc.
HRC_Count - this is the actual value I'm trying to graph
HRC_Description and HRC - these are labels for the Y axis
Total_HRC_Count - this is for my "Total" series (black bar on chart)
//get distinct Configs (to be added as Series in chart)
//this creates a dataview to parse for the series in the chart
DataView view = new DataView(dt);
DataTable distinctValues = new DataTable();
distinctValues = view.ToTable(true, "Config");
DataView dv = new DataView(distinctValues);
dv.Sort = "Config ASC";
DataTable dt_temp = new DataTable();
dt_temp = dv.ToTable();
distinctValues = dt_temp;
GraphDataNew(distinctValues);
then I call GraphDataNew and parse the dataview for the series:
private void GraphDataNew(DataTable dt_distinct)
{
chart_new.Series.Clear();
foreach (DataRow row in dt_distinct.Rows)
{
string s = row["Config"].ToString();
chart_new.Series.Add(s);
chart_new.Series[s].ChartType = SeriesChartType.Bar;
chart_new.Series[s].IsValueShownAsLabel = true;
chart_new.Series[s].Sort(PointSortOrder.Ascending, "X");
chart_new.Series[s].XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
chart_new.Series[s].YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
}
So now I have my Series (Configs) set up, now I add actual data:
DataView dv = new DataView(dt);
dv.Sort = "HRC_Description ASC, Config ASC"; // sort by description first, then config second
string HRC_Description = "";
string Config = "";
double HRC_Count = 0;
DataTable dt_temp = new DataTable();
dt_temp = dv.ToTable();
// add actual data
//loop through dt_temp and add datapoints and custom labels to chart
for (int x = 0; x < dt_temp.Rows.Count; x++)
{
HRC_Description = (dt_temp.Rows[x]["HRC_Description"].ToString().Trim());
Config = dt_temp.Rows[x]["Config"].ToString().Trim();
HRC_Count = Double.Parse(dt_temp.Rows[x]["HRC_Count"].ToString().Trim());
chart_new.Series[Config].Points.AddXY(HRC_Description, HRC_Count);
int y = chart_new.Series[Config].Points.Count;
chart_new.Series[Config].Points[y - 1].AxisLabel = HRC_Description;
}
Then I add the "Total" series bar:
if (1==1) // fake condition for this question
{
chart_new.Series.Add("Total");
chart_new.Series["Total"].ChartType = SeriesChartType.Bar;
chart_new.Series["Total"].Color = Color.Black;
chart_new.Series["Total"].IsValueShownAsLabel = true;
chart_new.Series["Total"].XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
chart_new.Series["Total"].YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
DataView view1 = new DataView(dt_temp);
DataTable distinctValues1 = view1.ToTable(true, "HRC_Description", "Total_HRC_Count");
dt_temp = distinctValues1;
double Total_HRC_Count = 0;
for (int x = 0; x < dt_temp.Rows.Count; x++)
{
HRC_Description = (dt_temp.Rows[x]["HRC_Description"].ToString().Trim());
Total_HRC_Count = Double.Parse(dt_temp.Rows[x]["Total_HRC_Count"].ToString().Trim());
chart_new.Series["Total"].Points.AddXY(HRC_Description, Total_HRC_Count);
}
}
This is what the chart looks like:
[![Example Chart][2]][2]
However, as you can see in the attached chart, my data is all off. There are 10 of the HRC_Description, but only 9 show up, and one is repeated. On top of that, it seems that whenever I have more than 2 series, the data gets mixed up. Does anyone have any tips on what I can do to fix this? It's driving me crazy! Thanks!!
I can't fully analyze your data but I can give you a hint, which should help in solving your problem:
I see that you add the datapoints with strings as the x-values.
This is ok (sort of; well, no, not really) but the x-values of the datapoints that actually are addded really are not strings but double and they all contain 0.
The strings only go into the labels, not the x-values! (So the values are lost)
But to be grouped together the points in your various series need some criterion and as the x-values won't work (even though they do look as if they did) the position of the points is used instead. Which dervies from the positions, i.e. from the order and number of points you add.
So only those bars will be grouped together which are added to the same position and since there are no real positions the order in which they are added is all that counts.
So you need to make sure to always use the same order and to never leave a spot empty when you add your points. If a values is missing in a series you need to add an empty dummy points (set its DataPoint.IsEmpty=true)
Easy to get wrong..!
You can check if this is the cause by checking the number of datapoints in each series. If they are not all the same this is the problem..
Here is an example: Note how the second, yellow and the 3rd, red series both are missing values but how only the yellow one is off; note the last point especially!
private void button17_Click(object sender, EventArgs e)
{
chart3.ChartAreas[0].AxisY.MajorGrid.Enabled = false;
chart3.Series.Clear();
Series s1 = chart3.Series.Add("S1");
Series s2 = chart3.Series.Add("S2");
Series s3 = chart3.Series.Add("S3");
Random R = new Random(42);
s1.ChartType = SeriesChartType.Bar;
s2.ChartType = SeriesChartType.Bar;
s3.ChartType = SeriesChartType.Bar;
for (int i = 0; i < 10; i++)
{
// this series is complete..:
s1.Points.AddXY(i + "", R.Next(100));
int r = R.Next(5);
// this series misses some points..:
if (r==0) s2.Points.AddXY(i + "", R.Next(100));
// this series inserts empty points and so misses no points.:
if (r == 0) s3.Points.AddXY(i + "", R.Next(100));
else { int p = s3.Points.AddXY(i + "", R.Next(100)); s3.Points[p].IsEmpty = true; }
}
// now add a value at "10" for all series..;
s1.Points.AddXY("10", 100);
s2.Points.AddXY("10", 100);
s3.Points.AddXY("10", 100);
}
I'm trying to populate a Flow Layout Panel with ComboBoxes and NumbericUpDowns.
The problem I'm having is using both the new NumbericUpDowns with the new ComboBoxes. Here is how I'm generating the ComboBoxes and NumericUpDowns.
// This int increments each time the code is run. It's located outside of the method below.
int captchaID = 0;
.
// Textboxes that are only for the UI, no code interaction based on text input.
string textboxText = "captchaTextbox";
TextBox newTextbox = new TextBox();
newTextbox.Name = captchaID.ToString() + textboxText;
newTextbox.Text = "";
newTextbox.Width = 175;
itemFlowPanel.Controls.Add(newTextbox);
// Combo Boxes
string comboBoxText = "captchaComboBox";
ComboBox newComboBox = new ComboBox();
newComboBox.Name = captchaID.ToString() + comboBoxText;
newComboBox.Width = 50;
newComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
itemFlowPanel.Controls.Add(newComboBox);
// This array holds my strings that are added to each ComboBox
string[] skills = new string[6];
skills[0] = "STR";
skills[1] = "DEX";
skills[2] = "CON";
skills[3] = "INT";
skills[4] = "WIS";
skills[5] = "CHA";
// This for loop is just populating my ComboBox with the array.
for (int i = 0; i < skills.Length; i++)
{
newComboBox.Items.Add(skills[i]);
}
// Numeric Up Downs
string numericUpDownText = "captchaNumericUpDown";
NumericUpDown newNumericUpDown = new NumericUpDown();
newNumericUpDown.Name = captchaID.ToString() + numericUpDownText;
newNumericUpDown.Width = 50;
newNumericUpDown.ValueChanged += new EventHandler(captchaNumericUpDown_Click);
newNumericUpDown.ValueChanged += new EventHandler(captchaNumericUpDown_ValueChanged);
itemFlowPanel.Controls.Add(newNumericUpDown);
captchaID++;
With the current code, I'm able to edit an EventHandler that each NumericUpDown contains, but I haven't found a way to make it able to read it's corresponding combobox (which increment together with captchaID).
What I'd like to be able to do, is create a new unique event for each, but if that's not possible, a way to check the ID of the combobox would help as well.
Here are quick solutions:
1) By using dictionary
Dictionary<NumericUpDown, ComboBox> _controls = new Dictionary<NumericUpDown, ComboBox>();
// when you create comboBox - add entry with associated numericUpDown
_controls.Add(numericUpDown1, comboBox1);
// now in the numericUpDown event you can get combobox like this
void numericUpDown_Whatever(object sender, WhateverEventArgs e)
{
var numericUpDown = (NumericUpDown)sender;
var comboBox = _controls[numericUpDown];
// do something
var selectedIndex = comboBox.SelectedIndex;
...
}
2) By using Tag
// add combobox into numericUpDown Tag when you create them
numericUpDown1.Tag = comboBox1;
// now in the numericUpDown event you can get combobox like this
void numericUpDown_Whatever(object sender, WhateverEventArgs e)
{
var numericUpDown = (NumericUpDown)sender;
var comboBox = (CombBox)numericUpDown.Tag;
// do something
var selectedIndex = comboBox.SelectedIndex;
...
}
You can rewrite your captchaNumericUpDown_ events to take a ComboBox as an additional parameter and then call them like this:
newNumericUpDown.ValueChanged += (sender, args) =>
{
captchaNumericUpDown_Click(sender, args, newComboBox);
}
I have a gridview to insert values into database, but it's always showing the latest value (i tested using label). I want to have it to input all the values in database (multiple rows) values of each row in grid view to be inserted into multiple rows in the database.
Here's my grid view:
I need to save every row's value into the database. Here's my code:
protected void btnCreate_Click(object sender, EventArgs e)
{
if (int.TryParse(testLabel.Text, out number))//Click count
{
testLabel.Text = (++number).ToString();
}
DataTable dt = (DataTable)ViewState["CurrentTable"];
if (dt.Rows.Count > 0)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
TextBox box1 = (TextBox)GridView1.Rows[i].Cells[1].FindControl("TextBox1");
TextBox box2 = (TextBox)GridView1.Rows[i].Cells[2].FindControl("TextBox2");
Model.question act = new Model.question(); // Entity Model CRUD
act.Answer = box2.Text; //Always show the last value.
act.QuestionContent = box1.Text; // Always show the last value.
act.TaskName = "Grammar";
act.ActivityName = dropListActivity.SelectedItem.Text;
act.QuestionNo = testLabel.Text;
daoQuestion.Insert(act);
}
daoQuestion.Save();
}
}
TextBox1 and TextBox2 are the same throughout your Grid. By selecting TextBox1 and TextBox2 from different grid doesn't help, you'll just get the values from the same two TextBoxes.
Try adding the TextBoxes to a List and then subsequently, just get their Text and insert into your database.
To add TextBox into a list, you can do this.
List<TextBox> tbList = new List<TextBox>();
tbList.Add(new TextBox{ Name="textbox"+i++ });
Subsequently, to grab the values out, just do this.
for(int i = 0; i < tbList.Count; i++)
{
//To see the data you're inserting into database.
Response.Write(tb[i].Text);
Response.Write(tb[i+1].Text);
//Insert into database based on your code.
daoQuestion.Insert(new Model.question
{
Answer = tb[i].Text,
QuestionContent = tb[++i].Text,
TaskName = "Grammar",
ActivityName = dropListActivity.SelectedItem.Text,
QuestionNo = testLabel.Text
});
daoQuestion.Save();
}