Reputation: 19
Question
How can I have column "Days" populate the results of column "Hours" divided by label25.Text?
Code
Below is the code I'm attempting to accomplish this. I'm thinking the issue is within the foreach portion.
dataGridView4.AutoGenerateColumns = false;
DataTable dt2 = new DataTable();
dt2.Columns.Add("Type", typeof(String));
dt2.Columns.Add("Hours", typeof(String));
dt2.Columns.Add("PerDiem", typeof(String));
dt2.Columns.Add("Days", typeof(decimal)).Expression = "[Hours]/" + label25.Text;
DataGridViewComboBoxColumn type = new DataGridViewComboBoxColumn();
var list10 = new List<string>() { "Tom", "Dick", "Harry"};
type.DataSource = list10;
type.HeaderText = "Type";
type.DataPropertyName = "Type";
DataGridViewTextBoxColumn hours = new DataGridViewTextBoxColumn();
hours.HeaderText = "Hours";
hours.DataPropertyName = "Hours";
DataGridViewComboBoxColumn perdiem = new DataGridViewComboBoxColumn();
var list11 = new List<string>() { "YES", "NO"};
perdiem.DataSource = list11;
perdiem.HeaderText = "PerDiem";
perdiem.DataPropertyName = "PerDiem";
DataGridViewTextBoxColumn days = new DataGridViewTextBoxColumn();
days.HeaderText = "Days";
days.DataPropertyName = "Days";
dataGridView4.DataSource = dt2;
dataGridView4.Columns.AddRange(type, hours, perdiem, days);
dataGridView4.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
type.FlatStyle = FlatStyle.Flat;
perdiem.FlatStyle = FlatStyle.Flat;
Any help would be appreciated!! Thank you in advance.
Update
DataTable dt2 = new DataTable();
dt2.Columns.Add("Hours", typeof(decimal));
dt2.Columns.Add("HoursInAWorkingDay", typeof(decimal));
dt2.Columns.Add("Days", typeof(decimal)).Expression = "[Hours]/[HoursInAWorkingDay]";
DataGridViewTextBoxColumn hours = new DataGridViewTextBoxColumn();
hours.HeaderText = "Hours";
hours.DataPropertyName = "Hours";
DataGridViewComboBoxColumn perdiem = new DataGridViewComboBoxColumn hoursinaworkingday = new DataGridViewComboBoxColumn();
var list13 = new List<string>() { "8", "10", "12", "14" };
hoursinaworkingday.DataSource = list13;
hoursinaworkingday.HeaderText = "Work Day";
hoursinaworkingday.DataPropertyName = "Work Day";
DataGridViewTextBoxColumn days = new DataGridViewTextBoxColumn();
days.HeaderText = "Days";
days.DataPropertyName = "Days";
Made the suggested changes and I'm still falling short. Unfortunately the Days column is not populating a value when entering data in Hours and/or Selecting an option from HoursInAWorkDay. Please help. I know we're close.
Upvotes: 0
Views: 210
Reputation: 74605
Posting this as a separate answer because your edit actually asks a separate question (how to bind up a combo so it properly edits a table column, versus how to make a table column auto calc a value based on two other columns)
This is a complete fixed code, nicely spaced out/arranged and commented so you can look over it and read what it's doing. You could make a new project, double click the blank form it create and replace the Form1_Load code with this. Note that (with the exception of Form1) I've named variables slightly more sensibly than "dt2", "list13" ;):
private void Form1_Load(object sender, EventArgs e)
{
//set up table
DataTable timesheet = new DataTable();
timesheet.Columns.Add("Hours", typeof(decimal));
timesheet.Columns.Add("HoursInAWorkingDay", typeof(decimal));
//Add creates a column and returns it, so we can set the expression on the return value, without needing to dig it out of the column collection again
timesheet.Columns.Add("Days", typeof(decimal)).Expression = "[Hours]/[HoursInAWorkingDay]";
//set up column for Hours - dont really need this, it would autogenerate
DataGridViewTextBoxColumn hours = new DataGridViewTextBoxColumn();
hours.HeaderText = "Hours";
hours.DataPropertyName = "Hours";
//set up column for HoursInAWorkingDay
DataGridViewComboBoxColumn hoursinaworkingday = new DataGridViewComboBoxColumn();
//make array of decimal values, then use LINQ to turn them into a list of objects that have a `string Dis` and a `decimal Val` property
//these will be used during binding
var hiawd = new[] { 8m, 10m, 12m, 14m }.Select(s => new { Dis = $"{s:0}h", Val = s }).ToList();
hoursinaworkingday.HeaderText = "Work Day";
hoursinaworkingday.DataPropertyName = "HoursInAWorkingDay"; //the column in dt2 that changing the combo shall edit
hoursinaworkingday.DisplayMember = "Dis"; //show the Dis property in the combo, e.g. the string "8h"
hoursinaworkingday.ValueMember = "Val"; //use the Val property of the item selected (e.g. the decimal 8) when setting the HoursInAWorkingDay
hoursinaworkingday.DataSource = hiawd; //the list of values to use for items in the combo. tip: set datasource last
//it is important to appreciate that the combo connects the datatable to the list. it:
//1. reads the dt row's HoursInAWorkingDay,
//2. finds the read value in the Val property of a list item,
//3. shows that item by the Dis property.
//4. when the user picks a new item the value of the new item's Val
// property is written back to the dt HoursInAWorkingDay column
//set up column for Days - dont really need this, it would autogenerate
DataGridViewTextBoxColumn days = new DataGridViewTextBoxColumn();
days.HeaderText = "Days";
days.DataPropertyName = "Days";
var dgv = new DataGridView();
dgv.Columns.Add(hours);
dgv.Columns.Add(hoursinaworkingday);
dgv.Columns.Add(days);
this.Controls.Add(dgv);
dgv.DataSource = timesheet;
dgv.Dock = DockStyle.Fill;
}
Upvotes: 1
Reputation: 74605
Change
dt2.Columns.Add("Days", typeof(String));
To
dt2.Columns.Add("Days", typeof(decimal)).Expression = "[Hours]/" + label25.Text;
Also make your Hours column typeof(decimal) and remove the for loop from the bottom of the code
The days column is now read only and autopopulates based on the hours. If you want it to be variable (ie to update if you change label25.Text) you should instead put a column in the datatable for the divisor and bind label25 to it
Other tips:
String is the default type of a column; you don't need to specify it
You could make your life much easier by adding a DataSet object to your project and doing all this in there; it creates strongly typed datatables that are much easier to work with in every way
Please also name your controls and variables properly - renaming a control/naming a var an apt name takes a couple of seconds. Eventually you will rue the day you wrote the code to be full of meaningless names like "datatable 2, list 10, label 25" because it makes it incredibly difficult to maintain; you're going to constantly have to look up what is what..
You do seem to appreciate the notion of naming some things sensibly (you've called your days and hours Columns "days" and "hours" rather than "decimal1" and "decimal2" - extend the notion out to every line of code you write) - it makes it easier for other developers to help you too
Upvotes: 2