UWP:在 CalendarView 中自动突出显示整周

UWP: Automatically highlight a whole week in CalendarView

我在 UWP 应用程序中使用 CalendarView。它以 "Month" 模式显示。我想要的是,当用户选择一个日期时,它应该以某种方式突出显示所选日期的整个星期。

我能够使用以下代码获得一些东西,该代码在用户选择日期后选择一周中的所有日子,但它看起来不太好,事件处理 detach/attach 很麻烦并且容易出错,我相信可能会有更多合适的选择:

private void cvMain_SelectedDatesChanged(CalendarView sender, CalendarViewSelectedDatesChangedEventArgs args)
{
    // detach event handler to prevent an endless loop
    this.cvMain.SelectedDatesChanged -= cvMain_SelectedDatesChanged;
    try
    {
        if (args.AddedDates.Count > 0)
        {
            // get first date of selection
            var addedDateOffset = args.AddedDates[0];
            var userSelectedDate = addedDateOffset.Date;

            // get first day of the selected way and the last day
            var startOfWeek = userSelectedDate.StartOfWeek();
            var endOfWeek = userSelectedDate.EndOfWeek();

            var selectedDatesList = new List<DateTimeOffset>();
            selectedDatesList.Add(startOfWeek);
            for (var dateInBetween = startOfWeek; dateInBetween <= endOfWeek; dateInBetween = dateInBetween.AddDays(1))
            {
                selectedDatesList.Add(dateInBetween);
            }
            selectedDatesList.Add(endOfWeek);

            cvMain.SelectedDates.Clear();
            foreach (var selectedDate in selectedDatesList)
            {
                cvMain.SelectedDates.Add(selectedDate);
            }
        }
    }
    finally
    {
        // reattach event handler
        this.cvMain.SelectedDatesChanged += cvMain_SelectedDatesChanged;
    }
}

我不确定我想要的是否真的可以用开箱即用的控件来完成,因为我们似乎无法直接访问当天的项目,而且 CalendarViewDayItemChanging 事件只是 运行 在 Page_Load 上一次,而不是在选择更改时。

有什么想法吗?

我想到了一个解决方案,但它不一定是一个好的解决方案,所以我只是把它扔在这里作为替代方案:-D。

我试过为此创建行为。首先,您需要安装 Behaviors 包:

Install-Package Microsoft.Xaml.Behaviors.Uwp.Managed -Version 2.0.0 

现在的行为如下所示:

public class WeekHighlightBehavior : Behavior
{
    public CalendarView CalendarControl
    {
        get { return (CalendarView)GetValue(CalendarProperty); }
        set { SetValue(CalendarProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Calendar.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CalendarProperty =
        DependencyProperty.Register("CalendarControl", typeof(CalendarView), typeof(WeekHighlightBehavior), new PropertyMetadata(0));

    protected override void OnAttached()
    {
        base.OnAttached();
        CalendarControl.SelectedDatesChanged += Calendar_SelectedDatesChanged;
    }

    private void Calendar_SelectedDatesChanged(CalendarView sender, CalendarViewSelectedDatesChangedEventArgs args)
    {
        var dayItem = this.AssociatedObject as CalendarViewDayItem;
        var calendar = CultureInfo.CurrentUICulture.Calendar;
        bool highlight = false;
        foreach (var date in args.AddedDates)
        {
            if (calendar.GetWeekOfYear(date.DateTime, CalendarWeekRule.FirstDay, DayOfWeek.Monday) ==
                calendar.GetWeekOfYear(dayItem.Date.DateTime, CalendarWeekRule.FirstDay, DayOfWeek.Monday))
            {
                highlight = true;
                break;
            }
        }

        if (highlight)
        {
            dayItem.Background = new SolidColorBrush(Colors.Yellow);
        }
        else
        {
            dayItem.Background = null;
        }
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        CalendarControl.SelectedDatesChanged -= Calendar_SelectedDatesChanged;
    }
}

该行为基本上观察CalendarViewSelectedDatesChanged事件,每次执行时,它会检查所选日期的一年中的星期是否与当天的星期几匹配行为附于。如果是,我们更改项目的背景。这将针对所有日期调用,因此一周中的所有日期肯定会突出显示。

不幸的是,您无法通过 XAML 中的样式 setter 附加它:

<CalendarView x:Name="CalendarView">
    <CalendarView.CalendarViewDayItemStyle>
        <Style TargetType="CalendarViewDayItem">
            <Setter Property="interactivity:Interaction.Behaviors">
                <Setter.Value>
                    <interactivity:BehaviorCollection>
                        <local:WeekHighlightBehavior CalendarControl="{Binding ElementName=CalendarView}" />
                    </interactivity:BehaviorCollection>
                </Setter.Value>
            </Setter>
            <Setter Property="Padding" Value="0" />
            <Setter Property="Margin" Value="0" />

        </Style>
    </CalendarView.CalendarViewDayItemStyle>
</CalendarView>

这样,行为只设置一次,即第一个创建的项目。但是,您可以在 CalendarViewDayItemChanging 事件的代码隐藏中设置行为:

private void CalendarView_CalendarViewDayItemChanging(CalendarView sender, CalendarViewDayItemChangingEventArgs args)
{
    var behavior = new WeekHighlightBehavior();
    behavior.CalendarControl = CalendarView;
    Interaction.GetBehaviors(args.Item).Clear();
    Interaction.GetBehaviors(args.Item).Add(behavior);
}

我正在手动清除附加的行为,因为我注意到它们没有被自动清除,因为 CalendarView 保留 CalendarDayViewItem 实例并在它认为合适的时候重新使用它们。