使用WPF Datagrid生成一年的考勤详情-最佳方法是什么?

4
我正在使用以下代码通过wpf DataGrid获取员工的年度考勤概览。实际问题是我很困惑如何将数据绑定到wpf datagrid列中。我希望动态生成所有网格列并将数据绑定到其中。我的要求是在列标题中显示日期,并且每行数据的起始位置应基于该月的第一天。请参见附加的图像以获得更多清晰度。
我是否应为每个列生成模型,例如FirstSunday、FirstMonday等,直至星期五的第五个?还是有其他更容易的方法来完成它呢? 非常感谢您的任何帮助。
以下代码用于生成所有日期和月份名称及其假日详情。
   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;
}
1个回答

4

嗨,下面的实现不完全符合您的要求,但我希望它会给您一个想法。我还没有进行样式等操作,只是想给你一个逻辑上的想法。

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);

        }
    }
}

转换器

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();
    }
}

自定义类型

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; }
}

视图模型

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);
        }
    }

}

输出 enter image description here

我希望这些内容可以帮助您了解。


1
感谢您宝贵的解决方案。我在动态绑定方面一直苦苦挣扎,现在有了一个想法。需要更新索引值为 index = j+5 而不是 index = j - 1,以显示在星期天开始的月份。太棒了!!! - Oasis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接