Skip to content

Instantly share code, notes, and snippets.

@julesx
Created August 18, 2022 14:57
Show Gist options
  • Save julesx/ed1720f103a450e5085c752d5e8b7f44 to your computer and use it in GitHub Desktop.
Save julesx/ed1720f103a450e5085c752d5e8b7f44 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using WPF.Core.Classes;
namespace MyApp.UserControls
{
/// <summary>
/// Interaction logic for ImageScroller.xaml
/// </summary>
public partial class ImageScroller : UserControl
{
private EventHandler<RenderingEventArgs>? renderHandler;
private VirtualizingStackPanel _panel;
private bool _shifting;
private bool ImageUnloaded;
private IList<MyImage> _snapshot = new List<MyImage>();
private IUserTag UserTag => (IUserTag)DataContext;
public ImageScroller()
{
InitializeComponent();
}
public void Shift(ScrollViewer target, double speed = 11.0, double distance = 20.0)
{
ScrollViewer scrollViewer = target;
double startOffset = scrollViewer.HorizontalOffset;
double destinationOffset = scrollViewer.HorizontalOffset + distance;
if (destinationOffset < 0.0)
{
destinationOffset = 0.0;
distance = scrollViewer.HorizontalOffset;
}
if (destinationOffset > scrollViewer.ScrollableWidth)
{
destinationOffset = scrollViewer.ScrollableWidth;
distance = scrollViewer.ScrollableWidth - scrollViewer.HorizontalOffset;
}
double animationTime = Math.Abs(distance / speed);
DateTime startTime = DateTime.Now;
CompositionTargetEx.Rendering -= renderHandler;
renderHandler = (object? sender, RenderingEventArgs e) =>
{
_shifting = true;
if (base.DataContext == BindingOperations.DisconnectedSource || Application.Current == null || Application.Current.MainWindow == null)
{
_shifting = false;
CompositionTargetEx.Rendering -= CompositionTargetEx_Rendering;
}
else
{
if (ImageUnloaded)
{
distance = scrollViewer.ScrollableWidth - scrollViewer.HorizontalOffset;
animationTime = Math.Abs(distance / speed);
startTime = DateTime.Now;
ImageUnloaded = false;
}
//Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)delegate
//{
//}).Wait();
double totalSeconds = (DateTime.Now - startTime).TotalSeconds;
if (totalSeconds >= animationTime)
{
scrollViewer.ScrollToHorizontalOffset(destinationOffset);
_shifting = false;
CompositionTargetEx.Rendering -= renderHandler;
}
if (distance < 0.0)
{
scrollViewer.ScrollToHorizontalOffset(startOffset - totalSeconds * speed);
}
else
{
scrollViewer.ScrollToHorizontalOffset(startOffset + totalSeconds * speed);
}
}
};
CompositionTargetEx.Rendering += renderHandler;
}
private void CompositionTargetEx_Rendering(object? sender, RenderingEventArgs e)
{
}
private void VirtualizingStackPanel_Loaded(object sender, RoutedEventArgs e)
{
_panel = (VirtualizingStackPanel)sender;
_panel.ScrollOwner.ScrollChanged -= _scrollChanged;
_panel.ScrollOwner.ScrollChanged += _scrollChanged;
if (_shifting)
{
return;
}
IUserTag userTag = UserTag;
if (userTag != null && userTag.RotatingImages.Count > 1 || _panel.ScrollOwner.VerticalOffset != _panel.ScrollOwner.ScrollableWidth)
{
base.Dispatcher.BeginInvoke((Action)delegate
{
Shift(_panel.ScrollOwner, 2.0, _panel.ScrollOwner.ScrollableWidth);
}, DispatcherPriority.ContextIdle, null);
}
}
private void _scrollChanged(object sender, RoutedEventArgs e)
{
if (!_shifting)
{
IUserTag userTag = UserTag;
if (userTag != null && userTag.RotatingImages.Count > 1)
{
base.Dispatcher.BeginInvoke((Action)delegate
{
Shift(_panel.ScrollOwner, 2.0, _panel.ScrollOwner.ScrollableWidth);
}, DispatcherPriority.ContextIdle, null);
}
}
UpdateSnapshot();
}
private void UpdateSnapshot()
{
Rect layoutBounds = LayoutInformation.GetLayoutSlot(_panel);
List<MyImage> list = (from visualChild in _panel.GetChildren()
let childBounds = LayoutInformation.GetLayoutSlot(visualChild)
where layoutBounds.Contains(childBounds) || layoutBounds.IntersectsWith(childBounds)
select visualChild.DataContext).Cast<MyImage>().ToList();
foreach (MyImage item in _snapshot.Except(list))
{
item.UnloadedTimestamp = DateTimeOffset.Now;
ImageUnloaded = true;
}
_snapshot = list;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment