Одним из самых сложных в проектировании приложений Windows является визуализация данных в виде графиков. Такой способ бывает иногда предпочтительней, например, Microsoft Power BI. В чем преимущество.
- Во первых, увеличивается скорость вывода информации, не надо ждать когда загрузится отчет
- Во вторых, абсолютно разные отчеты можно связать через собственное меню
- В третьих, передать в процедуру базу данных много параметров, придумав нестандартные фильтры данных.
- В четвертых, убрать лишние объекты из меню, если сравнивать с Power BI
Вот, например, как выглядит форма по объему продаж за Год и Месяц
Следующая форма по анализу предприятия, а именно, "Отчет АВС анализ" показывает, что основную прибыль предприятию приносит Группа товаров А, на нее приходится 80% продаж. Для усиления отчета добавлена таблица с характеристиками фильтрации в Excel (смотрите заголовки, они представляют из себя списки для фильтрации и сортировки). Таким образом, изменяя таблицу или вид графика мы можем получить разный вариант визуализации по продажам и принять решение об улучшении торговли. Например, увеличить производство товаров Группы А, а С уменьшить. Надо понимать, что на продажи влияет маркетинг, сезонность распродаж, активность менеджеров (МАП) и много других факторов, которые можно разместить на графике.
У такой системы проектирования - есть недостатки. Это скорость проектирования таких форм на C#, но если проектировать не формы, а контрол-элементы (UserControl), то можно нивелировать это недостаток. Например, такие объекты выглядят в Visual Studio 2019 так.
Часть кода на C# показана ниже. Обратите внимание на настройку графиков, использование библиотеки linkq, которая позволяет делать запросы типа SQL внутри языка C#, а также создание промежуточной таблицы DataTable. Она связана с GridView и является основным источником данных для графика.
protected void LoadChartRes()
{
try
{
DataTable dt = GetDataFromGrid();
int n = Convert.ToInt32(comboBoxMaxCount.Text);
string[] x = (from p in dt.AsEnumerable()
select "Группа " + p.Field<string>("Группа ABC")).Take(n).ToArray();
Decimal[] y1 = (from p in dt.AsEnumerable()
select p.Field<Decimal>("Сумма_ALL")).Take(n).ToArray();
Decimal[] y2 = (from p in dt.AsEnumerable()
select p.Field<Decimal>("Кол_ALL")).Take(n).ToArray();
ChartRes.Series[0].IsValueShownAsLabel = true;
ChartRes.Series[0].Points.DataBindXY(x, y1);
ChartRes.Series[0].LabelForeColor = Color.DarkGreen;
ChartRes.Series[0].LabelFormat = "{### ### ### ##0} руб.";
ChartRes.Series[0].Font = new System.Drawing.Font("Ariel", 14f);
ChartRes.ChartAreas[0].AxisX.LabelStyle.Font = new System.Drawing.Font("Ariel", 14f); // По оси Y
ChartRes.ChartAreas[0].AxisY.LabelStyle.Format = "{### ### ### ##0}";
ChartRes.Series[1].IsValueShownAsLabel = true;
ChartRes.Series[1].Points.DataBindXY(x, y2);
ChartRes.Series[1].LabelForeColor = Color.Blue;
ChartRes.Series[1].LabelFormat = "Кол-во = {### ### ### ##0}";
ChartRes.Series[1].Font = new System.Drawing.Font("Ariel", 12f);
if (ChartRes.Series.Count > 2)
{
ChartRes.Series.RemoveAt(2);
}
// 3D график
ChartRes.ChartAreas[0].Area3DStyle.Enable3D = checkBoxChart3D.Checked;
if (comboBoxChartView.Text == null) comboBoxChartView.Text = "Bar";
SeriesChartType ChartType = SeriesChartType.Bar;
switch (comboBoxChartView.Text)
{
case "Бар":
ChartType = SeriesChartType.Bar;
break;
case "Колонки":
ChartType = SeriesChartType.Column;
break;
case "Сплайн":
ChartType = SeriesChartType.Spline;
break;
case "Площадь":
ChartType = SeriesChartType.Area;
break;
case "Круг":
ChartType = SeriesChartType.Pie;
break;
}
for (int i = 0; i < ChartRes.Series.Count; i++)
{
ChartRes.Series[i].ChartType = ChartType;
}
}
catch (Exception ex)
{
MessageBox.Show("Случилась незапланированная ошибка в расчетах. Измените параметры.\nСистемное сообщение. " + ex.Message, "Построение графика", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private DataTable GetDataFromGrid()
{
// Создаем DataTable.
DataTable dt = new DataTable();
// Добавляем Columns.
foreach (DataGridViewColumn column in userControlGridView1.ucAdvancedDataGridView.Columns)
{
dt.Columns.Add(column.HeaderText, column.ValueType);
}
foreach (DataGridViewRow row in userControlGridView1.ucAdvancedDataGridView.Rows)
{
dt.Rows.Add();
foreach (DataGridViewCell cell in row.Cells)
{
dt.Rows[dt.Rows.Count - 1][cell.ColumnIndex] = cell.Value.ToString();
//if(cell.OwningColumn.HeaderText=="Кол-во заказано") cntPlan += Convert.ToDecimal(cell.Value.ToString());
}
}
decimal sum1 = 0;
decimal sum2 = 0;
// Итоги
if (dt.Rows.Count>0)
{
DataTable dt2 = dt.AsEnumerable()
.GroupBy(r => r.Field<string>("Группа ABC"))
.Select(g =>
{
var row = dt.NewRow();
row["Группа ABC"] = g.Key;
row["Сумма"] = g.Sum(r => r.Field<Decimal>("Сумма"));
decimal A1 = g.Sum(r => g.Key == "A" ? r.Field<Decimal>("Сумма") : 0);
decimal B1 = g.Sum(r => g.Key == "B" ? r.Field<Decimal>("Сумма") : 0);
decimal C1 = g.Sum(r => g.Key == "C" ? r.Field<Decimal>("Сумма") : 0);
decimal A2 = g.Sum(r => g.Key == "A" ? r.Field<Decimal>("Кол-во") : 0);
decimal B2 = g.Sum(r => g.Key == "B" ? r.Field<Decimal>("Кол-во") : 0);
decimal C2 = g.Sum(r => g.Key == "C" ? r.Field<Decimal>("Кол-во") : 0);
if (dt.Columns.Contains("Сумма_ALL") ==false)
{
dt.Columns.Add("Сумма_ALL", typeof(System.Decimal));
dt.Columns.Add("Кол_ALL", typeof(System.Decimal));
}
row["Сумма_ALL"] = 0;
row["Кол_ALL"] = 0;
if (A1 != 0)
{
row["Сумма_ALL"] = A1;
row["Кол_ALL"] = A2;
sum1 += A1;
sum2 += A2;
//textBoxGroupA.Text = A1.ToString("c");
}
if (B1 != 0)
{
row["Сумма_ALL"] = B1;
row["Кол_ALL"] = B2;
sum1 += B1;
sum2 += B2;
}
if (C1 != 0)
{
row["Сумма_ALL"] = C1;
row["Кол_ALL"] = C2;
sum1 += C1;
sum2 += C2;
}
textBoxSumma.Text = (sum1).ToString("### ### ### ##0 р\\.");
textBoxQty.Text = (sum2).ToString("### ### ### ##0");
return row;
}).CopyToDataTable();
//}
return dt2;
};
return dt;
}