Создание горизонтального DataGrid в WPF для графика работы
Я пытаюсь создать горизонтальный датагрид чтобы слева был сотрудник и сверху 30 дней месяца. На пересечении должен быть статус работы (либо "Р", либо "Н"). Если запись для дня месяца найдена в БД, то ставить "Р", если не найдена, то "Н". Также есть проблема со списком сотрудников - я вывожу таблицу из БД в List и поскольку в БД при заполнении графика создаётся множество записей для каждого дня, то слева получается много строк с одним и тем же сотрудником (но при этом мне нужны данные из таблицы для проверки даты).
Я запутался и вот что сделано:
namespace PlanningScheduleApp
{
public partial class DataGridTestWindow : Window
{
public string connectionString = "";
List<StaffModel> StaffList = new List<StaffModel>();
DepModel SelectedDep = new DepModel();
StaffModel SelectedStaff { get; set; }
public DataGridTestWindow(DepModel selectedDep)
{
InitializeComponent();
SelectedDep = selectedDep;
StaffList = Odb.db.Database.SqlQuery<StaffModel>("SELECT DISTINCT a.ID_Schedule, a.STAFF_ID, LTRIM(e.TABEL_ID) as TABEL_ID, e.SHORT_FIO, a.WorkBegin, a.WorkEnd, a.DTA, a.LunchTimeBegin, a.LunchTimeEnd, a.WorkingHours, b.ID_Absence, c.Cause as CauseAbsence, b.DateBegin, b.DateEnd, b.TimeBegin, b.TimeEnd FROM [Zarplats].[dbo].[Staff_Schedule] as a left join Zarplats.dbo.Schedule_Absence as b on a.STAFF_ID = b.id_Staff and a.DTA between b.DateBegin and b.DateEnd left join Zarplats.dbo.AbsenceRef as c on b.AbsenceRef_ID = c.ID_AbsenceRef left join perco...staff as e on a.STAFF_ID = e.ID_STAFF left join Zarplats.dbo.StaffView as f on a.STAFF_ID = f.STAFF_ID where f.Position = @podrazd order by a.DTA", new SqlParameter("podrazd", SelectedDep.Position)).ToList();
GenerateColumns();
FillDTAStatus();
StaffDGTest.ItemsSource = StaffList;
}
DateTime selectedMonth = new DateTime(2023, 11, 1);
private void GenerateColumns()
{
List<DateTime> datesInMonth = GetDatesForMonth(selectedMonth);
for (int i = 0; i < datesInMonth.Count; i++)
{
DataGridTemplateColumn column = new DataGridTemplateColumn
{
Header = datesInMonth[i].Day.ToString(),
Width = DataGridLength.Auto,
CellTemplate = FindResource("DayColumnTemplate") as DataTemplate,
};
StaffDGTest.Columns.Add(column);
}
}
private List<DateTime> GetDatesForMonth(DateTime month)
{
List<DateTime> datesInMonth = new List<DateTime>();
DateTime firstDayOfMonth = new DateTime(month.Year, month.Month, 1);
DateTime lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
for (DateTime date = firstDayOfMonth; date <= lastDayOfMonth; date = date.AddDays(1))
{
datesInMonth.Add(date);
}
return datesInMonth;
}
public void FillDTAStatus()
{
var datesInMonth = GetDatesForMonth(selectedMonth);
foreach (var staff in StaffList)
{
staff.DTAStatusList = new List<StatusInfo>();
for (int i = 0; i < datesInMonth.Count; i++)
{
bool hasRecord = CheckRecordInDatabase(staff.STAFF_ID, datesInMonth[i]);
Console.WriteLine($"---\nhasRecord for {staff.STAFF_ID} {datesInMonth[i].Date}: {hasRecord}");
StatusInfo status = new StatusInfo { Date = datesInMonth[i], Status = hasRecord ? "Р" : "Н" };
staff.DTAStatusList.Add(status);
}
}
}
private bool CheckRecordInDatabase(int staffId, DateTime date)
{
string query = "SELECT COUNT(*) FROM Zarplats.dbo.Staff_Schedule WHERE STAFF_ID = @staffId AND DTA = @date";
int recordCount = Odb.db.Database.SqlQuery<int>(query,
new SqlParameter("staffId", staffId),
new SqlParameter("date", date)).FirstOrDefault();
return recordCount > 0;
}
private void StaffDGTest_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
SelectedStaff = (StaffModel)StaffDGTest.SelectedItem;
MessageBox.Show($"SelectedStaff Info: \nFIO: {SelectedStaff.SHORT_FIO}\nDTAWork: {SelectedStaff.DTA}\nWorkStatus: {SelectedStaff.WorkStatus}");
}
}
}
<Window x:Class="PlanningScheduleApp.DataGridTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PlanningScheduleApp"
xmlns:models="clr-namespace:PlanningScheduleApp.Models"
xmlns:converters="clr-namespace:PlanningScheduleApp.Converters"
mc:Ignorable="d"
Title="DataGridTestWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Key="DayColumnTemplate">
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource MultiDayStatusConverter}">
<Binding Path="DTA" />
<Binding Path="DTAStatusList" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</Window.Resources>
<Grid>
<DataGrid x:Name="StaffDGTest" AutoGenerateColumns="False" MouseDoubleClick="StaffDGTest_MouseDoubleClick">
<DataGrid.Columns>
<DataGridTextColumn Header="Сотрудники" Binding="{Binding SHORT_FIO}"/>
<DataGridTemplateColumn Header="Статус работы" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding WorkStatus}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Добавление столбцов для каждого дня в месяце -->
<DataGridTemplateColumn Header="Дни" Width="*" CellTemplate="{StaticResource DayColumnTemplate}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
MultiDayStatusConverter.cs
namespace PlanningScheduleApp.Converters
{
public class MultiDayStatusConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 2 || !(values[0] is DateTime) || !(values[1] is List<StatusInfo>))
return string.Empty;
DateTime date = (DateTime)values[0];
List<StatusInfo> statusList = (List<StatusInfo>)values[1];
var statusForDate = statusList.FirstOrDefault(s => s.Date == date);
return statusForDate != null ? statusForDate.Status : "Н";
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
StaffModel
public class StaffModel
{
public int ID_Schedule { get; set; }
public int STAFF_ID { get; set; }
public string TABEL_ID { get; set; }
public string SHORT_FIO { get; set; }
public string WorkBegin { get; set; }
public string WorkEnd { get; set; }
public string LunchTimeBegin { get; set; }
public string LunchTimeEnd { get; set; }
public DateTime DTA { get; set; }
public double? WorkingHours { get; set; }
public string Position { get; set; }
public List<StatusInfo> DTAStatusList { get; set; } = new List<StatusInfo>();
public string WorkStatus
{
get
{
return DTAStatusList.Count > 0 ? DTAStatusList[3].Status : "-";
}
}
}
public class StatusInfo
{
public DateTime Date { get; set; }
public string Status { get; set; } = "Н"; // По умолчанию статус "Н"
}
