0

As I am looking for the Max and Min of each row not from each column my question is not a duplicate of https://stackoverflow.com/questions/2442525/how-to-select-min-and-max-values-of-a-column-in-a-datatable

I am working on a DataTable form. I am having trouble with aggregate calculations, within the same row. The end goal is the get this calculation: (Max(col1,col2,col3,col4) - Min(col1,col2,col3,col4))

Using this code works to add two values of the same row; dt.Columns.Add("Expression column", typeof(Double), "Col1 + Col2");

The error I get is

I have tried this but get an error

 dt.Columns.Add("Coreshift", typeof(Double), "max(Col1 ,Col2,Col3,Col4");
dt.Columns.Add("Coreshift", typeof(Double), "max(Dt.Col1 ,Dt.Dt.Col2,Dt.Col3,Dt.Col4");

Syntax error in aggregate argument: Expecting a single column argument with possible 'Child' qualifier.'

As I want to do this dynamically I have thought about putting each row value into an array, however I am not sure how to do that with out a button click.

I have referenced the msdn expression page C# DataColumn expression

Updated with new code.

 private static void Row_Changed(object sender, DataRowChangeEventArgs e)
    {

        int RowIndex = e.Row.Table.Rows.IndexOf(e.Row);




        Console.WriteLine("Row_Changed Event: a={0},b={1},c={2},d={3},e ={4}; actaion={1}",
    e.Row["Sw1"], e.Row["Sw2"], e.Row["Sw3"], e.Row[3], e.Row[4]);

        double[] scores = new double[] {(double)e.Row["Sw1"], (double)e.Row["Sw2"], (double)e.Row["Sw3"], (double)e.Row["Sw4"] };
        double x = scores.Max();
        Console.WriteLine("Max");
        Console.WriteLine(x);
        Console.WriteLine("Row index");
        Console.WriteLine(RowIndex);



    }

When I used your code I can't get your table to create the rows and columns,I'm sure its something simple. I've gotten in the obsessed crazy mode.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace a
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

    }

    private void Form1_Load(object sender, EventArgs e)
    {
        dataGridView1.DataSource = new GridForm();


    }



    class GridForm : Form
    {
        private DataTable _table = new DataTable();
        private DataGridView _grid = new DataGridView();

        public GridForm()
        {
            _table.Columns.Add("Col1", typeof(double));
            _table.Columns.Add("Col2", typeof(double));
            _table.Columns.Add("Col3", typeof(double));
            _table.Columns.Add("Col4", typeof(double));

            var calcCol = _table.Columns.Add("Calc", typeof(double));
            calcCol.DefaultValue = 0.0d;
            _table.RowChanged += (sender, args) =>
            {

                // 4 first columns as doubles
                var vals = args.Row.ItemArray.Take(4).Cast<double>().ToArray();
                var calc = vals.Max() - vals.Min();

                // Only set if changed to avoid infinite loop
                if (!double.Equals(args.Row["Calc"], calc))
                {
                    args.Row["Calc"] = calc;
                }
            };

            _table.LoadDataRow(new object[] {
        1d, 1d, 3d, 4d
    }, true);
            _table.LoadDataRow(new object[] {
        2d, 2d, 5d, 6d
    }, true);

            Controls.Add(_grid);
            _grid.DataSource = _table;
            _grid.Columns["Calc"].ReadOnly = true;
            _grid.Dock = DockStyle.Fill;
            _grid.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;
            _grid.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
            _grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
        }
    }








}

}

liquidacid
  • 108
  • 1
  • 9
  • The Max() and Min() methods in the datatable expressions are only meant to aggregate all rows in a related table. Your best bet here might be to hack around with the `RowChanged` event, unfortunately – gnud Apr 23 '18 at 21:37
  • Is there a c# equivalent of the Java Jtable table.getValueAt(row,col) – liquidacid Apr 23 '18 at 22:32
  • `table.Rows[row][col]` – gnud Apr 23 '18 at 22:33

1 Answers1

1

Here's a very small and stupid example that illustrates how you can use the RowChanged handler to do the calculations. This might give you other problems if you use complex dataset/datatable/dataview functionality, but if you mainly use one datatable in one datagridview I think this might work.

class GridForm : Form
{
    private DataTable _table = new DataTable();
    private DataGridView _grid = new DataGridView();    

    public GridForm()
    {
        _table.Columns.Add("Col1", typeof(double));
        _table.Columns.Add("Col2", typeof(double));
        _table.Columns.Add("Col3", typeof(double));
        _table.Columns.Add("Col4", typeof(double));

        var calcCol = _table.Columns.Add("Calc", typeof(double));
        calcCol.DefaultValue = 0.0d;
        _table.RowChanged += (sender, args) =>
        {

            // 4 first columns as doubles
            var vals = args.Row.ItemArray.Take(4).Cast<double>().ToArray();
            var calc = vals.Max() - vals.Min();

            // Only set if changed to avoid infinite loop
            if (!double.Equals(args.Row["Calc"], calc))
            {
                args.Row["Calc"] = calc;
            }
        };

        _table.LoadDataRow(new object[] {
            1d, 1d, 3d, 4d
        }, true);
        _table.LoadDataRow(new object[] {
            2d, 2d, 5d, 6d
        }, true);

        Controls.Add(_grid);
        _grid.DataSource = _table;
        _grid.Columns["Calc"].ReadOnly = true;
        _grid.Dock = DockStyle.Fill;
        _grid.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;
        _grid.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
        _grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
    }
}
gnud
  • 77,584
  • 5
  • 64
  • 78
  • I had come up with a similar solution. However I am stuck when it comes to updating the Calc column. – liquidacid Apr 24 '18 at 18:43
  • What's the problem? The column doesn't update? Your event handler doesn't trigger? – gnud Apr 24 '18 at 18:51
  • When I made the example, I noticed that you can't set the calculated column to read only in the datatable, if you do, you can't update it. You can set it to read only in the grid though, that's what I do in the example. – gnud Apr 24 '18 at 18:51
  • On my example I am using "dt.Rows[0][4] = (double)maxv;" to update and I am getting a stack overflow error – liquidacid Apr 25 '18 at 12:48
  • Did you see the comment in my code about avoiding infinite loops? The RowChanged event is triggered again when you update the calculated column, that's why the stack overflows – gnud Apr 25 '18 at 18:45