简体   繁体   中英

C# Using data from DataGridView in a Chart

I have code that generates data in the DataGridView and I want to also push this to a chart from the same button click.

Process:

Text is put into a text box myInputBox then the button processButton is pressed to split the text up and output it to the DataGridView myOutputDGV the button has the following code:

private void processButton_Click(object sender, EventArgs e)
        {
            List<string> mySplit = new List<string>(myInputBox.Text.Split(new string[] { "XN" }, StringSplitOptions.None));

            DataGridViewTextBoxColumn myOutputGrid = new DataGridViewTextBoxColumn();
            myOutputGrid.HeaderText = "Line";
            myOutputGrid.Name = "Line";
            myOutputDGV.Columns.Add(myOutputGrid);
            myOutputGrid = new DataGridViewTextBoxColumn();

            myOutputGrid.HeaderText = "Section";
            myOutputGrid.Name = "Section";
            myOutputDGV.Columns.Add(myOutputGrid);
            myOutputGrid = new DataGridViewTextBoxColumn();

            myOutputGrid.HeaderText = "Range";
            myOutputGrid.Name = "Range";
            myOutputDGV.Columns.Add(myOutputGrid);
            myOutputGrid = new DataGridViewTextBoxColumn();

            myOutputGrid.HeaderText = "Total";
            myOutputGrid.Name = "Total";
            myOutputDGV.Columns.Add(myOutputGrid);
            myOutputGrid = new DataGridViewTextBoxColumn();

            foreach (string item in mySplit)
            {
                myOutputDGV.Rows.Add(item.Trim(),
                item.Split(new string[] { "(cost=" }, StringSplitOptions.None).First(),
                Regex.Match(item, @"cost=(.+?) rows").Groups[1].Value,
                Regex.Match(item, @"cost=(.+?)\.\.").Groups[1].Value,
            }
        }

I want to populate my chart myChart with the values from column[1] (Line) on the X axis and column[3] (Total) on the Y axis.

EDIT:

I have tried adding the following code in the button processButton click code but the chart isn't populated:

ChartArea chartArea1 = new ChartArea();
chartArea1.AxisX.MajorGrid.LineColor = Color.LightGray;
chartArea1.AxisY.MajorGrid.LineColor = Color.LightGray;
chartArea1.AxisX.LabelStyle.Font = new Font("Consolas", 8);
chartArea1.AxisY.LabelStyle.Font = new Font("Consolas", 8);
myChart.ChartAreas.Add(chartArea1);

myChart.Series.Add(new Series());

myChart.Series[0].XValueMember = myOutputDGV.Columns[1].DataPropertyName;
myChart.Series[0].YValueMembers = myOutputDGV.Columns[3].DataPropertyName;
myChart.DataSource = myOutputDGV.DataSource;

myChart.Series[0].ChartType = SeriesChartType.Line;

EDIT 2:

I have also tried this to no avail:

System.Windows.Forms.DataVisualization.Charting.ChartArea myChartArea = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
myChartArea.AxisX.MajorGrid.LineColor = Color.Red;
myChartArea.AxisY.MajorGrid.LineColor = Color.Red;
myChartArea.AxisX.LabelStyle.Font = new System.Drawing.Font("Consolas", 10);
myChartArea.AxisY.LabelStyle.Font = new System.Drawing.Font("Consolas", 10);
myChart.ChartAreas.Add(myChartArea);

myChart.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series());

var datax = myOutputDGV.Rows.Cast<DataGridViewRow>().Select(x => x.Cells[1].Value).ToList();
var datay = myOutputDGV.Rows.Cast<DataGridViewRow>().Select(x => x.Cells[4].Value).ToList();

EDIT 3 FULL CODE:

private void ProcessButton_Click(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(myInputBox.Text) || myInputBox.Text == "")
{
    MessageBox.Show("Please enter data", "Info");
}
else
{
    myOutputDGV.Rows.Clear();
    myOutputDGV.Columns.Clear();
    myOutputDGV.Refresh();
    myChart.ChartAreas.Clear();
    myChart.Series.Clear();

    List<string> mySplit = new List<string>(myInputBox.Text.Split(new string[] { "XN" }, StringSplitOptions.None));

    DataGridViewTextBoxColumn myOutputGrid = new DataGridViewTextBoxColumn();
    myOutputGrid.HeaderText = "Line";
    myOutputGrid.Name = "Line";
    myOutputDGV.Columns.Add(myOutputGrid);
    myOutputGrid = new DataGridViewTextBoxColumn();

    myOutputGrid.HeaderText = "Section";
    myOutputGrid.Name = "Section";
    myOutputDGV.Columns.Add(myOutputGrid);
    myOutputGrid = new DataGridViewTextBoxColumn();

    myOutputGrid.HeaderText = "Cost Range";
    myOutputGrid.Name = "Cost Range";
    myOutputDGV.Columns.Add(myOutputGrid);
    myOutputGrid = new DataGridViewTextBoxColumn();

    myOutputGrid.HeaderText = "Cost First Row";
    myOutputGrid.Name = "Cost First Row";
    myOutputDGV.Columns.Add(myOutputGrid);
    myOutputGrid = new DataGridViewTextBoxColumn();

    myOutputGrid.HeaderText = "Cost All Rows";
    myOutputGrid.Name = "Cost All Rows";
    myOutputDGV.Columns.Add(myOutputGrid);
    myOutputGrid = new DataGridViewTextBoxColumn();

    myOutputGrid.HeaderText = "Rows";
    myOutputGrid.Name = "Rows";
    myOutputDGV.Columns.Add(myOutputGrid);
    myOutputGrid = new DataGridViewTextBoxColumn();

    myOutputGrid.HeaderText = "Width";
    myOutputGrid.Name = "Width";
    myOutputDGV.Columns.Add(myOutputGrid);

    foreach (string item in mySplit)
    {
        myOutputDGV.Rows.Add(item.Trim(),
        item.Split(new string[] { "(cost=" }, StringSplitOptions.None).First(),
        Regex.Match(item, @"cost=(.+?) rows").Groups[1].Value,
        Regex.Match(item, @"cost=(.+?)\.\.").Groups[1].Value,
        Regex.Match(item, @"\.\.(.+?) ").Groups[1].Value,
        Regex.Match(item, @"rows=(.+?) ").Groups[1].Value,
        Regex.Match(item, @"width=(.+?)\)").Groups[1].Value);
    }

    var datax = myOutputDGV.Rows.Cast<DataGridViewRow>().Select(x => x.Cells[1].Value).ToList();
    var datay = myOutputDGV.Rows.Cast<DataGridViewRow>().Select(x => x.Cells[4].Value).ToList();
    System.Windows.Forms.DataVisualization.Charting.ChartArea myChartArea = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
    myChartArea.AxisX.MajorGrid.LineColor = Color.Red;
    myChartArea.AxisY.MajorGrid.LineColor = Color.Red;
    myChartArea.AxisX.LabelStyle.Font = new System.Drawing.Font("Consolas", 10);
    myChartArea.AxisY.LabelStyle.Font = new System.Drawing.Font("Consolas", 10);
    myChart.ChartAreas.Add(myChartArea);
    myChart.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series());

    myChart.Series[0].XValueMember = myOutputDGV.Columns[1].DataPropertyName;
    myChart.Series[0].YValueMembers = myOutputDGV.Columns[3].DataPropertyName;
    myChart.DataSource = myOutputDGV.DataSource;
    myChart.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series());
}
}

EDIT 4 i have grids and half a line:

            var datax = myOutputDGV.Rows.Cast<DataGridViewRow>().Select(x => x.Cells[1].Value).ToList();
            var datay = myOutputDGV.Rows.Cast<DataGridViewRow>().Select(x => x.Cells[4].Value).ToList();
            string dataxx = datax.ToString();
            string datayy = datay.ToString();
            System.Windows.Forms.DataVisualization.Charting.ChartArea myChartArea = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
            myChart.ChartAreas.Add(myChartArea);
            myChart.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series());
            myChart.Series[0].Points.AddXY(dataxx, datayy);

If you want to preserve your code as much as possible, you can fill a DataTable instead of the DataGridView and use that as the DataSource in both the DataGridView and Chart .

Following code is roughly what you need to do for this case: Declare the DataTable , create Columns (of correct types, I just guessed them!), fill the Rows , and use it as DataSource .

The benefits are clear: You will have forced data-types and you can use a breakpoint and VS Data Visualizer to check, if the content looks as expected (but you'll see it in this case in DataGridView too). It might be the data type giving you a trouble in the chart .

C# (translated):

private DataTable dt;

private void MyForm_Load()
{
    LoadDefaults();
}

private void LoadDefaults()
{
    dt.Columns.Add("Line", typeof(Int16));
    dt.Columns.Add("Section", typeof(string));
    dt.Columns.Add("Range", typeof(string));
    dt.Columns.Add("Total", typeof(float));
}

private void processButton_Click(object sender, EventArgs e)
{

foreach (var Item in mySplit) {
    dt.Rows.Add({Item.Trim(), ......});
    }


this.DataGridView1.DataSource = dt;
...
myChart.DataSource = dt;
}

VB.NET

Dim dt As DataTable

Private Sub MyForm_Load()
    Call LoadDefaults()
End Sub

Private Sub LoadDefaults()
    dt.Columns.Add("Line", GetType(Int16))
    dt.Columns.Add("Section", GetType(String))
    dt.Columns.Add("Range", GetType(String))
    dt.Columns.Add("Total", GetType(Single))
End Sub

Private Sub processButton_Click(sender As Object, e As EventArgs) Handles BtnExcel.Click
    For Each Item In mySplit
        dt.Rows.Add({Item.Trim(), Item.Split("(cost=", StringSplitOptions.None).First(), Regex.Match(Item, @"cost=(.+?) rows").Groups[1].Value, Regex.Match(Item, @"cost=(.+?)\.\.").Groups[1].Value})
    Next

    Me.DataGridView1.DataSource = dt
    ...
    myChart.DataSource = dt
End Sub

EDIT - debugging charts example:

在此处输入图片说明

There are many ways to use Chart DataBinding . - I suggest, when binding, not to bind to the chart but to the Points of a Series ! - This way you can control things better, like choosing which Series to bind to.

An example..:

var datax = dataGridView1.Rows
            .Cast<DataGridViewRow>().Select(x => x.Cells[ixName].Value).ToList();
var datay = dataGridView1.Rows
            .Cast<DataGridViewRow>().Select(x => x.Cells[yName].Value).ToList();

aSeries.Points.DataBindXY(datax, datay);

..where xName and yName can be names or indices of the DGV Columns .

But, as has been suggested, using a DataTable is recommended. In any case you need an IEnumerable to bind.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM