none
Raggruppamento per Settimana con Proprietà DataTime RRS feed

  • Domanda

  • Ciao a tutti,

    Avrei bisogno di fare un raggruppamento settimanale su un DataGrid avendo una collezione con una proprietà DateTime

    Le settimane devono includere anche i giorni che non riguardano il mese selezionato.

    Qualcuno potrebbe darmi qualche suggerimento ?

    Grazie a tutti


    fabio miceli

    lunedì 3 agosto 2020 19:05

Risposte

  • Qui trovi l'esempio di come raggruppare una datagrid.

    Nel tuo caso specifico o ti crei una Proprietà aggiuntaiva WeekOfYear di sola lettura in cui chiami Calendar.GetWeekOfYear o ti crei un Converter, in cui richiami sempre Calendar.GetWeekOfYear, da assegnare  PropertyGroupDescription nello xaml.

    Esempio di custom converter in base all'esempio :

        [ValueConversion(typeof(DateTime),typeof(int))]
        public class WeekOfYearConverter:IValueConverter
        {
            #region IValueConverter Members
    
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value is DateTime)
                {
                  return  culture.Calendar.GetWeekOfYear((DateTime)value
                        , System.Globalization.CalendarWeekRule.FirstFourDayWeek
                        , DayOfWeek.Monday);
                }
                return value;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return System.Windows.DependencyProperty.UnsetValue;
            }
    
            #endregion
        }

        <Window.Resources>
            <local:CompleteConverter x:Key="completeConverter" />
    <local:WeekOfYearConverter x:Key="woyConverter" />
    
            <local:Tasks x:Key="tasks" />
            <CollectionViewSource x:Key="cvsTasks" Source="{StaticResource tasks}" 
                                  Filter="CollectionViewSource_Filter">
                <CollectionViewSource.SortDescriptions>
                    <!-- Requires 'xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"' declaration. -->
                    <scm:SortDescription PropertyName="DueDate" />
                    <scm:SortDescription PropertyName="ProjectName"/>
                    <scm:SortDescription PropertyName="Complete" />
    
                </CollectionViewSource.SortDescriptions>
                <CollectionViewSource.GroupDescriptions>
                    <PropertyGroupDescription PropertyName="DueDate" Converter="{StaticResource woyConverter}"/>
                </CollectionViewSource.GroupDescriptions>
            </CollectionViewSource>
        </Window.Resources>

    Se questo post ti ha dato una mano, ti prego di contrassegnarlo come utile o risposta.

    • Contrassegnato come risposta Fabio Miceli martedì 4 agosto 2020 18:21
    martedì 4 agosto 2020 08:54
  • Ciao Spaccabit grazie per avermi risposto.

    ho seguito il tuo suggerimento, ho fatto come hai detto ok funziona .

    L'unica cosa è che per avere, ad esempio tutte le settimane del mese di Agosto, devo settare la proprietà DateTime    il primo giorno della prima settimana del mese precedente e aggiungere al numero massimo del ciclo i giorni mancanti sia del mese precedente che quello successivo in questo modo:

                // Get a reference to the tasks collection.
                Tasks _tasks = (Tasks)this.Resources["tasks"];
                DateTime dateTime = new DateTime(2020,7,27);
                // Generate some task data and add it to the task list.
                for (int i = 0; i <= 41; i++)
                {
                    _tasks.Add(new Task()
                    {
                        ProjectName = "Project " + ((i % 3) + 1).ToString(),
                        TaskName = "Task " + i.ToString(),
                        DueDate = dateTime.AddDays(i), // DateTime.Now.AddDays(i),
                        Complete = (i % 2 == 0)
                    });
                }
    

    così va bene, mi da tutte le settimane complete anche dei giorni del mese precedente e successivo.

    Ma ad ogni mese che cambio dovrei cambiare il numero massimo nel ciclo for !

    come posso farlo generare in automatico ?


    fabio miceli

    • Contrassegnato come risposta Fabio Miceli martedì 4 agosto 2020 18:21
    martedì 4 agosto 2020 15:30
  •         static void Main(string[] args)
            {
    
                var firstDate = new DateTime(2020, 8, 1);
    
                var lastDate = firstDate.AddMonths(1).AddDays(-1);
    
                if (lastDate.DayOfWeek != DayOfWeek.Sunday)
                {
                    lastDate = lastDate.AddDays(7 - (int)lastDate.DayOfWeek);
                }
    
                firstDate = firstDate.DayOfWeek == DayOfWeek.Sunday // se è domenica aggiungo un giorno
                     ? firstDate.AddDays(1)
                     : firstDate.AddDays(-(int)firstDate.DayOfWeek + 1);
    
                var currentDate = firstDate;
    
                while (currentDate <= lastDate)
                {
                    Console.WriteLine(currentDate);
                    currentDate=currentDate.AddDays(1);
                }
    
    
                Console.WriteLine(firstDate);
    
                Console.WriteLine(lastDate);
    
                Console.ReadKey();
    
            }

    Se questo post ti ha dato una mano, ti prego di contrassegnarlo come utile o risposta.
    • Contrassegnato come risposta Fabio Miceli martedì 4 agosto 2020 18:21
    martedì 4 agosto 2020 16:51

Tutte le risposte

  • Qui trovi l'esempio di come raggruppare una datagrid.

    Nel tuo caso specifico o ti crei una Proprietà aggiuntaiva WeekOfYear di sola lettura in cui chiami Calendar.GetWeekOfYear o ti crei un Converter, in cui richiami sempre Calendar.GetWeekOfYear, da assegnare  PropertyGroupDescription nello xaml.

    Esempio di custom converter in base all'esempio :

        [ValueConversion(typeof(DateTime),typeof(int))]
        public class WeekOfYearConverter:IValueConverter
        {
            #region IValueConverter Members
    
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value is DateTime)
                {
                  return  culture.Calendar.GetWeekOfYear((DateTime)value
                        , System.Globalization.CalendarWeekRule.FirstFourDayWeek
                        , DayOfWeek.Monday);
                }
                return value;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return System.Windows.DependencyProperty.UnsetValue;
            }
    
            #endregion
        }

        <Window.Resources>
            <local:CompleteConverter x:Key="completeConverter" />
    <local:WeekOfYearConverter x:Key="woyConverter" />
    
            <local:Tasks x:Key="tasks" />
            <CollectionViewSource x:Key="cvsTasks" Source="{StaticResource tasks}" 
                                  Filter="CollectionViewSource_Filter">
                <CollectionViewSource.SortDescriptions>
                    <!-- Requires 'xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"' declaration. -->
                    <scm:SortDescription PropertyName="DueDate" />
                    <scm:SortDescription PropertyName="ProjectName"/>
                    <scm:SortDescription PropertyName="Complete" />
    
                </CollectionViewSource.SortDescriptions>
                <CollectionViewSource.GroupDescriptions>
                    <PropertyGroupDescription PropertyName="DueDate" Converter="{StaticResource woyConverter}"/>
                </CollectionViewSource.GroupDescriptions>
            </CollectionViewSource>
        </Window.Resources>

    Se questo post ti ha dato una mano, ti prego di contrassegnarlo come utile o risposta.

    • Contrassegnato come risposta Fabio Miceli martedì 4 agosto 2020 18:21
    martedì 4 agosto 2020 08:54
  • Ciao Spaccabit grazie per avermi risposto.

    ho seguito il tuo suggerimento, ho fatto come hai detto ok funziona .

    L'unica cosa è che per avere, ad esempio tutte le settimane del mese di Agosto, devo settare la proprietà DateTime    il primo giorno della prima settimana del mese precedente e aggiungere al numero massimo del ciclo i giorni mancanti sia del mese precedente che quello successivo in questo modo:

                // Get a reference to the tasks collection.
                Tasks _tasks = (Tasks)this.Resources["tasks"];
                DateTime dateTime = new DateTime(2020,7,27);
                // Generate some task data and add it to the task list.
                for (int i = 0; i <= 41; i++)
                {
                    _tasks.Add(new Task()
                    {
                        ProjectName = "Project " + ((i % 3) + 1).ToString(),
                        TaskName = "Task " + i.ToString(),
                        DueDate = dateTime.AddDays(i), // DateTime.Now.AddDays(i),
                        Complete = (i % 2 == 0)
                    });
                }
    

    così va bene, mi da tutte le settimane complete anche dei giorni del mese precedente e successivo.

    Ma ad ogni mese che cambio dovrei cambiare il numero massimo nel ciclo for !

    come posso farlo generare in automatico ?


    fabio miceli

    • Contrassegnato come risposta Fabio Miceli martedì 4 agosto 2020 18:21
    martedì 4 agosto 2020 15:30
  •         static void Main(string[] args)
            {
    
                var firstDate = new DateTime(2020, 8, 1);
    
                var lastDate = firstDate.AddMonths(1).AddDays(-1);
    
                if (lastDate.DayOfWeek != DayOfWeek.Sunday)
                {
                    lastDate = lastDate.AddDays(7 - (int)lastDate.DayOfWeek);
                }
    
                firstDate = firstDate.DayOfWeek == DayOfWeek.Sunday // se è domenica aggiungo un giorno
                     ? firstDate.AddDays(1)
                     : firstDate.AddDays(-(int)firstDate.DayOfWeek + 1);
    
                var currentDate = firstDate;
    
                while (currentDate <= lastDate)
                {
                    Console.WriteLine(currentDate);
                    currentDate=currentDate.AddDays(1);
                }
    
    
                Console.WriteLine(firstDate);
    
                Console.WriteLine(lastDate);
    
                Console.ReadKey();
    
            }

    Se questo post ti ha dato una mano, ti prego di contrassegnarlo come utile o risposta.
    • Contrassegnato come risposta Fabio Miceli martedì 4 agosto 2020 18:21
    martedì 4 agosto 2020 16:51
  • Perfetto.

    Grazie mille per gli esempi e consigli

    mi metto subito al lavoro

    ciao alla prossima



    fabio miceli

    martedì 4 agosto 2020 18:21
  • Ciao Spaccabit scusami ti volevo chiedere un'ultima cosa:

    Sull'intestazione del Gruppo oltre al numero della settimana e la quantità dei giorni vorrei visualizzare anche la settimana "Dal>Al:

    Es: "Settimana dal 03 Agosto al 09 Agosto:

    Come potrei fare?


    fabio miceli

    martedì 4 agosto 2020 19:50
  • Potresti creati un converter che a partire dal numero della settimana ti restitusce la stringa del periodo e utilzzallo qui:

                                    <Expander.Header>
                                        <DockPanel>
                                            <TextBlock FontWeight="Bold" Text="{Binding Path=Name, Converter={x:Static local:wnToDateRange}}" Margin="5,0,0,0" Width="100"/>
                                            <TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
                                        </DockPanel>
                                    </Expander.Header>

    per recuperare la la data dal numero settimana puoi usare la seguente funzione:

    public static DateTime FirstDateOfWeek(int year, int weekOfYear)
    {
        DateTime jan1 = new DateTime(year, 1, 1);
        int daysOffset = Convert.ToInt32(System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek) - Convert.ToInt32(jan1.DayOfWeek);
        DateTime firstWeekDay = jan1.AddDays(daysOffset);
        System.Globalization.CultureInfo curCulture = System.Globalization.CultureInfo.CurrentCulture;
        int firstWeek = curCulture.Calendar.GetWeekOfYear(jan1, curCulture.DateTimeFormat.CalendarWeekRule, curCulture.DateTimeFormat.FirstDayOfWeek);
        if (firstWeek <= 1) {
            weekOfYear -= 1;
        }
        return firstWeekDay.AddDays(weekOfYear * 7);
    }

    venerdì 7 agosto 2020 08:23
  • Ciao Spaccabit,

    perfetto grazie.

    Devo dirti che il mese di gennaio non lo raggruppa correttamente:

    cioè se la data iniziale la setto in questo modo:

      DateTime dateTime = new DateTime(2020, 1, 1);

    non inserisce il 30 e il 31 12 2019 all'interno del gruppo della prima settimana del mese di gennaio 2020,

    se invece la setto in quest'altro modo:

      DateTime dateTime = new DateTime(2019, 12, 30);

    gli ultimi giorni del 2019 li raggruppa d soli (come numero di settimana restituisce il 53, invece che 1 come nella prima settimana/gennaio 2020), escludendoli  dalla prima settimana di gennaio/2020,

    Questo è il codice completo in testa alla a MainWindow:

            public  MainWindow()
            {
                InitializeComponent();
    
                // Get a reference to the tasks collection.
                 _tasks = (Tasks)this.Resources["tasks"];
                //DateTime dateTime = new DateTime(2020,7,27);
    
                DateTime dateTime = new DateTime(2019, 12, 30);
    
                // Generate some task data and add it to the task list.
    
                string _week;
                CultureInfo culture;
                for (int i = 0; i <= 41; i++)
                {
                    _tasks.Add(new Task()
                    {
                    ProjectName = "Project " + ((i % 3) + 1).ToString(),
                        TaskName = "Task " + i.ToString(),
                        
                        DueDate = dateTime.AddDays(i), // DateTime.Now.AddDays(i),
                        ID = i.ToString()
                    });
    
                    if (dateTime.Day == 31) dateTime.AddMonths(1);
                }
            }
    


    fabio miceli

    venerdì 7 agosto 2020 08:52
  • Ho provato a mettere questa clausola all' interno del converter:

        [ValueConversion(typeof(DateTime), typeof(int))]
        public class WeekOfYearConverter : IValueConverter
        {
            #region IValueConverter Members
    
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                int result = 0;
                if (value is DateTime)
                {
    
                    if (((DateTime)value).Day == 30 && ((DateTime)value).Month == 12 && ((DateTime)value).Year == 2019 ||
                       ((DateTime)value).Day == 31 && ((DateTime)value).Month == 12 && ((DateTime)value).Year == 2019)
                    {
                       
                        result = 1;
                    }
                    else
                    {
                        result = culture.Calendar.GetWeekOfYear((DateTime)value
                          , System.Globalization.CalendarWeekRule.FirstFourDayWeek
                          , DayOfWeek.Monday);
                    }
                    //return culture.Calendar.GetWeekOfYear((DateTime)value
                    //      , System.Globalization.CalendarWeekRule.FirstFourDayWeek
                    //      , DayOfWeek.Monday);
    
                    return result;
                }
                return value;
            }
    

    Per il mese di Gennaio 2020

    Funziona solo se la data iniziale la setto in questo modo:

    DateTime dateTime = new DateTime(2019, 12, 30);


    fabio miceli

    venerdì 7 agosto 2020 09:52