C1FlexGrid for Winforms is a powerful, full-featured grid. It is modeled after Microsoft Excel, starting with familiar and powerful keyboard handling, editing, selection, clipboard support, as well as flexible appearance and optimized performance. This blog explains how to add a chart control in C1FlexGrid - another popular feature provided in Excel. In this blog, we'll add a C1Chart control in the Grid and show how to reposition the chart within the grid. It will also modify the C1Chart layout with filtering of grid contents. Adding the Chart in the Grid As we see in MS Excel, after a user selects a set of values in the Excel sheet & adds a chart object, Chart data reflects the selected data. Similar implementation can be achieved using the code provided below.


private void addChartToolStripMenuItem_Click(object sender, EventArgs e)  
{  
  if (c1FlexGrid1.Clip != "")  
  {  
     data = c1FlexGrid1.Clip;   // capture the selected data in the grid  
     string[] values = data.Split('\\r');  
     if (ischart == true)         // if the chart already exists in the grid then clear the series collection  
     {  
       chart.ChartGroups[0].ChartData.SeriesList.Clear();  
       C1.Win.C1Chart.ChartDataSeries cds;        // Add new data  
       for (int i = 0; i < values.Length; i++)  
       {  
          if (values[ i ] != "")  
          {  
             cds = new C1.Win.C1Chart.ChartDataSeries();  
             cds = chart.ChartGroups[0].ChartData.SeriesList.AddNewSeries();  
             cds.PointData.Length = 1;  
             cds.Label = "Series " + values[ i ].ToString();  
             cds.Y[0] = Convert.ToInt16(values[ i ]);  
          }  
        }  
   }  
   else   // if it doesn't, then add a new chart  
   {  
     chart = new C1.Win.C1Chart.C1Chart();  
     c1FlexGrid1.Controls.Add(chart);  
     chart.Location = new Point(200, 100);  
     chart.Size = new Size(300,300);  
     chart.Legend.Visible = true;  
     chart.Header.Visible = true;  
     chart.Header.Text = "ADDED CHART CONTROL";  
     chart.MouseDown += new MouseEventHandler(chart_MouseDown);  
     chart.MouseCaptureChanged += new EventHandler(chart_MouseCaptureChanged);  
     chart.ChartGroups[0].ChartType = C1.Win.C1Chart.Chart2DTypeEnum.Pie;  
     chart.ChartGroups[0].ChartData.SeriesList.Clear();  
     C1.Win.C1Chart.ChartDataSeries cds;  
     for (int i = 0; i < values.Length; i++)       // Add Data  
     {  
        if (values[ i ] != "")  
        {  
          cds = new C1.Win.C1Chart.ChartDataSeries();  
          cds = chart.ChartGroups[0].ChartData.SeriesList.AddNewSeries();  
          cds.PointData.Length = 1;  
          cds.Label = "Series " + values[ i ].ToString();  
          cds.Y[0] = Convert.ToInt16(values[ i ]);  
        }  
      }  
    }  

   ischart = true;                                // now the chart is there on the grid  
  }  
}  

Reposition Chart After adding a chart object, you may find that the Chart object overlaps the existing grid data and you need to reposition the chart location. Following code block helps users to shift the position of the chart as per their requirement.


void chart_MouseDown(object sender, MouseEventArgs e)  
{  
  chartPoint = e.Location;   // Capture the Chart Control for moving  
}  

void chart_MouseCaptureChanged(object sender, EventArgs e)  
{  
  Point tmpPoint = c1FlexGrid1.HitTest().Point;  
  // drop it in the user specified place in the grid  
  chart.Location = new Point(tmpPoint.X - chartPoint.X, tmpPoint.Y - chartPoint.Y);  
}  

Filtering in FlexGrid & Chart This section will show how we can implement custom filtering in C1FlexGrid & accordingly plot the filtered data in chart. To do this, we'll manually handle the behavior of the FilterEditorForm in C1FlexGrid. For a detailed description to handle this form and access its child controls, you can refer to this link. For this blog content, we have shown only the implementation to customize the Apply & Clear buttons on the FilterEditorForm by capturing and handling their click events as follows :


void applybtn_Click(object sender, EventArgs e)  
{  
  if (c1FlexGrid1.Clip != "") //check if the data is selected or not  
  {  
    if (chart != null)   // check if the chart exists or not  
    {  
       foreach (Column col in c1FlexGrid1.Cols)  
       {  
           if (col.Filter.IsActive == true)  // check which column has the active filter  
           {  
             if (((C1.Win.C1FlexGrid.ColumnFilter)(this.c1FlexGrid1.Cols[col.SafeIndex].Filter)).ValueFilter.ShowValues != null)  
             {  
                  object[] values = ((C1.Win.C1FlexGrid.ColumnFilter)(this.c1FlexGrid1.Cols[col.Index].Filter)).ValueFilter.ShowValues;  
                   chart.ChartGroups[0].ChartData.SeriesList.Clear();  
                   C1.Win.C1Chart.ChartDataSeries cds;  
                   for (int i = 0; i < values.Length; i++)  
                   {  
                      if (values[ i ].ToString() != "")  
                      {                              // Add the filtered data in the Chart  
                         cds = new C1.Win.C1Chart.ChartDataSeries();  
                         cds = chart.ChartGroups[0].ChartData.SeriesList.AddNewSeries();  
                         cds.PointData.Length = 1;  
                         cds.Label = "Series " + values[ i ].ToString();  
                         cds.Y[0] = Convert.ToInt16(values[ i ]);  
                        }  
                     }  
                 }  
             }  
          }  
      }  
   }  
   else                        // if the data is not selected then remove the chart from the grid  
   {                             // upon applying filtering  
       c1FlexGrid1.Controls.Clear();  
       ischart = false;  
    }  
}  

void clearbtn_Click(object sender, EventArgs e)  
{  
  if (c1FlexGrid1.Clip != "")  // if data has been selected in the grid then set default  
    {  
       // data in  the chart upon clearing  
       data = c1FlexGrid1.Clip;  
       string[] values = data.Split('\\r');  
       if (ischart == true)  
       {  
          chart.ChartGroups[0].ChartData.SeriesList.Clear();  
          C1.Win.C1Chart.ChartDataSeries cds;  
          for (int i = 0; i < values.Length; i++)  
          {  
             if (values[ i ] != "")  
             {  
               cds = new C1.Win.C1Chart.ChartDataSeries();  
               cds = chart.ChartGroups[0].ChartData.SeriesList.AddNewSeries();  
               cds.PointData.Length = 1;  
               cds.Label = "Series " + values[ i ].ToString();  
               cds.Y[0] = Convert.ToInt16(values[ i ]);  
              }  
          }  
      }  
   }  
  else  
  {  
    c1FlexGrid1.Controls.Clear(); // if data hasn't been selected in the grid then  
    ischart = false; // upon clearing the chart will be removed  
  }  
}  

After the data is selected in the grid, the apply & clear buttons will work as they work in Excel. The filtered data is shown in the chart & upon clearing the filter, the default selected data in the grid is reflected in the chart. Click on the following image to get a better understanding of the behavior. Refer the attached samples for the complete implementation. Download Sample CS Download Sample VB