Worm
Worm

Reputation: 19

How can you divide value of one dataTable column by value of label text?

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

Answers (2)

Caius Jard
Caius Jard

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

Caius Jard
Caius Jard

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

Related Questions