c# - 使用 WPF Datagrid 生成一年的出勤详细信息 - 最好的方法是什么?

标签 c# wpf

我正在使用下面的代码来获取使用 wpf DataGrid 的员工的年度考勤仪表板详细信息。实际问题是将数据与 wpf datagrid 列绑定(bind)很困惑。我想动态生成所有网格列并绑定(bind)数据放入其中。我的要求是在列标题中显示天数,每行数据的起始位置应基于每月的第一天。为了更清晰,请查找附加图像。

我是否应该为每个列生成模型,例如第一个星期日、第一个星期一以及每周的第五个星期六,以绑定(bind)该列,或者是否有任何其他方法可以轻松完成。 任何帮助将不胜感激。

enter image description here

下面的代码用于生成带有假期详细信息的所有日期和月份名称

   public class DashboardDateDetails
    {
        public bool IsHoliday { get; set; }
        public string DayName { get; set; }
        public string ShortDate { get; set; }
        public DateTime Date { get; set; }
        public string MonthWithYear { get; set; }
        public string ReasonForHoliday { get; set; }
    }

//输入参数 HolidaysList 将保存一年中的假期列表。此方法将返回所选年份从 1 月 1 日到 12 月 31 日的日期和日期以及假期详细信息。

private List<DashboardDateDetails> GetDashBoardData(List<KeyValuePair<string,DateTime>> HolidaysList)
{
    List<DashboardDateDetails> MonthList = new List<DashboardDateDetails>();
    int CurrentYear = DateTime.Now.Year;
    DateTime FirstDateOfYear = new DateTime(CurrentYear,01,01);            
    System.Globalization.CultureInfo Culture = new System.Globalization.CultureInfo("en-US");
    string[] DayNames = Culture.DateTimeFormat.AbbreviatedDayNames;
    string[] MonthNames = Culture.DateTimeFormat.MonthNames;
    string FirstDayNameOfYear = DayNames[(int)FirstDateOfYear.DayOfWeek];
    for (int MonthCount = 1; MonthCount <= 12; MonthCount++)
    {
        int NumberOfDaysInMonth = DateTime.DaysInMonth(CurrentYear, MonthCount);
        for (int DayCount = 1; DayCount <= NumberOfDaysInMonth; DayCount++)
        {                    
            DashboardDateDetails DateDetails = new DashboardDateDetails();
            DateTime CurrentDate = new DateTime(CurrentYear, MonthCount, DayCount);
            DateDetails.DayName = DayNames[(int)CurrentDate.DayOfWeek];
            DateDetails.Date = CurrentDate;
            DateDetails.ShortDate = CurrentDate.ToShortDateString();
            DateDetails.MonthWithYear = MonthNames[(int)CurrentDate.Month - 1];
            if (HolidaysList != null && HolidaysList.Any())
            {
                var HolidayDate = HolidaysList.Where(a => a.Value.ToShortDateString() == CurrentDate.ToShortDateString());
                DateDetails.IsHoliday = HolidayDate != null && HolidayDate.Any();
                DateDetails.ReasonForHoliday = HolidayDate != null && HolidayDate.Count() > 0 ? HolidayDate.First().Key : string.Empty;
            }
            MonthList.Add(DateDetails);
        }
    }
    return MonthList;
}

最佳答案

您好,以下实现与您想要的不完全相同,但我希望它能给您一个想法。我没有继续风格,只是想给您一个逻辑概念。

xaml

 <DataGrid AutoGenerateColumns="False" x:Name="dataGrid" IsReadOnly="True" ItemsSource="{Binding DashboardDates}"/>

xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        //Creat datagrid columns.Can also be done in xaml. but for short i have done in .cs 
        CreateCoulmns();
        DataContext = new ViewModel();
    }

    void CreateCoulmns()
    {
        var converter = new BackGroundConverter();
        for (int i = -1; i < 35; i++)
        {
            DataGridTextColumn dataGridTextColumn = new DataGridTextColumn();

            if (i == -1)
            {
                dataGridTextColumn.Header = "Month / Day";
                dataGridTextColumn.Binding = new Binding("MonthName");
            }
            else
            {
                switch (i % 7)
                {
                    case 0: dataGridTextColumn.Header = "Mo"; break;
                    case 1: dataGridTextColumn.Header = "Tu"; break;
                    case 2: dataGridTextColumn.Header = "We"; break;
                    case 3: dataGridTextColumn.Header = "Th"; break;
                    case 4: dataGridTextColumn.Header = "Fr"; break;
                    case 5: dataGridTextColumn.Header = "Sa"; break;
                    case 6: dataGridTextColumn.Header = "Su"; break;
                }
                dataGridTextColumn.Binding = new Binding(string.Format("Days[{0}].NumericDay", i));

                //Set BackGround property in style and use converter to set background according to HolidayType
                dataGridTextColumn.CellStyle = new Style(typeof(DataGridCell));
                dataGridTextColumn.CellStyle.Setters.Add(
                    new Setter
                    {
                        Property = DataGridCell.BackgroundProperty,
                        Value = new Binding(string.Format("Days[{0}]", i)) { Converter = converter }

                    });
            }
            dataGrid.Columns.Add(dataGridTextColumn);

        }
    }
}

Converter

public class BackGroundConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var day = value as Day;
        if (day != null)
        {
            //Dont use else if Like Saturday can be a restricted holiday so gray needs to be overridden by red.
            if (day.HolidayType == HolidayType.SatOrSun)
                return new SolidColorBrush(Colors.Gray);
            if (day.HolidayType == HolidayType.RestrictedHoliday)
                return new SolidColorBrush(Colors.Red);
            if (day.HolidayType == HolidayType.PublicHoilday)
                return new SolidColorBrush(Colors.Blue);
        }
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Custom Types

public enum HolidayType
{
    None,
    SatOrSun,
    PublicHoilday,
    RestrictedHoliday
}

public class Day
{
    public int? NumericDay { get; set; }

    public HolidayType HolidayType { get; set; }
}

public class DashboardDateDetails
{
    public string MonthName { get; set; }

    public List<Day> Days { get; set; }
}

ViewModel

public class ViewModel
{
    public ViewModel()
    {
        DashboardDates = new List<DashboardDateDetails>();
        GenerateCalendar();
    }
    //This will be binded to ItemsSource
    public List<DashboardDateDetails> DashboardDates { get; set; }

    //Suppose these are Restricted Holidays
    List<DateTime> RestrictedHolidays = new List<DateTime>{
        new DateTime(2014,2,1),
        new DateTime(2014,3,5),
        new DateTime(2014,4,15),
        new DateTime(2014,6,2),
        new DateTime(2014,8,15),
        new DateTime(2014,11,25),
        new DateTime(2014,12,24)
    };

    //Suppose these are Public Holidays
    List<DateTime> PublicHolidays = new List<DateTime>{
        new DateTime(2014,2,1),
        new DateTime(2014,3,15),
        new DateTime(2014,4,19),
        new DateTime(2014,6,20),
        new DateTime(2014,8,11),
        new DateTime(2014,11,12),
        new DateTime(2014,12,25)
    };

    void GenerateCalendar()
    {
        //Lop for 12 months
        for (int month = 1; month <= 12; month++)
        {
            //firstdate for month.This will help to get the first day of month
            var firstdate = new DateTime(2014, month, 1);

            //Get the first date index
            int firstDateIndex = (int)firstdate.DayOfWeek;
            //In DayOfWeek enum first day is Sunday but we want Monday so decrement the index
            firstDateIndex--;

            //Restricted holidays for this month
            var restrictedHolidays = RestrictedHolidays.Where(s => s.Month == month);

            //Public holidays for this month
            var publicHolidays = PublicHolidays.Where(s => s.Month == month);

            //Instance of DashboardDateDetails
            DashboardDateDetails details = new DashboardDateDetails
            {
                MonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(month),
                Days = new Day[40].ToList()  //Create an array of capacity 40
            };

            for (int j = 1; j <= DateTime.DaysInMonth(2014, month); j++)
            {
                int index = 0;

                if (firstDateIndex < 0)
                    index = j - 1;
                else
                    index = j + firstDateIndex - 1;

                var day = new Day { NumericDay = j };
                //is sat or sun
                if (((index % 7) == 6) || ((index % 7) == 5))
                    day.HolidayType = HolidayType.SatOrSun;
                //is restricted holiday
                if (restrictedHolidays.Any(s => s.Day == index))
                    day.HolidayType = HolidayType.RestrictedHoliday;
                //is public holiday
                if (publicHolidays.Any(s => s.Day == index))
                    day.HolidayType = HolidayType.PublicHoilday;

                details.Days[index] = day;
            }

            DashboardDates.Add(details);
        }
    }

}

Output enter image description here

我希望这能帮助你给出一个想法。

关于c# - 使用 WPF Datagrid 生成一年的出勤详细信息 - 最好的方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20870667/

相关文章:

c# - 将文件拖放到列表框中

.net - VMa <-Ma,VMb-> Ma…对…VMa <-VMb-> Ma

wpf - 将样式应用于 ListBoxItem 而不影响内部的 ComboboxItem

c# - 将 View 更新为 WPF 中的数据集

c# - 对于多个属性(键)和作为值的列表来说,最合适的数据类型是什么?

c# - C# 中静态接口(interface)方法的替代方法

c# - 未输出 XmlDocument 前缀

c# - 推断列表初始化是否可能?

C# .Net Write plug-ins for windows live writer 无法加载我的插件

wpf - 为 ContentPresenter 中的所有元素设置样式