diff options
Diffstat (limited to 'Xamarin.Forms.Core/ImageSource.cs')
-rw-r--r-- | Xamarin.Forms.Core/ImageSource.cs | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/Xamarin.Forms.Core/ImageSource.cs b/Xamarin.Forms.Core/ImageSource.cs new file mode 100644 index 00000000..71e75952 --- /dev/null +++ b/Xamarin.Forms.Core/ImageSource.cs @@ -0,0 +1,142 @@ +using System; +using System.IO; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; + +namespace Xamarin.Forms +{ + [TypeConverter(typeof(ImageSourceConverter))] + public abstract class ImageSource : Element + { + readonly object _synchandle = new object(); + CancellationTokenSource _cancellationTokenSource; + + TaskCompletionSource<bool> _completionSource; + + internal ImageSource() + { + } + + protected CancellationTokenSource CancellationTokenSource + { + get { return _cancellationTokenSource; } + private set + { + if (_cancellationTokenSource == value) + return; + if (_cancellationTokenSource != null) + _cancellationTokenSource.Cancel(); + _cancellationTokenSource = value; + } + } + + bool IsLoading + { + get { return _cancellationTokenSource != null; } + } + + public virtual Task<bool> Cancel() + { + if (!IsLoading) + return Task.FromResult(false); + + var tcs = new TaskCompletionSource<bool>(); + TaskCompletionSource<bool> original = Interlocked.CompareExchange(ref _completionSource, tcs, null); + if (original == null) + { + _cancellationTokenSource.Cancel(); + } + else + tcs = original; + + return tcs.Task; + } + + public static ImageSource FromFile(string file) + { + return new FileImageSource { File = file }; + } + + public static ImageSource FromResource(string resource, Type resolvingType) + { + return FromResource(resource, resolvingType.GetTypeInfo().Assembly); + } + + public static ImageSource FromResource(string resource, Assembly sourceAssembly = null) + { + if (sourceAssembly == null) + { + MethodInfo callingAssemblyMethod = typeof(Assembly).GetTypeInfo().GetDeclaredMethod("GetCallingAssembly"); + if (callingAssemblyMethod != null) + { + sourceAssembly = (Assembly)callingAssemblyMethod.Invoke(null, new object[0]); + } + else + { + Log.Warning("Warning", "Can not find CallingAssembly, pass resolvingType to FromResource to ensure proper resolution"); + return null; + } + } + + return FromStream(() => sourceAssembly.GetManifestResourceStream(resource)); + } + + public static ImageSource FromStream(Func<Stream> stream) + { + return new StreamImageSource { Stream = token => Task.Run(stream, token) }; + } + + public static ImageSource FromUri(Uri uri) + { + if (!uri.IsAbsoluteUri) + throw new ArgumentException("uri is relative"); + return new UriImageSource { Uri = uri }; + } + + public static implicit operator ImageSource(string source) + { + Uri uri; + return Uri.TryCreate(source, UriKind.Absolute, out uri) && uri.Scheme != "file" ? FromUri(uri) : FromFile(source); + } + + public static implicit operator ImageSource(Uri uri) + { + if (!uri.IsAbsoluteUri) + throw new ArgumentException("uri is relative"); + return FromUri(uri); + } + + protected void OnLoadingCompleted(bool cancelled) + { + if (!IsLoading || _completionSource == null) + return; + + TaskCompletionSource<bool> tcs = Interlocked.Exchange(ref _completionSource, null); + if (tcs != null) + tcs.SetResult(cancelled); + + lock(_synchandle) + { + CancellationTokenSource = null; + } + } + + protected void OnLoadingStarted() + { + lock(_synchandle) + { + CancellationTokenSource = new CancellationTokenSource(); + } + } + + protected void OnSourceChanged() + { + EventHandler eh = SourceChanged; + if (eh != null) + eh(this, EventArgs.Empty); + } + + internal event EventHandler SourceChanged; + } +}
\ No newline at end of file |