Merge cells using EPPlus? - c#

I'm using the EPPlus library to read/write Excel files: http://epplus.codeplex.com/
I'm trying to simply merge some cells when writing a document:
using (ExcelPackage pck = new ExcelPackage())
{
//Create the worksheet
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Demo");
//Format the header for column 1-3
using (ExcelRange rng = ws.Cells["A1:C1"])
{
bool merge = rng.Merge;
}
}
There's a property named Merge that simply returns true or false. I thought maybe that would Merge the cells, but it doesn't.
Anyone know how to do this?

You have to use it like this:
ws.Cells["A1:C1"].Merge = true;
instead of:
using (ExcelRange rng = ws.Cells["A1:C1"])
{
bool merge = rng.Merge;
}

If you want to merge cells dynamically, you can also use:
worksheet.Cells[FromRow, FromColumn, ToRow, ToColumn].Merge = true;
All these variables are integers.

You can create a extension method:
public static void Merge(this ExcelRangeBase range)
{
ExcelCellAddress start = range.Start;
ExcelCellAddress end = range.End;
range.Worksheet.Cells[start.Row, start.Column, end.Row, end.Column].Merge = true;
}
You can use this as you would via interop:
range.Merge();

int inicio = CELDA_CUERPO;
bool values = true;
int COLUMNA_A = 0;
int finx_a = 0;
int finy_a = 0;
int COLUMNA_B = 1;
int finx_b = 0;
int finy_b = 0;
//Pintar cabecera:
for (int i = 0; i < ListaCabecera.Length; i++)
{
celda = $"{letras[i]}{CELDA_CABECERA}";
if (i == 0)
{
inicioRango = celda;
}
Sheet.Cells[celda].Value = ListaCabecera[i];
//System.Drawing.Color colFromHex = System.Drawing.ColorTranslator.FromHtml("#B7DEE8");
Sheet.Cells[celda].Style.Font.Color.SetColor(Color.FromArgb(0, 124, 183));
Sheet.Cells[celda].Style.Fill.PatternType = ExcelFillStyle.Solid;
Sheet.Cells[celda].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(232, 235, 249));
Sheet.Cells[celda].Style.Font.Bold = true;
Sheet.Cells[celda].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
}
//Pintar detalle:
for (int i = 0; i < Datos.GetLength(0); i++)
{
for (int j = 0; j < Datos.GetLength(1); j++)
{
celda = $"{letras[j]}{CELDA_CUERPO + i}";
finalizaRango = celda;
if (j < 3) if (Datos[i, j].valor != null && Datos[i, j + 1].valor == null)
{
Sheet.Cells[celda].Style.Font.Color.SetColor(Color.FromArgb(156, 0, 6));
Sheet.Cells[celda].Style.Fill.PatternType = ExcelFillStyle.Solid;
Sheet.Cells[celda].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(255, 199,206));
}
Sheet.Cells[celda].Value = Datos[i, j].valor;
}
//::::::::::::::::::: MERGE A ::::::::::::::::::::
if (i < Datos.GetLength(0) - 1)
{
// :::::::::::::::::::::: x :::::::::::::::::::::::::::::::::
if (values)
{
if (Datos[i, COLUMNA_A].valor == Datos[i, COLUMNA_A].valor)
{
values = false;
finx_a = inicio + i;
finx_b = inicio + i;
//list_x.Add(finx_b);
}
}
else
{
if (Datos[i - 1, COLUMNA_A].valor != Datos[i, COLUMNA_A].valor)
{
finx_a = inicio + i;
}
if (Datos[i - 1, COLUMNA_B].valor != Datos[i, COLUMNA_B].valor)
{
finx_b = inicio + i;
//list_x.Add(finx_b);
}
}
// :::::::::::::::::::::: y (A) :::::::::::::::::::::::::::::::::
if (Datos[i, COLUMNA_A].valor != Datos[i + 1, COLUMNA_A].valor)
{
finy_a = inicio + i;
//list_y.Add(finy);
Sheet.Cells[$"A{finx_a}:A{finy_a}"].Value = Datos[i, COLUMNA_A].valor;
Sheet.Cells[$"A{finx_a}:A{finy_a}"].Merge = true;
Sheet.Cells[$"A{finx_a}:A{finy_a}"].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
}
// :::::::::::::::::::::: y (B) :::::::::::::::::::::::::::::::::
if (Datos[i, COLUMNA_B].valor != Datos[i + 1, COLUMNA_B].valor)
{
finy_b = inicio + i;
//list_y.Add(finy_b);
Sheet.Cells[$"B{finx_b}:B{finy_b}"].Value = Datos[i, COLUMNA_B].valor;
Sheet.Cells[$"B{finx_b}:B{finy_b}"].Merge = true;
Sheet.Cells[$"B{finx_b}:B{finy_b}"].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
}
}
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
}

Related

How to merge Excel column with dynamic value

I trying to merge the excel column when there is same value in the first 2 row. The value is coming from my database query. Currently what I had generated is like this:
I want to merge the column like this:
Here is my function code:
public static async Task<MemoryStream> getNewListingExcelWithContentColumnMerge<T>(List<T> list, List<string> header, string name, string headerTitle)
{
try
{
int row = 3;
int col = 1;
MemoryStream output = new MemoryStream();
using (ExcelPackage package = new ExcelPackage())
{
ExcelWorksheet ws = package.Workbook.Worksheets.Add(name);
ws.PrinterSettings.PaperSize = ePaperSize.A4;
ws.PrinterSettings.FitToPage = true;
ws.Cells["A1:D1"].Merge = true;
ws.Cells["A1:D1"].Value = headerTitle;
for (int i = 0; i < header.Count(); i++)
{
ws.Cells[row, col].Value = header[i];
col++;
}
ws.Cells[1, 1, 1, col].Style.Font.Bold = true;
col = 1;
row++;
for (int i = 0; i < list.Count(); i++)
{
Type type = list[i].GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
object asd = property.GetValue(list[i], null);
//Add data to the next line if consist of '\n'.
if (asd != null && asd.ToString().Contains(Environment.NewLine))
{
var splitValue = asd.ToString().Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
var sameValuePlacementList = new List<int>();
for (var j = 0; j < splitValue.Count(); j++)
{
if (j == 0)
{
ws.Cells[row, col].Value = splitValue[j];
ws.Cells[row, col].Style.WrapText = true;
}
else
{
ws.Cells[row, col].RichText.Add(Environment.NewLine + splitValue[j]);
}
}
}
else
{
ws.Cells[row, col].Value = asd;
}
col++;
}
col = 1;
row++;
}
ws.Cells[3, 1, ws.Dimension.End.Row, ws.Dimension.End.Column - 1].AutoFitColumns();
ws.Cells[3, 1, ws.Dimension.End.Row, ws.Dimension.End.Column - 1].Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
ws.Cells[3, 1, ws.Dimension.End.Row, ws.Dimension.End.Column - 1].Style.Border.Top.Style = ExcelBorderStyle.Thin;
ws.Cells[3, 1, ws.Dimension.End.Row, ws.Dimension.End.Column - 1].Style.Border.Right.Style = ExcelBorderStyle.Thin;
ws.Cells[3, 1, ws.Dimension.End.Row, ws.Dimension.End.Column - 1].Style.Border.Left.Style = ExcelBorderStyle.Thin;
package.SaveAs(output);
return output;
}
}
catch (Exception ex)
{
return null;
}
}
What can I try next?
You can do it this way:
ws.Range[ws.Cells[1, 1], ws.Cells[4, 1]].Merge();
It will merge rows from 1 to 4 in column 1.
int tempRow = startRowForMerge;
int firstSameRowIndex = 0;
int lastSameRowIndex = 0;
int maxCount = tempRow + list.Count() - 1; // -1 because array start from 0
bool needToMerge = false;
foreach(int tempColumn in mergeColumnList)
{
tempRow = startRowForMerge;
for (int i = 0; i < list.Count(); i++)
{
if (tempRow < maxCount)
{
if (row > 4 && ws.Cells[tempRow, tempColumn].Value.ToString() == ws.Cells[tempRow - 1, tempColumn].Value.ToString())
{
needToMerge = true;
if (firstSameRowIndex == 0)
{
firstSameRowIndex = tempRow - 1;
}
lastSameRowIndex = tempRow;
}
else
{
if (needToMerge == true) // to merge data in between the list
{
ws.Cells[firstSameRowIndex, tempColumn, lastSameRowIndex, tempColumn].Merge = true;
ws.Cells[firstSameRowIndex, tempColumn, lastSameRowIndex, tempColumn].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
needToMerge = false;
firstSameRowIndex = 0;
lastSameRowIndex = 0;
}
}
}
else
{
if (needToMerge == true) // to merge data in last row
{
ws.Cells[firstSameRowIndex, tempColumn, lastSameRowIndex, tempColumn].Merge = true;
ws.Cells[firstSameRowIndex, tempColumn, lastSameRowIndex, tempColumn].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
needToMerge = false;
firstSameRowIndex = 0;
lastSameRowIndex = 0;
}
}
tempRow++;
}
}

Multiplication and Sum in GridView ASP.Net C#

I have a datatable which is bound to GridView datasource as follows.
Overall i want to Multiply 'Quantity' column value with 'Part1 qty' column value until 'column5' cell value is repeating and so on
the result of operation should appear underneath the value as highlighted in red for understanding
My GridView data currently
I want the following output
Required Output
My GridMarkup
My GridMarkup
What I have done so far is
protected void GridView1_DataBound(object sender, EventArgs e)
{
int gridViewCellCount = GridView1.Rows[0].Cells.Count;
string[] columnNames = new string[gridViewCellCount];
for (int k = 0; k < gridViewCellCount; k++)
{
columnNames[k] = ((System.Web.UI.WebControls.DataControlFieldCell)(GridView1.Rows[0].Cells[k])).ContainingField.HeaderText;
}
for (int i = GridView1.Rows.Count - 1; i > 0; i--)
{
GridViewRow row = GridView1.Rows[i];
GridViewRow previousRow = GridView1.Rows[i - 1];
var result = Array.FindIndex(columnNames, element => element.EndsWith("QTY"));
var Arraymax=columnNames.Max();
int maxIndex = columnNames.ToList().IndexOf(Arraymax);
decimal MultiplicationResult=0;
int counter = 0;
for (int j = 8; j < row.Cells.Count; j++)
{
if (row.Cells[j].Text == previousRow.Cells[j].Text)
{
counter++;
if (row.Cells[j].Text != " " && result < maxIndex)
{
var Quantity = GridView1.Rows[i].Cells[1].Text;
var GLQuantity = GridView1.Rows[i].Cells[result].Text;
var PreviousQuantity= GridView1.Rows[i-1].Cells[1].Text;
var PreviousGLQuantity= GridView1.Rows[i-1].Cells[result].Text;
//var Quantity = dt.Rows[i].ItemArray[1];
//var GLQuantity = dt.Rows[i].ItemArray[Convert.ToInt64(result)].ToString();
var GLQ = GLQuantity.TrimEnd(new Char[] { '0' });
var PGLQ = PreviousGLQuantity.TrimEnd(new char[] { '0' });
if (GLQ == "")
{
GLQ = 0.ToString();
}
if (PGLQ == "")
{
PGLQ = 0.ToString();
}
MultiplicationResult = Convert.ToDecimal(Quantity) * Convert.ToDecimal(GLQ) + Convert.ToDecimal(PreviousQuantity) * Convert.ToDecimal(PGLQ);
object o = dt.Rows[i].ItemArray[j] + " " + MultiplicationResult.ToString();
GridView1.Rows[i].Cells[j].Text = o.ToString();
GridView1.Rows[i].Cells[j].Text.Replace("\n", "<br/>");
result++;
}
else
result++;
if (previousRow.Cells[j].RowSpan == 0)
{
if (row.Cells[j].RowSpan == 0)
{
previousRow.Cells[j].RowSpan += 2;
}
else
{
previousRow.Cells[j].RowSpan = row.Cells[j].RowSpan + 1;
}
row.Cells[j].Visible = false;
}
}
else
result++;
}
}
}
Thanks in advance.
We can use below Answer
protected void GridView1_DataBound(object sender, EventArgs e)
{
int gridViewCellCount = GridView1.Rows[0].Cells.Count;
string[] columnNames = new string[gridViewCellCount];
for (int k = 0; k < gridViewCellCount; k++)
{
columnNames[k] = ((System.Web.UI.WebControls.DataControlFieldCell)(GridView1.Rows[0].Cells[k])).ContainingField.HeaderText;
}
for (int i = GridView1.Rows.Count - 1; i > 0; i--)
{
GridViewRow row = GridView1.Rows[i];
GridViewRow previousRow = GridView1.Rows[i - 1];
var result = Array.FindIndex(columnNames, element => element.EndsWith("QTY"));
var Arraymax = columnNames.Max();
int maxIndex = columnNames.ToList().IndexOf(Arraymax);
decimal MultiplicationResult = 0;
decimal currentCellResult = 0;
for (int j = 8; j < row.Cells.Count; j++)
{
var defaultvalue = row.Cells[j].Text.ToString();
var defaultvalueArray = defaultvalue.Split(' ');
var originalMultiplicationResult = defaultvalueArray.Count() == 2 ? defaultvalueArray.Last() : "0";
var originalCellValue = defaultvalueArray.Count() == 2 ? defaultvalueArray.First() : row.Cells[j].Text.ToString();
if (originalCellValue == previousRow.Cells[j].Text)
{
if (row.Cells[j].Text != " " && result < maxIndex)
{
var Quantity = GridView1.Rows[i].Cells[1].Text;
var GLQuantity = GridView1.Rows[i].Cells[result].Text;
var PreviousQuantity = GridView1.Rows[i - 1].Cells[1].Text;
var PreviousGLQuantity = GridView1.Rows[i - 1].Cells[result].Text;
var GLQ = GLQuantity.TrimEnd(new Char[] { '0' });
var PGLQ = PreviousGLQuantity.TrimEnd(new char[] { '0' });
if (GLQ == "")
{
GLQ = 0.ToString();
}
if (PGLQ == "")
{
PGLQ = 0.ToString();
}
currentCellResult = Convert.ToDecimal(Quantity) * Convert.ToDecimal(GLQ);
MultiplicationResult = currentCellResult + Convert.ToDecimal(PreviousQuantity) * Convert.ToDecimal(PGLQ);
if (row.Cells[j].RowSpan == 0)
{
//DataTable dt = (DataTable)ViewState["dt"];
object o = dt.Rows[i].ItemArray[j] + " " + MultiplicationResult.ToString();
previousRow.Cells[j].Text = o.ToString();
//previousRow.Cells[j].Text = previousRow.Cells[j].Text.Split("");
}
else
{
//DataTable dt = (DataTable)ViewState["dt"];
var t = Convert.ToDecimal(originalMultiplicationResult) - Convert.ToDecimal(currentCellResult) + MultiplicationResult;
object o = dt.Rows[i].ItemArray[j] + " " + t.ToString();
previousRow.Cells[j].Text = o.ToString();
//previousRow.Cells[j].Text.Replace("\n", "<br>");
}
result++;
}
else
result++;
if (previousRow.Cells[j].RowSpan == 0)
{
if (row.Cells[j].RowSpan == 0)
{
previousRow.Cells[j].RowSpan += 2;
}
else
{
previousRow.Cells[j].RowSpan = row.Cells[j].RowSpan + 1;
}
row.Cells[j].Visible = false;
}
}
else
result++;
}
}
}

How to group and name series chart in visual studio c#

I have DataGridView which consist of these data
From these data i would like to make the first column, airport name to group the third column and sum to their corresponding ActLoadQuantityTo which is in the fifth column, the cargo type which landed on the airport. right now my chart is messed up as it look like this
for (int j = 0; j < dgv_3.Rows.Count; j++)
{
double Load_qty = 0;
double new_load_qty = 0;
DiscPort = dgv_3.Rows[j].Cells["ActDiscDischargingPort"].Value.ToString();
DestType = dgv_3.Rows[j].Cells["SchLoadDestination"].Value.ToString();
CargoType = dgv_3.Rows[j].Cells["SchLoadCargoType"].Value.ToString();
string CargoType2 = "Series-" + CargoType;
Load_qty = Convert.ToDouble(dgv_3.Rows[j].Cells["ActLoadQuantityTon"].Value);
if (chart3.Series.IndexOf(DiscPort) != -1)
{
chart3.Series["000 - Port"].Points.AddY(Load_qty);
}
else
{
chart3.Series["000 - Port"].Points.AddXY(DiscPort, Load_qty);
}
}
no grouping of series,etc. i've tried adding more series but it just doesn't make sense toward the DataGridView. and my expectation is that i would like the chart to look like this as I've described before
Any idea what set of code should it be?
I found my desired result by using this code
public void isichartdomestic(System.Data.DataTable initialDataSource)
{
chart3.Titles.Add("Your title");
chart3.Legends.Add("Your Legend");
for (int i = 1; i < initialDataSource.Columns.Count; i++)
{
System.Windows.Forms.DataVisualization.Charting.Series series = new System.Windows.Forms.DataVisualization.Charting.Series();
foreach (DataRow dr in initialDataSource.Rows)
{
double y = (double)dr[i];
series.Points.AddXY(dr["DiscPort"].ToString(), y);
TotalDomestic += y;
}
chart3.Series.Add(series);
string NamaSeries = series.ToString();
NamaSeries = NamaSeries.Replace("Series-","");
chart3.Series[NamaSeries].IsValueShownAsLabel = true;
chart3.Series[NamaSeries].IsVisibleInLegend = true;
if (NamaSeries == "Series1")
{
chart3.Series[NamaSeries].LegendText = "Bag";
}
else if (NamaSeries == "Series2")
{
chart3.Series[NamaSeries].LegendText = "Bulk";
}
else if (NamaSeries == "Series3")
{
chart3.Series[NamaSeries].LegendText = "Clinker";
}
else if (NamaSeries == "Series4")
{
chart3.Series[NamaSeries].LegendText = "Container";
}
}
lb_TotalDomestic.Text = Convert.ToString("Total Domestic: " + TotalDomestic);
TotalDomesticExport += TotalDomestic;
}

Dates being flipped through inter op excel

I am having a strange issue with dates in excel at present some dates when exported from my grid while displaying file are swapping the month and days however I used the number format to account for this but still some items seems to have an issue.
private static void ExportToExcel(List<ListViewItem> items, ListView listView)
{
using (var progressIndicatorForm = new ProgressIndicatorForm(0, items.Count))
{
try
{
progressIndicatorForm.Show();
System.Windows.Forms.Application.DoEvents();
Microsoft.Office.Interop.Excel.Application app = null;
Microsoft.Office.Interop.Excel.Workbook workBook = null;
Microsoft.Office.Interop.Excel.Worksheet workSheet = null;
try
{
app = new Microsoft.Office.Interop.Excel.Application();
workBook = app.Workbooks.Add(1);
workSheet = (Microsoft.Office.Interop.Excel.Worksheet)workBook.Worksheets[1];
List<string> columnNames = GetColumnNames(listView);
for (int columnIndex = 0; columnIndex < columnNames.Count; columnIndex++)
{
workSheet.Cells[0 + 1, columnIndex + 1] = columnNames[columnIndex];
}
for (int rowIndex = 1; rowIndex <= items.Count; rowIndex++)
{
progressIndicatorForm.Current = rowIndex;
progressIndicatorForm.Description = string.Format("Exporting {0} of {1} records...", rowIndex, items.Count);
System.Windows.Forms.Application.DoEvents();
var item = items[rowIndex - 1];
for (var columnIndex = 0; columnIndex < listView.Columns.Count; columnIndex++)
{
var column = listView.Columns[columnIndex];
if (column.Tag != null && column.Tag.ToString() == typeof(DateTime).ToString())
{
string text = item.SubItems[columnIndex].Text;
DateTime? dateTime = ParseDateTime(text);
if (dateTime.HasValue)
{
Range range = (Range)workSheet.Cells[rowIndex + 1, columnIndex + 1];
range.Value = dateTime.Value.ToOADate();
range.NumberFormat = "dd/MM/yyyy";
}
else
{
workSheet.Cells[rowIndex + 1, columnIndex + 1] = text;
}
}
else
{
workSheet.Cells[rowIndex + 1, columnIndex + 1] = item.SubItems[columnIndex].Text;
}
}
}
app.Visible = true;
}
catch (Exception ex)
{
ExceptionManager.HandleUnexpectedException(ex);
}
finally
{
app = null;
workBook = null;
workSheet = null;
}
}
catch (Exception ex)
{
ExceptionManager.HandleUnexpectedException(ex);
}
finally
{
progressIndicatorForm.Close();
}
}
}
As you see I am using the following which is the suggested method for the dd/mm/yyyy
range.NumberFormat = "dd/MM/yyyy";

Collapsing the space between bars on a StackedBar100 in MSChart

Essentially I have to show rows of bars on a stacked bar chart. There will be one for each question. Optionally there will be an extra bar or two for each question if there's a National score or a Competitor score is available.
My issue is one of presentation. I wish to place the bars central relative to the label for the question or remove gaps if one of the national or competitor scores isn't present.
Perhaps a picture will help:
I put together an example quickly (that generated the above picture) into an MVC project. These are the files:
Index.cshtml
<h2>Attempt 2</h2>
<img src="/Home/StackedBar100" />
<h2>Attempt 1</h2>
<img src="/Home/StackedBar100_FirstAttempt" />
HomeController.cs
<!-- language: c# -->
public class HomeController : Controller
{
List<Color> colors = new List<Color>();
string[] rows = new string[] { "Q1", "Q2", "Q3", "Q4" };
string[] stackTypes = new string[] { "National", "Value", "Competitor" };
Color[] stackColors = new Color[] { Color.White, Color.Green, Color.Orange };
protected override void Initialize(RequestContext requestContext)
{
// Set up bands of colours for testing purposes.
int diff = (255 - 20) / 10;
for (int c = 10; c > 0; c--)
{
colors.Add(Color.FromArgb(0, (c * diff) + 10, 0));
}
base.Initialize(requestContext);
}
public ActionResult Index()
{
return View();
}
public ActionResult StackedBar100()
{
var chart = new Chart();
var chartArea = new ChartArea("Default");
chart.ChartAreas.Add(chartArea);
chart.Width = 640;
chart.Height = 480;
var r = new Random();
for (int s = 0; s < stackTypes.Count(); s++)
{
var stack = stackTypes[s];
var stackColor = stackColors[s];
{
for (int i = 1; i <= 10; i++)
{
var series = new Series(stack + i.ToString());
series.ChartType = SeriesChartType.StackedBar100;
series.Color = colors[i - 1];
series.BorderColor = stackColor;
series["StackedGroupName"] = stack;
series["DrawSideBySide"] = "true";
series.IsValueShownAsLabel = true;
series.LabelForeColor = Color.White;
chart.Series.Add(series);
}
}
}
var dt = CreateData();
foreach (DataRow row in dt.Rows)
{
var question = row["Question"];
var stack = row["Stack"];
var hidden = Convert.ToBoolean(row["Hidden"]);
var ks = "";
for (int k = 1; k <= 10; k++)
{
ks = k.ToString();
chart.Series[stack + ks].Points.AddXY(question, row[ks]);
if (hidden)
{
chart.Series[stack + ks].Points.Last().IsEmpty = true;
}
else if ((row[ks] as double?) < 3)
{
chart.Series[stack + ks].Points.Last().IsValueShownAsLabel = false;
}
}
}
return ReturnChartAsImage(chart);
}
private DataTable CreateData()
{
var r = new Random();
var dt = new DataTable("Chart Data");
dt.Columns.Add("Question", typeof(string));
dt.Columns.Add("Stack", typeof(string));
dt.Columns.Add("Hidden", typeof(string));
for (int i = 1; i <= 10; i++)
{
dt.Columns.Add(i.ToString(), typeof(double));
}
foreach (var row in rows.OrderByDescending(rw => rw))
{
foreach (var stack in stackTypes)
{
if (
(stack == "Value") && row != "Q4" ||
(stack == "National" && (row == "Q2" || row == "Q4")) ||
(stack == "Competitor" && (row == "Q3" || row == "Q4")))
{
var dr = dt.NewRow();
dr["Question"] = row;
dr["Hidden"] = false;
dr["Stack"] = stack;
for (int k = 1; k <= 10; k++)
{
dr[k.ToString()] = r.NextDouble() * 10;
}
dt.Rows.Add(dr);
}
else
{
var dr = dt.NewRow();
dr["Question"] = row;
dr["Stack"] = stack;
dr["Hidden"] = true;
dt.Rows.Add(dr);
}
}
}
dt.WriteXml(#"c:\Users\chris_000\Desktop\1.xml");
return dt;
}
public ActionResult StackedBar100_FirstAttempt()
{
var chart = new Chart();
var chartArea = new ChartArea("Default");
chart.ChartAreas.Add(chartArea);
chart.Width = 640;
chart.Height = 480;
for (int i = 1; i <= 30; i++)
{
var series = new Series("Series" + i.ToString());
series.ChartType = SeriesChartType.StackedBar100;
series.Color = colors[(i - 1) % 10];
if (i <= 10)
{
series["StackedGroupName"] = "Value";
}
else if (i > 10 && i <= 20)
{
series["StackedGroupName"] = "National";
series.BorderColor = Color.Green;
}
else
{
series["StackedGroupName"] = "Competitor";
series.BorderColor = Color.Orange;
}
chart.Series.Add(series);
}
var dt = CreateData_FirstAttempt();
foreach (DataRow row in dt.Rows)
{
var question = row["Question"];
var group = row["Stack"];
for (int k = 1; k <= 30; k++)
{
chart.Series["Series" + k.ToString()].Points.AddXY(question, row[k.ToString()]);
}
}
return ReturnChartAsImage(chart);
}
private DataTable CreateData_FirstAttempt()
{
var r = new Random();
var dt = new DataTable("Chart Data");
dt.Columns.Add("Question", typeof(string));
dt.Columns.Add("Stack", typeof(string)); // Value, National, Competitor
for (int i = 1; i <= 30; i++)
{
dt.Columns.Add(i.ToString(), typeof(double));
}
foreach (var row in rows.OrderByDescending(rw => rw))
{
var dr = dt.NewRow();
dr["Question"] = row;
dr["Stack"] = "Score";
for (int k = 1; k <= 30; k++)
{
if (k <= 10)
{
if (row != "Q4")
{
dr[k.ToString()] = r.NextDouble() * 100;
}
else
{
dr[k.ToString()] = DBNull.Value;
}
}
else if (k > 10 && k <= 20)
{
if (row == "Q2" || row == "Q4")
{
dr[k.ToString()] = r.NextDouble();
}
else
{
dr[k.ToString()] = DBNull.Value;
}
}
else
{
if (row == "Q3" || row == "Q4")
{
dr[k.ToString()] = r.NextDouble();
}
else
{
dr[k.ToString()] = DBNull.Value;
}
}
}
dt.Rows.Add(dr);
}
return dt;
}
private ActionResult ReturnChartAsImage(Chart chart)
{
MemoryStream ms = new MemoryStream();
chart.SaveImage(ms, ChartImageFormat.Png);
return File(ms.ToArray(), "image/png");
}
}
That's a long example, but shows two different attempts at building multiple bars on a stacked chart. One using 30 columns, but splitting every 10 for each group. The second (more sensible) naming the stacks after the Value, National or Competitor they're supposed to represent.
So, in short, can I collapse the space occupied but the missing series/bars? Is it the way I'm feeding the data in perhaps?
Thanks.

Categories