Batch flip-view range updates for programmatic calendar navigation (#805)
* Batch calendar range updates during programmatic navigation * Refine programmatic calendar navigation batching state
This commit is contained in:
@@ -142,7 +142,14 @@ public partial class WinoCalendarControl : Control
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void ManageHighlightedDateRange()
|
private void ManageHighlightedDateRange()
|
||||||
=> SelectedFlipViewDayRange = InternalFlipView.SelectedItem as DayRangeRenderModel;
|
{
|
||||||
|
if (InternalFlipView?.IsProgrammaticNavigationInProgress == true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedFlipViewDayRange = InternalFlipView?.SelectedItem as DayRangeRenderModel;
|
||||||
|
}
|
||||||
|
|
||||||
private void DeregisterCanvas(WinoDayTimelineCanvas canvas)
|
private void DeregisterCanvas(WinoDayTimelineCanvas canvas)
|
||||||
{
|
{
|
||||||
@@ -190,14 +197,29 @@ public partial class WinoCalendarControl : Control
|
|||||||
{
|
{
|
||||||
base.OnApplyTemplate();
|
base.OnApplyTemplate();
|
||||||
|
|
||||||
|
if (InternalFlipView != null)
|
||||||
|
{
|
||||||
|
InternalFlipView.ProgrammaticNavigationCompleted -= InternalFlipViewProgrammaticNavigationCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
InternalFlipView = GetTemplateChild(PART_WinoFlipView) as WinoCalendarFlipView;
|
InternalFlipView = GetTemplateChild(PART_WinoFlipView) as WinoCalendarFlipView;
|
||||||
IdleGrid = GetTemplateChild(PART_IdleGrid) as Grid;
|
IdleGrid = GetTemplateChild(PART_IdleGrid) as Grid;
|
||||||
|
|
||||||
|
if (InternalFlipView != null)
|
||||||
|
{
|
||||||
|
InternalFlipView.ProgrammaticNavigationCompleted += InternalFlipViewProgrammaticNavigationCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
UpdateIdleState();
|
UpdateIdleState();
|
||||||
ManageCalendarOrientation();
|
ManageCalendarOrientation();
|
||||||
ManageDisplayType();
|
ManageDisplayType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InternalFlipViewProgrammaticNavigationCompleted(object? sender, ProgrammaticNavigationCompletedEventArgs e)
|
||||||
|
{
|
||||||
|
SelectedFlipViewDayRange = e.DayRange;
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateIdleState()
|
private void UpdateIdleState()
|
||||||
{
|
{
|
||||||
InternalFlipView.Opacity = IsFlipIdle ? 0 : 1;
|
InternalFlipView.Opacity = IsFlipIdle ? 0 : 1;
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ public partial class WinoCalendarFlipView : CustomCalendarFlipView
|
|||||||
set { SetValue(IsIdleProperty, value); }
|
set { SetValue(IsIdleProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool IsProgrammaticNavigationInProgress { get; private set; }
|
||||||
|
|
||||||
|
internal int? PendingTargetIndex { get; private set; }
|
||||||
|
|
||||||
|
internal event EventHandler<ProgrammaticNavigationCompletedEventArgs>? ProgrammaticNavigationCompleted;
|
||||||
|
|
||||||
public WinoCalendarFlipView()
|
public WinoCalendarFlipView()
|
||||||
{
|
{
|
||||||
RegisterPropertyChangedCallback(ItemsSourceProperty, new DependencyPropertyChangedCallback(OnItemsSourceChanged));
|
RegisterPropertyChangedCallback(ItemsSourceProperty, new DependencyPropertyChangedCallback(OnItemsSourceChanged));
|
||||||
@@ -123,37 +129,61 @@ public partial class WinoCalendarFlipView : CustomCalendarFlipView
|
|||||||
await DispatcherQueue.EnqueueAsync(() =>
|
await DispatcherQueue.EnqueueAsync(() =>
|
||||||
{
|
{
|
||||||
// Find the day range that contains the date.
|
// Find the day range that contains the date.
|
||||||
var dayRange = GetItemsSource()?.FirstOrDefault(a => a.CalendarDays.Any(b => b.RepresentingDate.Date == dateTime.Date));
|
var dayRanges = GetItemsSource();
|
||||||
|
var dayRange = dayRanges?.FirstOrDefault(a => a.CalendarDays.Any(b => b.RepresentingDate.Date == dateTime.Date));
|
||||||
|
|
||||||
if (dayRange != null)
|
if (dayRange != null && dayRanges != null)
|
||||||
{
|
{
|
||||||
var navigationItemIndex = GetItemsSource().IndexOf(dayRange);
|
var navigationItemIndex = dayRanges.IndexOf(dayRange);
|
||||||
|
var hasNavigationWork = navigationItemIndex != SelectedIndex;
|
||||||
|
|
||||||
if (Math.Abs(navigationItemIndex - SelectedIndex) > 4)
|
IsProgrammaticNavigationInProgress = hasNavigationWork;
|
||||||
|
PendingTargetIndex = navigationItemIndex;
|
||||||
|
|
||||||
|
if (!hasNavigationWork)
|
||||||
{
|
{
|
||||||
// Difference between dates are high.
|
PendingTargetIndex = null;
|
||||||
// No need to animate this much, just go without animating.
|
return;
|
||||||
|
|
||||||
SelectedIndex = navigationItemIndex;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Until we reach the day in the flip, simulate next-prev button clicks.
|
|
||||||
// This will make sure the FlipView animations are triggered.
|
|
||||||
// Setting SelectedIndex directly doesn't trigger the animations.
|
|
||||||
|
|
||||||
while (SelectedIndex != navigationItemIndex)
|
try
|
||||||
|
{
|
||||||
|
if (Math.Abs(navigationItemIndex - SelectedIndex) > 4)
|
||||||
{
|
{
|
||||||
if (SelectedIndex > navigationItemIndex)
|
// Difference between dates are high.
|
||||||
|
// No need to animate this much, just go without animating.
|
||||||
|
|
||||||
|
SelectedIndex = navigationItemIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Until we reach the day in the flip, simulate next-prev button clicks.
|
||||||
|
// This will make sure the FlipView animations are triggered.
|
||||||
|
// Setting SelectedIndex directly doesn't trigger the animations.
|
||||||
|
|
||||||
|
while (SelectedIndex != navigationItemIndex)
|
||||||
{
|
{
|
||||||
GoPreviousFlip();
|
if (SelectedIndex > navigationItemIndex)
|
||||||
}
|
{
|
||||||
else
|
GoPreviousFlip();
|
||||||
{
|
}
|
||||||
GoNextFlip();
|
else
|
||||||
|
{
|
||||||
|
GoNextFlip();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (SelectedIndex == PendingTargetIndex)
|
||||||
|
{
|
||||||
|
ProgrammaticNavigationCompleted?.Invoke(this, new ProgrammaticNavigationCompletedEventArgs(SelectedItem as DayRangeRenderModel ?? dayRange));
|
||||||
|
}
|
||||||
|
|
||||||
|
IsProgrammaticNavigationInProgress = false;
|
||||||
|
PendingTargetIndex = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -161,3 +191,13 @@ public partial class WinoCalendarFlipView : CustomCalendarFlipView
|
|||||||
private ObservableRangeCollection<DayRangeRenderModel> GetItemsSource()
|
private ObservableRangeCollection<DayRangeRenderModel> GetItemsSource()
|
||||||
=> ItemsSource as ObservableRangeCollection<DayRangeRenderModel>;
|
=> ItemsSource as ObservableRangeCollection<DayRangeRenderModel>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal sealed class ProgrammaticNavigationCompletedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public ProgrammaticNavigationCompletedEventArgs(DayRangeRenderModel dayRange)
|
||||||
|
{
|
||||||
|
DayRange = dayRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DayRangeRenderModel DayRange { get; }
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user