This commit is contained in:
h82258652 2020-09-18 12:39:10 +08:00
Родитель 9fc459992b
Коммит 8dfc8e3477
5 изменённых файлов: 111 добавлений и 13 удалений

Просмотреть файл

@ -28,8 +28,7 @@
<TextBlock HorizontalAlignment="Left"
VerticalAlignment="Top"
Foreground="OrangeRed"
IsHitTestVisible="False"
Text="Please scroll down to see the effect." />
IsHitTestVisible="False"><Run Text="Please scroll down to see the effect." /><LineBreak /><Run Text="The default threshold for triggering lazy loading is 300 px." /></TextBlock>
<Button Width="48"
Height="48"
HorizontalAlignment="Right"

Просмотреть файл

@ -71,7 +71,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
if (ImageExBase.IsLazyLoadingSupported)
{
SampleController.Current.RegisterNewCommand("Lazy loading sample (17763 or higher supported)", (sender, args) =>
SampleController.Current.RegisterNewCommand("Lazy loading sample", (sender, args) =>
{
var imageExLazyLoadingControl = new ImageExLazyLoadingControl();
imageExLazyLoadingControl.CloseButtonClick += (s, a) =>

Просмотреть файл

@ -6,6 +6,7 @@
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="{ThemeResource ApplicationForegroundThemeBrush}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="LazyLoadingThreshold" Value="300" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:ImageEx">

Просмотреть файл

@ -54,12 +54,17 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// <summary>
/// Identifies the <see cref="EnableLazyLoading"/> dependency property.
/// </summary>
public static readonly DependencyProperty EnableLazyLoadingProperty = DependencyProperty.Register(nameof(EnableLazyLoading), typeof(bool), typeof(ImageExBase), new PropertyMetadata(false));
public static readonly DependencyProperty EnableLazyLoadingProperty = DependencyProperty.Register(nameof(EnableLazyLoading), typeof(bool), typeof(ImageExBase), new PropertyMetadata(false, EnableLazyLoadingChanged));
/// <summary>
/// Gets a value indicating whether <see cref="EnableLazyLoading"/> is supported
/// Identifies the <see cref="LazyLoadingThreshold"/> dependency property.
/// </summary>
public static bool IsLazyLoadingSupported { get; } = ApiInformation.IsEventPresent("Windows.UI.Xaml.FrameworkElement", nameof(EffectiveViewportChanged));
public static readonly DependencyProperty LazyLoadingThresholdProperty = DependencyProperty.Register(nameof(LazyLoadingThreshold), typeof(double), typeof(ImageExBase), new PropertyMetadata(default(double), LazyLoadingThresholdChanged));
/// <summary>
/// Gets a value indicating whether <see cref="EnableLazyLoading"/> is supported, always return true.
/// </summary>
public static bool IsLazyLoadingSupported { get; } = true;
/// <summary>
/// Returns a mask that represents the alpha channel of an image as a <see cref="CompositionBrush"/>
@ -160,5 +165,30 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
get { return (bool)GetValue(EnableLazyLoadingProperty); }
set { SetValue(EnableLazyLoadingProperty, value); }
}
/// <summary>
/// Gets or sets a value indicating the threshold for triggering lazy loading.
/// </summary>
public double LazyLoadingThreshold
{
get { return (double)GetValue(LazyLoadingThresholdProperty); }
set { SetValue(LazyLoadingThresholdProperty, value); }
}
private static void EnableLazyLoadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ImageExBase control)
{
control.InvalidateLazyLoading();
}
}
private static void LazyLoadingThresholdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ImageExBase control)
{
control.InvalidateLazyLoading();
}
}
}
}

Просмотреть файл

@ -82,7 +82,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
if (IsLazyLoadingSupported)
{
EffectiveViewportChanged += ImageExBase_EffectiveViewportChanged;
LayoutUpdated += ImageExBase_LayoutUpdated;
}
}
@ -213,6 +213,22 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
return base.ArrangeOverride(finalSize);
}
/// <summary>
/// from https://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Rect.cs,04390f584fcba8e4
/// </summary>
private static bool IntersectsWith(Rect rect1, Rect rect2)
{
if (rect1.IsEmpty || rect2.IsEmpty)
{
return false;
}
return (rect1.Left <= rect2.Right) &&
(rect1.Right >= rect2.Left) &&
(rect1.Top <= rect2.Bottom) &&
(rect1.Bottom >= rect2.Top);
}
private void OnImageOpened(object sender, RoutedEventArgs e)
{
ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());
@ -225,15 +241,36 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
VisualStateManager.GoToState(this, FailedState, true);
}
private void ImageExBase_EffectiveViewportChanged(FrameworkElement sender, EffectiveViewportChangedEventArgs args)
private void ImageExBase_LayoutUpdated(object sender, object e)
{
var bringIntoViewDistanceX = args.BringIntoViewDistanceX;
var bringIntoViewDistanceY = args.BringIntoViewDistanceY;
InvalidateLazyLoading();
}
var width = ActualWidth;
var height = ActualHeight;
private void InvalidateLazyLoading()
{
if (!IsLoaded)
{
_isInViewport = false;
return;
}
if (bringIntoViewDistanceX <= width && bringIntoViewDistanceY <= height)
var hostElement = GetHostElement();
if (hostElement == null)
{
_isInViewport = false;
return;
}
var controlRect = TransformToVisual(hostElement)
.TransformBounds(new Rect(0, 0, ActualWidth, ActualHeight));
var lazyLoadingThreshold = LazyLoadingThreshold;
var hostRect = new Rect(
0 - lazyLoadingThreshold,
0 - lazyLoadingThreshold,
hostElement.ActualWidth + (2 * lazyLoadingThreshold),
hostElement.ActualHeight + (2 * lazyLoadingThreshold));
if (IntersectsWith(controlRect, hostRect))
{
_isInViewport = true;
@ -249,5 +286,36 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
_isInViewport = false;
}
}
/// <summary>
/// Find ascendant element until <see cref="ScrollViewer" /> or root element.
/// </summary>
/// <returns><see cref="ScrollViewer"/> or root element.</returns>
private FrameworkElement GetHostElement()
{
FrameworkElement hostElement = this;
while (true)
{
var parent = VisualTreeHelper.GetParent(hostElement) as FrameworkElement;
if (parent == null)
{
break;
}
if (parent is ScrollViewer)
{
return parent;
}
hostElement = parent;
}
if (ReferenceEquals(hostElement, this))
{
return null;
}
return hostElement;
}
}
}