Проблема с выводом Charts на WPF C#

Рейтинг: 0Ответов: 3Опубликовано: 28.05.2023

Я собираюсь вывести диаграмму с использованием библиотеки LiveCharts. Нужно сделать так, чтоб на каждый месяц выводилось по три столбца с местами: первое, второе, третье - по вертикали должно отображаться количество занятых мест в месяце, по горизонтали - месяца. В легенде должные отображаться цветовые значения этих мест на диаграмме. Вот код разметки:

<Page x:Class="SportCompetitions.Pages.ClientPages.Results.StatMonthPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:SportCompetitions.Pages.ClientPages.Results" xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
      mc:Ignorable="d" 
      d:DesignHeight="485" d:DesignWidth="680" Loaded="Page_Loaded">
 
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <TextBlock Text="Ваша статистика по занимаемым местам" 
                   Foreground="White" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <lvc:CartesianChart Series="{Binding SeriesCollection}" LegendLocation="Top"
                            x:Name="StatisticsChart" Grid.Row="1" Margin="50">
            <lvc:CartesianChart.AxisX>
                <lvc:Axis Title="Месяцы" Labels="{Binding monthLabel}"/>
            </lvc:CartesianChart.AxisX>
            <lvc:CartesianChart.AxisY>
                <lvc:Axis Title="Количество мест" Labels="{Binding placeValue}"/>
            </lvc:CartesianChart.AxisY>
        </lvc:CartesianChart>
        <Button Content="Назад" Width="250" Grid.Row="2"
                                Height="40" Style="{StaticResource ButtonStyle}" Click="BackButton_Click"/>
        <Button Content="←" Width="40" Grid.Row="1" HorizontalAlignment="Left" Margin="10,0,0,0"
                                Height="40" Style="{StaticResource ButtonStyle}" Click="PrewButton_Click"/>
    </Grid>
</Page>

А далее сама реализация функционала:


    namespace SportCompetitions.Pages.ClientPages.Results
    {
        public partial class StatMonthPage : Page
        {
            DB_SportCompetitsEntities db = new DB_SportCompetitsEntities();
            User user;
            public StatMonthPage(User us)
            {
                InitializeComponent();
                user = us;
            }
     
            private void PrewButton_Click(object sender, RoutedEventArgs e)
            {
     
            }
     
            private void BackButton_Click(object sender, RoutedEventArgs e)
            {
                NavigationService.GoBack();
            }
     
            private void Page_Loaded(object sender, RoutedEventArgs e)
            {
                var placeList = db.ResultReg.Where(u => u.RegEvent.ID_User == user.ID_User && u.TopEvent != null).GroupBy(t =>  new { t.TopEvent, t.RegEvent.Event.DateEnd.Month })
    .Select(r => new { TopName = r.Key, Count = r.Select(grouped => grouped.ID_RegEvent).Distinct().Count()}).ToList();
                SeriesCollection monthList1 = new SeriesCollection();
                monthLabel = new[] { "Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек" };
     
                foreach (var item in placeList)
                {
                    monthList1.Add(new ColumnSeries
                    {
                        Title = string.Format("{0} место", item.TopName.TopEvent.ToString()),
                        Values = new ChartValues<int> { item.Count }
                    });
                }
                StatisticsChart.Series = monthList1;
                StatisticsChart.LegendLocation = LegendLocation.Top;
                StatisticsChart.ChartLegend.Foreground = Brushes.White;
                StatisticsChart.ChartLegend.FontSize = 14;
                StatisticsChart.ChartLegend.ContentStringFormat = string.Format("{0} место", StatisticsChart.ChartLegend.Content);
                placeValue = value => value.ToString("N");
                DataContext = this;
     
            }
            public SeriesCollection[] SeriesCollection { get; set; }
            public string[] monthLabel { get; set; }
            public Func<double, string> placeValue { get; set; }
        }
    }

Далее я прикрепляю фотографию того, что у меня выводится. Проблема в том, что я не могу отобразить места в нужные месяцы. По запросу я, так понимаю, получаю корректные данные, потому как первое место, находящееся в одном месяце не объединяется в количество с другим. Помогите, пожалуйста, решить эту проблему, я уже пятый день сижу над этим

введите сюда описание изображения

Ответы

▲ 0Принят

Проблема решена:

            var placeList1 = db.ResultReg.Where(u => u.RegEvent.ID_User == user.ID_User && u.TopEvent == 1).GroupBy(t => new { t.TopEvent, t.RegEvent.Event.DateEnd.Month })
.Select(r => new { TopName = r.Key.TopEvent, Count = r.Select(grouped => grouped.ID_RegEvent).Distinct().Count(), Month = r.Select(grouped => grouped.RegEvent.Event.DateEnd.Month).FirstOrDefault() }).ToList();
            var placeList2 = db.ResultReg.Where(u => u.RegEvent.ID_User == user.ID_User && u.TopEvent == 2).GroupBy(t => new { t.TopEvent, t.RegEvent.Event.DateEnd.Month })
.Select(r => new { TopName = r.Key.TopEvent, Count = r.Select(grouped => grouped.ID_RegEvent).Distinct().Count(), Month = r.Select(grouped => grouped.RegEvent.Event.DateEnd.Month).FirstOrDefault() }).ToList();
            var placeList3 = db.ResultReg.Where(u => u.RegEvent.ID_User == user.ID_User && u.TopEvent == 3).GroupBy(t => new { t.TopEvent, t.RegEvent.Event.DateEnd.Month })
.Select(r => new { TopName = r.Key.TopEvent, Count = r.Select(grouped => grouped.ID_RegEvent).Distinct().Count(), Month = r.Select(grouped => grouped.RegEvent.Event.DateEnd.Month).FirstOrDefault() }).ToList();
int[] fp = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            int[] sp = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            int[] tp = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            for (int m = 1; m <= 12; m++)
            {
                if (placeList1.Where(u => u.Month == m).Select(c => c.Count).FirstOrDefault() != 0 && placeList1.Where(u => u.Month == m).Select(c => c.Count).FirstOrDefault() != default)
                    fp[m - 1] = placeList1.Where(u => u.Month == m).Select(c => c.Count).FirstOrDefault();
                if (placeList2.Where(u => u.Month == m).Select(c => c.Count).FirstOrDefault() != 0 && placeList2.Where(u => u.Month == m).Select(c => c.Count).FirstOrDefault() != default)
                    sp[m - 1] = placeList2.Where(u => u.Month == m).Select(c => c.Count).FirstOrDefault();
                if (placeList3.Where(u => u.Month == m).Select(c => c.Count).FirstOrDefault() != 0 && placeList3.Where(u => u.Month == m).Select(c => c.Count).FirstOrDefault() != default)
                    tp[m - 1] = placeList3.Where(u => u.Month == m).Select(c => c.Count).FirstOrDefault();
            }
                monthList.Add(new ColumnSeries
                {
                    Title = "1 место",
                    Values = fp.AsChartValues(),
                });
                monthList.Add(new ColumnSeries
                {
                    Title = "2 место",
                    Values = sp.AsChartValues(),
                });
                monthList.Add(new ColumnSeries
                {
                    Title = "3 место",
                    Values = tp.AsChartValues(),
                });

введите сюда описание изображения

▲ 1

"По запросу я, так понимаю, получаю корректные данные" - вот это совсем не факт и начать нужно именно с этого. Запрос должен возвращать список структур месяц, место, количество. Или, лучше: месяц, кол-во первых мест, кол-во вторых мест, кол-во третьих мест. Я такого не вижу. Надо подумать над запросом.

Вот пример:

using System;
using System.Linq;
using System.Collections.Generic;
namespace UserPositionReportSolution {
    class ResultReg {
        // имитация данных пользователя
        // RegEvent.ID_User -> UserID
        // RegEvent.Event.DateEnd.Month -> Month
        // TopEvent -> Position
        public ResultReg(int i, int m, int p) { UserID = i; Month = m; Position = p; }
        public int UserID { get; set; }
        public int Month { get; set; }
        public int Position { get; set; }
    }
    class MonthResult {
        public MonthResult(string m) { Month = m; First = Second = Third = 0; }
        public string Month { get; set; }
        public int First { get; set; }
        public int Second { get; set; }
        public int Third { get; set; }
    }
    class UserPositionReport {
        static void Main() {
            // набор случайных данных для тестирования
            var ResultRegs = new List<ResultReg>() { new ResultReg(4, 4, 2),
                new ResultReg(1, 2, 2),
                new ResultReg(3, 5, 2),
                new ResultReg(0, 3, 1),
                new ResultReg(4, 7, 3),
                new ResultReg(2, 1, 3),
                new ResultReg(4, 5, 3),
                new ResultReg(3, 9, 1),
                new ResultReg(3, 8, 2),
                new ResultReg(2, 1, 1),
                new ResultReg(4, 5, 2),
                new ResultReg(5, 10, 2),
                new ResultReg(2, 2, 2),
                new ResultReg(2, 1, 1),
                new ResultReg(1, 10, 1),
                new ResultReg(5, 5, 2),
                new ResultReg(1, 11, 3),
                new ResultReg(4, 1, 2),
                new ResultReg(2, 5, 3),
                new ResultReg(5, 2, 1),
                new ResultReg(2, 2, 1),
                new ResultReg(1, 8, 3),
                new ResultReg(4, 12, 1),
                new ResultReg(0, 10, 1),
                new ResultReg(3, 3, 2),
                new ResultReg(2, 7, 1),
                new ResultReg(4, 9, 2),
                new ResultReg(3, 7, 2),
                new ResultReg(3, 4, 2),
                new ResultReg(3, 8, 3),
                new ResultReg(4, 4, 2),
                new ResultReg(0, 1, 2),
                new ResultReg(2, 6, 2),
                new ResultReg(1, 4, 1),
                new ResultReg(3, 2, 2),
                new ResultReg(3, 11, 3),
                new ResultReg(1, 4, 3),
                new ResultReg(2, 6, 3),
                new ResultReg(1, 10, 1),
                new ResultReg(2, 3, 3),
                new ResultReg(5, 4, 2),
                new ResultReg(2, 9, 1),
                new ResultReg(3, 3, 2),
                new ResultReg(2, 3, 3),
                new ResultReg(1, 6, 2),
                new ResultReg(4, 5, 2),
                new ResultReg(4, 7, 1),
                new ResultReg(3, 11, 1),
                new ResultReg(3, 4, 3),
                new ResultReg(1, 2, 3) };
            int selecteduser = 3; // для примера пользователь с ID 3
            // месяц, кол-во первых мест, кол-во вторых мест, кол-во третьих мест
            var placeList = ResultRegs.Where(w => w.UserID == selecteduser)
                .GroupBy(g => g.Month, g => g.Position,
                    (m, p) => new { Month = m - 1, First = p.Count(c => c == 1),
                        Second = p.Count(c => c == 2), Third = p.Count(c => c == 3) })
                .ToList();
            var monthresults = Array.ConvertAll(new[] { "Янв", "Фев", "Мар", "Апр",
                "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек" },
                ml => new MonthResult(ml));
            foreach (var pl in placeList) {
                monthresults[pl.Month].First = pl.First;
                monthresults[pl.Month].Second = pl.Second;
                monthresults[pl.Month].Third = pl.Third;
            }
            // вывод результата на консоль
            foreach (var item in monthresults) 
                Console.WriteLine("{0}\t{1}\t{2}\t{3}",
                    item.Month, item.First, item.Second, item.Third);
            // и, если нужно, результаты раздельно:
            var axisx = Array.ConvertAll(monthresults, mr => mr.Month);
            var Series1 = Array.ConvertAll(monthresults, mr => mr.First);
            var Series2 = Array.ConvertAll(monthresults, mr => mr.Second);
            var Series3 = Array.ConvertAll(monthresults, mr => mr.Third);
        }
    }
}       

Здесь запрос возвращает структуру: месяц, кол-во первых мест, кол-во вторых мест, кол-во третьих мест.

По результату построил диаграмму в Excel: введите сюда описание изображения

Не знаю библиотеку LiveCharts, но принципы построения диаграмм должны быть схожи. Month - это категория (ось X), а First, Second и Third - серии данных

▲ 0

Как я понял, моя самая большая ошибка в том, что в строчку Values я записывал одно значение. Кто-нибудь может подсказать как реализовать проверку месяца?

                var placeList1 = db.ResultReg.Where(u => u.RegEvent.ID_User == user.ID_User && u.TopEvent == 1).GroupBy(t => new { t.TopEvent, t.RegEvent.Event.DateEnd.Month })
.Select(r => new { TopName = r.Key.TopEvent, Count = r.Select(grouped => grouped.ID_RegEvent).Distinct().Count(), Month = r.Select(grouped => grouped.RegEvent.Event.DateEnd) }).ToList();
            var placeList2 = db.ResultReg.Where(u => u.RegEvent.ID_User == user.ID_User && u.TopEvent == 2).GroupBy(t => new { t.TopEvent, t.RegEvent.Event.DateEnd.Month })
.Select(r => new { TopName = r.Key.TopEvent, Count = r.Select(grouped => grouped.ID_RegEvent).Distinct().Count(), Month = r.Select(grouped => grouped.RegEvent.Event.DateEnd) }).ToList();
            var placeList3 = db.ResultReg.Where(u => u.RegEvent.ID_User == user.ID_User && u.TopEvent == 3).GroupBy(t => new { t.TopEvent, t.RegEvent.Event.DateEnd.Month })
.Select(r => new { TopName = r.Key.TopEvent, Count = r.Select(grouped => grouped.ID_RegEvent).Distinct().Count(), Month = r.Select(grouped => grouped.RegEvent.Event.DateEnd) }).ToList();
foreach (var item in placeList1)
            {
                    monthList1.Add(new ColumnSeries
                    {
                        Title = string.Format("{0} место", item.TopName.ToString()),
                        Values = new ChartValues<int> { item.Count }
                    });
            }
            foreach (var item in placeList2)
            {
                    monthList1.Add(new ColumnSeries
                    {
                        Title = string.Format("{0} место", item.TopName.ToString()),
                        Values = new ChartValues<int> { item.Count }
                    });
            }
            foreach (var item in placeList3)
            {
                    monthList1.Add(new ColumnSeries
                    {
                        Title = string.Format("{0} место", item.TopName.ToString()),
                        Values = new ChartValues<int> { item.Count }
                    });
            }