在 Xamarin 表单应用程序中创建 outlook 样式事件

Creating outlook style occurrences in Xamarin forms application

我有一组复选框代表一周中的几天我还有一个开始日期和结束日期。我不想要的是 outlook 如何处理其日历中的日子,但我有点不知所措如何计算它。我打算使用这个库,但它与 Xamarin 表单不兼容。 https://github.com/SergeyBarskiy/RecurrenceCalculator。当我说不起作用时它没有在 quite 中更新一段时间所以与 XF 不兼容。

星期列表中的日子将以逗号分隔,即 Mon、Tue、Wed,但可能没有 Thur、Fri、Sunday

我需要一些方法来计算最坏情况下的日期,我可以在基于服务器的 api 上完成。但我宁愿在用户设备上进行。

if (picksessionType.SelectedItem.ToString() == Enums.RepeatOccurance.Daily.ToString())
{
   foreach (var item in daysOfWeekList)
   {
     Session session = new Session();
     session.Name = "\r\n" + txtName.Text + "\r\n" + item.ToString() + "\r\n";
     session.StartDate = txtDateStartEntry.SelectedDate; // I obv need to shift this date to each date in days of week list
     session.EndDate = txtDateEndEntry.SelectedDate;
     session.IsActive = true;
     session.IsDeleted = false;
     await api.AddToSession(session);
  }
 await DisplayAlert(Constants.AppName, "Sessions Created For "+daysOfWeekList.ToString(), "OK");
}

目前在ui我正在做以下事情

 <Frame x:Name="daySelector" IsVisible="false">
    <StackLayout Orientation="Horizontal">
      <syncfusion:SfCheckBox  x:Name="daySun" Text="Sun" StateChanged="SfCheckBox_StateChanged" Visual="Material"></syncfusion:SfCheckBox>
      <syncfusion:SfCheckBox x:Name="dayMon" Text="Mon" StateChanged="SfCheckBox_StateChanged" Visual="Material"></syncfusion:SfCheckBox>
      <syncfusion:SfCheckBox x:Name="dayTue" Text="Tue" StateChanged="SfCheckBox_StateChanged" Visual="Material"></syncfusion:SfCheckBox>

     <syncfusion:SfCheckBox x:Name="dayWed" Text="Wed" StateChanged="SfCheckBox_StateChanged" Visual="Material"></syncfusion:SfCheckBox>
     <syncfusion:SfCheckBox x:Name="dayThur" Text="Thur" StateChanged="SfCheckBox_StateChanged" Visual="Material"></syncfusion:SfCheckBox>
     <syncfusion:SfCheckBox x:Name="dayFri" Text="Fri"  StateChanged="SfCheckBox_StateChanged" Visual="Material"></syncfusion:SfCheckBox>
      <syncfusion:SfCheckBox x:Name="daySat" Text="Sat"  StateChanged="SfCheckBox_StateChanged" Visual="Material"></syncfusion:SfCheckBox>
 </StackLayout>
</Frame>

如果有人有新的更好的整理方法,此功能还可以进行一些令人震惊的整理工作。

private void SfCheckBox_StateChanged(object sender, StateChangedEventArgs e)
{
    var selectedDay = sender as SfCheckBox;
    daysOfWeekList.Add(selectedDay.Text);

    List<string> distinct = daysOfWeekList.Distinct().ToList();
    if (daySun.IsChecked == false)
        distinct.Remove(daySun.Text);
    if (dayMon.IsChecked == false)
        distinct.Remove(dayMon.Text);
    if (dayTue.IsChecked == false)
       distinct.Remove(dayTue.Text);
    if (dayWed.IsChecked == false)
       distinct.Remove(dayWed.Text);
    if (dayThur.IsChecked == false)
       distinct.Remove(dayThur.Text);
    if (dayFri.IsChecked == false)
       distinct.Remove(dayFri.Text);
    if (daySat.IsChecked == false)
       distinct.Remove(daySat.Text);

       daysOfWeekList = distinct;
    }

Ui 例子

所以在 UI 示例中,您会看到我选择了两个日期,然后我选择了 Daily 选择周一、周二、周三、周四直到结束日期,它应该在上面的 for 循环中为选中的每一天创建会话。

提前致谢

编辑 2

我已经尝试了上面的代码,但是因为我在这些条件之间选择了星期五,它说他们应该创建 9 个会话,但我认为应该只创建 8 个,因为第 27 个是截止点,但系统仍在为28号

这是我的示例的 .netFiddle

https://dotnetfiddle.net/N6nkgP

单元测试

星期几枚举值 https://docs.microsoft.com/en-us/dotnet/api/system.dayofweek?view=net-6.0

using System;
using NUnit.Framework;
using System.Collections.Generic;

namespace TestApp {
public class Program
{
    public static void Main() 
    {
        var x = new NUnitLite.AutoRun().Execute(new string[]{"--test:TestApp.CalculateOccuranceTests", "--noc"});
        Console.WriteLine("");
        Console.WriteLine("----------------------------------------------");
        Console.WriteLine(x==0?"All Test Passed... :¬)": string.Format("{0} tests failed... :¬(", x));
        Console.WriteLine("----------------------------------------------");
    }
}

  
    [TestFixture]
    public class CalculateOccuranceTests
    {
        [TestCase(8,"2022-01-10" ,"2022-01-27",2,3,5 )]
        public void OccuranceTest(int expected,DateTime startDate, DateTime endDate, params int[] numbers)
        {
            //Setup
            List<int> daysofWeek = new List<int>();
            foreach (var item in numbers)
            {
                daysofWeek.Add(item);
                Console.WriteLine("Date Selected "  + item.ToString());
            }
            //act
            var act = CalculateDaysToSessions( startDate, endDate, daysofWeek);
            //Assert
            Assert.AreEqual(expected,act.Count);
        }


        public List<DateTime> CalculateDaysToSessions(DateTime startDate, DateTime enddate, List<int> daysOfWeek)
        {
            List<DateTime> dates = new List<DateTime>();
            DateTime date = new DateTime();
            date = startDate;

            while (date <= enddate)
            {

                if (daysOfWeek.Contains((int)date.DayOfWeek))
                {
                    dates.Add(date);
                    Console.WriteLine("Date Session "  + date.ToString("dd/MM/yyyy"));

                }
                date = date.AddDays(1);

            }
            return dates;

        }

   
}

}

以上输出

Date Selected 2 =Tuesday    
Date Selected 3 =Wednesday
Date Selected 5 =Friday
Date Session 11/01/2022
Date Session 12/01/2022
Date Session 14/01/2022
Date Session 18/01/2022
Date Session 19/01/2022
Date Session 21/01/2022
Date Session 25/01/2022
Date Session 26/01/2022
Date Session 28/01/2022

当它不应该创建第 28 个时

我所要做的就是在它现在按预期工作的时候这样做。

if (date > enddate) date = date.AddDays(-1);

编辑 3 Jason 是正确的 date.AddDays 必须在循环的底部不需要 if 语句

计算这个的算法应该很简单。只需在开始日期和结束日期之间循环,并检查每次迭代以查看它是否是用户选择的日期之一

// this is pseudo-c# and may need to be cleaned up a bit
List<DaysOfWeek> days = // initialize this based on the user selections
List<DateTime> dates = new List<DateTime>();
var date = StartDate;

while (date <= EndDate)
{
  if (days.Includes(date.DayOfWeek))
  {
    dates.Add(date);
  }

  date = date.AddDays(1);
}