maui-linux/Xamarin.Forms.Core/ImageElement.cs

152 строки
5.1 KiB
C#

using System;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms
{
static class ImageElement
{
public static readonly BindableProperty FileImageProperty = BindableProperty.Create("Image", typeof(FileImageSource), typeof(IImageElement), default(FileImageSource),
propertyChanging: OnImageSourceChanging, propertyChanged: OnImageSourceChanged);
public static readonly BindableProperty SourceProperty = BindableProperty.Create(nameof(IImageElement.Source), typeof(ImageSource), typeof(IImageElement), default(ImageSource),
propertyChanging: OnImageSourceChanging, propertyChanged: OnImageSourceChanged);
public static readonly BindableProperty AspectProperty = BindableProperty.Create(nameof(IImageElement.Aspect), typeof(Aspect), typeof(IImageElement), Aspect.AspectFit);
public static readonly BindableProperty IsOpaqueProperty = BindableProperty.Create(nameof(IImageElement.IsOpaque), typeof(bool), typeof(IImageElement), false);
static void OnImageSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
ImageSource newSource = (ImageSource)newValue;
IImageElement image = (IImageElement)bindable;
if (newSource != null && image != null)
{
newSource.SourceChanged += image.OnImageSourcesSourceChanged;
}
ImageSourceChanged(bindable, newSource);
}
static void OnImageSourceChanging(BindableObject bindable, object oldValue, object newValue)
{
ImageSource oldSource = (ImageSource)oldValue;
IImageElement image = (IImageElement)bindable;
if (oldSource != null && image != null)
{
oldSource.SourceChanged -= image.OnImageSourcesSourceChanged;
}
ImageSourceChanging(oldSource);
}
public static SizeRequest Measure(IImageElement ImageElementManager, SizeRequest desiredSize, double widthConstraint, double heightConstraint)
{
double desiredAspect = desiredSize.Request.Width / desiredSize.Request.Height;
double constraintAspect = widthConstraint / heightConstraint;
double desiredWidth = desiredSize.Request.Width;
double desiredHeight = desiredSize.Request.Height;
if (desiredWidth == 0 || desiredHeight == 0)
return new SizeRequest(new Size(0, 0));
double width = desiredWidth;
double height = desiredHeight;
if (constraintAspect > desiredAspect)
{
// constraint area is proportionally wider than image
switch (ImageElementManager.Aspect)
{
case Aspect.AspectFit:
case Aspect.AspectFill:
height = Math.Min(desiredHeight, heightConstraint);
width = desiredWidth * (height / desiredHeight);
break;
case Aspect.Fill:
width = Math.Min(desiredWidth, widthConstraint);
height = desiredHeight * (width / desiredWidth);
break;
}
}
else if (constraintAspect < desiredAspect)
{
// constraint area is proportionally taller than image
switch (ImageElementManager.Aspect)
{
case Aspect.AspectFit:
case Aspect.AspectFill:
width = Math.Min(desiredWidth, widthConstraint);
height = desiredHeight * (width / desiredWidth);
break;
case Aspect.Fill:
height = Math.Min(desiredHeight, heightConstraint);
width = desiredWidth * (height / desiredHeight);
break;
}
}
else
{
// constraint area is same aspect as image
width = Math.Min(desiredWidth, widthConstraint);
height = desiredHeight * (width / desiredWidth);
}
return new SizeRequest(new Size(width, height));
}
public static void OnBindingContextChanged(IImageElement image, VisualElement visualElement)
{
if (image.Source != null)
BindableObject.SetInheritedBindingContext(image.Source, visualElement?.BindingContext);
}
public static void ImageSourceChanging(ImageSource oldImageSource)
{
if (oldImageSource == null) return;
try
{
// This method generates are particularly unhappy async/await state-machine combined
// with the CoW mechanisms of the try/catch that actually makes it worth avoiding
// if oldValue is null (which it often is). Early return does not prevent the
// state-machine mechanisms being kicked in, only moving to another method will do that.
CancelOldValue(oldImageSource);
}
catch (ObjectDisposedException)
{
// Workaround bugzilla 37792 https://bugzilla.xamarin.com/show_bug.cgi?id=37792
}
}
async static void CancelOldValue(ImageSource oldvalue)
{
try
{
await oldvalue.Cancel();
}
catch (ObjectDisposedException)
{
// Workaround bugzilla 37792 https://bugzilla.xamarin.com/show_bug.cgi?id=37792
}
}
public static void ImageSourceChanged(BindableObject bindable, ImageSource newSource)
{
var visualElement = (VisualElement)bindable;
if (newSource != null)
BindableObject.SetInheritedBindingContext(newSource, visualElement?.BindingContext);
visualElement?.InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
}
public static void ImageSourcesSourceChanged(object sender, EventArgs e)
{
if (sender is IImageElement imageController)
imageController.RaiseImageSourcePropertyChanged();
((VisualElement)sender).InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
}
}
}