chore: use file-scoped namespace

This commit is contained in:
NaBian committed 2022-03-13 20:28:58 +08:00
1 parent 99d2fafb72
commit bbf1b7d4c6
748 files changed
+57929 -58678

No files matched your search

@@ -15,504 +15,503 @@ using HandyControl.Data;
using HandyControl.Tools;
using HandyControl.Tools.Interop;
namespace HandyControl.Controls
namespace HandyControl.Controls;
public class GifImage : Image, IDisposable
{
public class GifImage : Image, IDisposable
private static readonly Guid GifGuid = new("{b96b3caa-0728-11d3-9d7b-0000f81ef32e}");
private static readonly Guid GifSingleFrameGuid = new("{b96b3cb0-0728-11d3-9d7b-0000f81ef32e}");
internal IntPtr NativeImage;
private byte[] _rawData;
private bool _isStart;
private bool _isLoaded;
static GifImage()
{
private static readonly Guid GifGuid = new("{b96b3caa-0728-11d3-9d7b-0000f81ef32e}");
VisibilityProperty.OverrideMetadata(typeof(GifImage), new PropertyMetadata(default(Visibility), OnVisibilityChanged));
}
private static readonly Guid GifSingleFrameGuid = new("{b96b3cb0-0728-11d3-9d7b-0000f81ef32e}");
public static readonly DependencyProperty UriProperty = DependencyProperty.Register(
"Uri", typeof(Uri), typeof(GifImage), new PropertyMetadata(default(Uri), OnUriChanged));
internal IntPtr NativeImage;
private static void OnUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (GifImage) d;
ctl.StopAnimate();
private byte[] _rawData;
private bool _isStart;
private bool _isLoaded;
static GifImage()
if (e.NewValue != null)
{
VisibilityProperty.OverrideMetadata(typeof(GifImage), new PropertyMetadata(default(Visibility), OnVisibilityChanged));
var v = (Uri) e.NewValue;
ctl.GetGifStreamFromPack(v);
ctl.StartAnimate();
}
else
{
ctl.Source = null;
}
}
public Uri Uri
{
get => (Uri) GetValue(UriProperty);
set => SetValue(UriProperty, value);
}
private static void OnVisibilityChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
{
var ctl = (GifImage) s;
if (ctl.NativeImage == IntPtr.Zero) return;
var v = (Visibility) e.NewValue;
if (v != Visibility.Visible)
{
ctl.StopAnimate();
}
else if (!ctl._isStart)
{
ctl.StartAnimate();
}
}
~GifImage() => Dispose(false);
public GifImage()
{
Loaded += (s, e) =>
{
if (DesignerProperties.GetIsInDesignMode(this)) return;
if (_isLoaded) return;
_isLoaded = true;
if (Uri != null)
{
GetGifStreamFromPack(Uri);
StartAnimate();
}
else if (Source is BitmapImage image)
{
GetGifStreamFromPack(image.UriSource);
StartAnimate();
}
};
Unloaded += (s, e) => Dispose();
}
public GifImage(string filename)
{
Source = null;
CreateSourceFromFile(filename);
StartAnimate();
}
public GifImage(Stream stream)
{
Source = null;
CreateSourceFromStream(stream);
StartAnimate();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (NativeImage == IntPtr.Zero) return;
try
{
StopAnimate();
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(this, NativeImage));
}
catch
{
// ignored
}
finally
{
NativeImage = IntPtr.Zero;
}
}
private void CreateSourceFromFile(string filename)
{
filename = Path.GetFullPath(filename);
var status = InteropMethods.Gdip.GdipCreateBitmapFromFile(filename, out var bitmap);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
status = InteropMethods.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
if (status != InteropMethods.Gdip.Ok)
{
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
throw InteropMethods.Gdip.StatusException(status);
}
public static readonly DependencyProperty UriProperty = DependencyProperty.Register(
"Uri", typeof(Uri), typeof(GifImage), new PropertyMetadata(default(Uri), OnUriChanged));
SetNativeImage(bitmap);
private static void OnUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
EnsureSave(this, filename, null);
}
private void CreateSourceFromStream(Stream stream)
{
if (stream == null)
throw new ArgumentException("stream null");
var status = InteropMethods.Gdip.GdipCreateBitmapFromStream(new GPStream(stream), out var bitmap);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
status = InteropMethods.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
if (status != InteropMethods.Gdip.Ok)
{
var ctl = (GifImage) d;
ctl.StopAnimate();
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
throw InteropMethods.Gdip.StatusException(status);
}
if (e.NewValue != null)
SetNativeImage(bitmap);
EnsureSave(this, null, stream);
}
private void GetGifStreamFromPack(Uri uri)
{
try
{
StreamResourceInfo streamInfo;
if (!uri.IsAbsoluteUri)
{
var v = (Uri) e.NewValue;
ctl.GetGifStreamFromPack(v);
ctl.StartAnimate();
streamInfo = Application.GetContentStream(uri) ?? Application.GetResourceStream(uri);
}
else
{
ctl.Source = null;
}
}
public Uri Uri
{
get => (Uri) GetValue(UriProperty);
set => SetValue(UriProperty, value);
}
private static void OnVisibilityChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
{
var ctl = (GifImage) s;
if (ctl.NativeImage == IntPtr.Zero) return;
var v = (Visibility) e.NewValue;
if (v != Visibility.Visible)
{
ctl.StopAnimate();
}
else if (!ctl._isStart)
{
ctl.StartAnimate();
}
}
~GifImage() => Dispose(false);
public GifImage()
{
Loaded += (s, e) =>
{
if (DesignerProperties.GetIsInDesignMode(this)) return;
if (_isLoaded) return;
_isLoaded = true;
if (Uri != null)
if (uri.GetLeftPart(UriPartial.Authority).Contains("siteoforigin"))
{
GetGifStreamFromPack(Uri);
StartAnimate();
}
else if (Source is BitmapImage image)
{
GetGifStreamFromPack(image.UriSource);
StartAnimate();
}
};
Unloaded += (s, e) => Dispose();
}
public GifImage(string filename)
{
Source = null;
CreateSourceFromFile(filename);
StartAnimate();
}
public GifImage(Stream stream)
{
Source = null;
CreateSourceFromStream(stream);
StartAnimate();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (NativeImage == IntPtr.Zero) return;
try
{
StopAnimate();
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(this, NativeImage));
}
catch
{
// ignored
}
finally
{
NativeImage = IntPtr.Zero;
}
}
private void CreateSourceFromFile(string filename)
{
filename = Path.GetFullPath(filename);
var status = InteropMethods.Gdip.GdipCreateBitmapFromFile(filename, out var bitmap);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
status = InteropMethods.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
if (status != InteropMethods.Gdip.Ok)
{
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
throw InteropMethods.Gdip.StatusException(status);
}
SetNativeImage(bitmap);
EnsureSave(this, filename, null);
}
private void CreateSourceFromStream(Stream stream)
{
if (stream == null)
throw new ArgumentException("stream null");
var status = InteropMethods.Gdip.GdipCreateBitmapFromStream(new GPStream(stream), out var bitmap);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
status = InteropMethods.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
if (status != InteropMethods.Gdip.Ok)
{
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
throw InteropMethods.Gdip.StatusException(status);
}
SetNativeImage(bitmap);
EnsureSave(this, null, stream);
}
private void GetGifStreamFromPack(Uri uri)
{
try
{
StreamResourceInfo streamInfo;
if (!uri.IsAbsoluteUri)
{
streamInfo = Application.GetContentStream(uri) ?? Application.GetResourceStream(uri);
streamInfo = Application.GetRemoteStream(uri);
}
else
{
if (uri.GetLeftPart(UriPartial.Authority).Contains("siteoforigin"))
{
streamInfo = Application.GetRemoteStream(uri);
}
else
{
streamInfo = Application.GetContentStream(uri) ?? Application.GetResourceStream(uri);
}
}
if (streamInfo == null)
{
throw new FileNotFoundException("Resource not found.", uri.ToString());
}
CreateSourceFromStream(streamInfo.Stream);
}
catch
{
// ignored
}
}
private void SwitchToCommonImage()
{
if (Source == null && Uri != null)
{
SetCurrentValue(SourceProperty, new BitmapImage(Uri));
}
}
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
internal static void EnsureSave(GifImage image, string filename, Stream dataStream)
{
if (!image.RawGuid.Equals(GifGuid) && !image.RawGuid.Equals(GifSingleFrameGuid))
{
image.SwitchToCommonImage();
return;
}
var animatedGif = false;
var dimensions = image.FrameDimensionsList;
if (dimensions.Select(guid => new GifFrameDimension(guid)).Contains(GifFrameDimension.Time))
{
animatedGif = image.GetFrameCount(GifFrameDimension.Time) > 1;
}
if (!animatedGif)
{
image.SwitchToCommonImage();
return;
}
try
{
Stream created = null;
long lastPos = 0;
if (dataStream != null)
{
lastPos = dataStream.Position;
dataStream.Position = 0;
}
try
{
if (dataStream == null)
{
created = dataStream = File.OpenRead(filename);
}
image._rawData = new byte[(int) dataStream.Length];
dataStream.Read(image._rawData, 0, (int) dataStream.Length);
}
finally
{
if (created != null)
{
created.Close();
}
else
{
// ReSharper disable once PossibleNullReferenceException
dataStream.Position = lastPos;
}
streamInfo = Application.GetContentStream(uri) ?? Application.GetResourceStream(uri);
}
}
// possible exceptions for reading the filename
catch (UnauthorizedAccessException)
{
}
catch (DirectoryNotFoundException)
{
}
catch (IOException)
{
}
// possible exceptions for setting/getting the position inside dataStream
catch (NotSupportedException)
{
}
catch (ObjectDisposedException)
{
}
// possible exception when reading stuff into dataStream
catch (ArgumentException)
if (streamInfo == null)
{
throw new FileNotFoundException("Resource not found.", uri.ToString());
}
CreateSourceFromStream(streamInfo.Stream);
}
internal void SetNativeImage(IntPtr handle)
catch
{
if (handle == IntPtr.Zero)
throw new ArgumentException("NativeHandle0");
NativeImage = handle;
}
internal Guid RawGuid
{
get
{
var guid = new Guid();
var status = InteropMethods.Gdip.GdipGetImageRawFormat(new HandleRef(this, NativeImage), ref guid);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
return guid;
}
}
internal void StartAnimate()
{
ImageAnimator.Animate(this, OnFrameChanged);
_isStart = true;
}
internal void StopAnimate()
{
ImageAnimator.StopAnimate(this, OnFrameChanged);
_isStart = false;
}
internal Guid[] FrameDimensionsList
{
get
{
var status = InteropMethods.Gdip.GdipImageGetFrameDimensionsCount(new HandleRef(this, NativeImage), out var count);
if (status != InteropMethods.Gdip.Ok)
{
throw InteropMethods.Gdip.StatusException(status);
}
if (count <= 0)
{
return new Guid[0];
}
var size = Marshal.SizeOf(typeof(Guid));
var buffer = Marshal.AllocHGlobal(checked(size * count));
if (buffer == IntPtr.Zero)
{
throw InteropMethods.Gdip.StatusException(InteropMethods.Gdip.OutOfMemory);
}
status = InteropMethods.Gdip.GdipImageGetFrameDimensionsList(new HandleRef(this, NativeImage), buffer, count);
if (status != InteropMethods.Gdip.Ok)
{
Marshal.FreeHGlobal(buffer);
throw InteropMethods.Gdip.StatusException(status);
}
var guids = new Guid[count];
try
{
for (var i = 0; i < count; i++)
{
guids[i] = (Guid) InteropMethods.PtrToStructure((IntPtr) ((long) buffer + size * i), typeof(Guid));
}
}
finally
{
Marshal.FreeHGlobal(buffer);
}
return guids;
}
}
internal int GetFrameCount(GifFrameDimension dimension)
{
var count = new[] { 0 };
var dimensionId = dimension.Guid;
var status = InteropMethods.Gdip.GdipImageGetFrameCount(new HandleRef(this, NativeImage), ref dimensionId, count);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
return count[0];
}
internal GifPropertyItem GetPropertyItem(int propid)
{
GifPropertyItem propitem;
var status = InteropMethods.Gdip.GdipGetPropertyItemSize(new HandleRef(this, NativeImage), propid, out var size);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
if (size == 0)
return null;
var propdata = Marshal.AllocHGlobal(size);
if (propdata == IntPtr.Zero)
throw InteropMethods.Gdip.StatusException(InteropMethods.Gdip.OutOfMemory);
status = InteropMethods.Gdip.GdipGetPropertyItem(new HandleRef(this, NativeImage), propid, size, propdata);
try
{
if (status != InteropMethods.Gdip.Ok)
{
throw InteropMethods.Gdip.StatusException(status);
}
propitem = GifPropertyItemInternal.ConvertFromMemory(propdata, 1)[0];
}
finally
{
Marshal.FreeHGlobal(propdata);
}
return propitem;
}
internal int SelectActiveFrame(GifFrameDimension dimension, int frameIndex)
{
var count = new[] { 0 };
var dimensionId = dimension.Guid;
var status = InteropMethods.Gdip.GdipImageSelectActiveFrame(new HandleRef(this, NativeImage), ref dimensionId, frameIndex);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
return count[0];
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
internal IntPtr GetHbitmap() => GetHbitmap(Colors.LightGray);
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
internal IntPtr GetHbitmap(Color background)
{
var status = InteropMethods.Gdip.GdipCreateHBITMAPFromBitmap(new HandleRef(this, NativeImage), out var hBitmap,
ColorHelper.ToWin32(background));
if (status == 2 && (Width >= short.MaxValue || Height >= short.MaxValue))
{
throw new ArgumentException("GdiplusInvalidSize");
}
if (status != InteropMethods.Gdip.Ok && NativeImage != IntPtr.Zero)
{
throw InteropMethods.Gdip.StatusException(status);
}
return hBitmap;
}
private void GetBitmapSource()
{
var handle = IntPtr.Zero;
try
{
handle = GetHbitmap();
Source = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
catch
{
// ignored
}
finally
{
if (handle != IntPtr.Zero)
{
InteropMethods.DeleteObject(handle);
}
}
}
private void OnFrameChanged(object sender, EventArgs e)
{
Dispatcher.BeginInvoke(new Action(() =>
{
ImageAnimator.UpdateFrames();
Source?.Freeze();
GetBitmapSource();
InvalidateVisual();
}));
// ignored
}
}
}
private void SwitchToCommonImage()
{
if (Source == null && Uri != null)
{
SetCurrentValue(SourceProperty, new BitmapImage(Uri));
}
}
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
internal static void EnsureSave(GifImage image, string filename, Stream dataStream)
{
if (!image.RawGuid.Equals(GifGuid) && !image.RawGuid.Equals(GifSingleFrameGuid))
{
image.SwitchToCommonImage();
return;
}
var animatedGif = false;
var dimensions = image.FrameDimensionsList;
if (dimensions.Select(guid => new GifFrameDimension(guid)).Contains(GifFrameDimension.Time))
{
animatedGif = image.GetFrameCount(GifFrameDimension.Time) > 1;
}
if (!animatedGif)
{
image.SwitchToCommonImage();
return;
}
try
{
Stream created = null;
long lastPos = 0;
if (dataStream != null)
{
lastPos = dataStream.Position;
dataStream.Position = 0;
}
try
{
if (dataStream == null)
{
created = dataStream = File.OpenRead(filename);
}
image._rawData = new byte[(int) dataStream.Length];
dataStream.Read(image._rawData, 0, (int) dataStream.Length);
}
finally
{
if (created != null)
{
created.Close();
}
else
{
// ReSharper disable once PossibleNullReferenceException
dataStream.Position = lastPos;
}
}
}
// possible exceptions for reading the filename
catch (UnauthorizedAccessException)
{
}
catch (DirectoryNotFoundException)
{
}
catch (IOException)
{
}
// possible exceptions for setting/getting the position inside dataStream
catch (NotSupportedException)
{
}
catch (ObjectDisposedException)
{
}
// possible exception when reading stuff into dataStream
catch (ArgumentException)
{
}
}
internal void SetNativeImage(IntPtr handle)
{
if (handle == IntPtr.Zero)
throw new ArgumentException("NativeHandle0");
NativeImage = handle;
}
internal Guid RawGuid
{
get
{
var guid = new Guid();
var status = InteropMethods.Gdip.GdipGetImageRawFormat(new HandleRef(this, NativeImage), ref guid);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
return guid;
}
}
internal void StartAnimate()
{
ImageAnimator.Animate(this, OnFrameChanged);
_isStart = true;
}
internal void StopAnimate()
{
ImageAnimator.StopAnimate(this, OnFrameChanged);
_isStart = false;
}
internal Guid[] FrameDimensionsList
{
get
{
var status = InteropMethods.Gdip.GdipImageGetFrameDimensionsCount(new HandleRef(this, NativeImage), out var count);
if (status != InteropMethods.Gdip.Ok)
{
throw InteropMethods.Gdip.StatusException(status);
}
if (count <= 0)
{
return new Guid[0];
}
var size = Marshal.SizeOf(typeof(Guid));
var buffer = Marshal.AllocHGlobal(checked(size * count));
if (buffer == IntPtr.Zero)
{
throw InteropMethods.Gdip.StatusException(InteropMethods.Gdip.OutOfMemory);
}
status = InteropMethods.Gdip.GdipImageGetFrameDimensionsList(new HandleRef(this, NativeImage), buffer, count);
if (status != InteropMethods.Gdip.Ok)
{
Marshal.FreeHGlobal(buffer);
throw InteropMethods.Gdip.StatusException(status);
}
var guids = new Guid[count];
try
{
for (var i = 0; i < count; i++)
{
guids[i] = (Guid) InteropMethods.PtrToStructure((IntPtr) ((long) buffer + size * i), typeof(Guid));
}
}
finally
{
Marshal.FreeHGlobal(buffer);
}
return guids;
}
}
internal int GetFrameCount(GifFrameDimension dimension)
{
var count = new[] { 0 };
var dimensionId = dimension.Guid;
var status = InteropMethods.Gdip.GdipImageGetFrameCount(new HandleRef(this, NativeImage), ref dimensionId, count);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
return count[0];
}
internal GifPropertyItem GetPropertyItem(int propid)
{
GifPropertyItem propitem;
var status = InteropMethods.Gdip.GdipGetPropertyItemSize(new HandleRef(this, NativeImage), propid, out var size);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
if (size == 0)
return null;
var propdata = Marshal.AllocHGlobal(size);
if (propdata == IntPtr.Zero)
throw InteropMethods.Gdip.StatusException(InteropMethods.Gdip.OutOfMemory);
status = InteropMethods.Gdip.GdipGetPropertyItem(new HandleRef(this, NativeImage), propid, size, propdata);
try
{
if (status != InteropMethods.Gdip.Ok)
{
throw InteropMethods.Gdip.StatusException(status);
}
propitem = GifPropertyItemInternal.ConvertFromMemory(propdata, 1)[0];
}
finally
{
Marshal.FreeHGlobal(propdata);
}
return propitem;
}
internal int SelectActiveFrame(GifFrameDimension dimension, int frameIndex)
{
var count = new[] { 0 };
var dimensionId = dimension.Guid;
var status = InteropMethods.Gdip.GdipImageSelectActiveFrame(new HandleRef(this, NativeImage), ref dimensionId, frameIndex);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
return count[0];
}
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
internal IntPtr GetHbitmap() => GetHbitmap(Colors.LightGray);
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
internal IntPtr GetHbitmap(Color background)
{
var status = InteropMethods.Gdip.GdipCreateHBITMAPFromBitmap(new HandleRef(this, NativeImage), out var hBitmap,
ColorHelper.ToWin32(background));
if (status == 2 && (Width >= short.MaxValue || Height >= short.MaxValue))
{
throw new ArgumentException("GdiplusInvalidSize");
}
if (status != InteropMethods.Gdip.Ok && NativeImage != IntPtr.Zero)
{
throw InteropMethods.Gdip.StatusException(status);
}
return hBitmap;
}
private void GetBitmapSource()
{
var handle = IntPtr.Zero;
try
{
handle = GetHbitmap();
Source = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
catch
{
// ignored
}
finally
{
if (handle != IntPtr.Zero)
{
InteropMethods.DeleteObject(handle);
}
}
}
private void OnFrameChanged(object sender, EventArgs e)
{
Dispatcher.BeginInvoke(new Action(() =>
{
ImageAnimator.UpdateFrames();
Source?.Freeze();
GetBitmapSource();
InvalidateVisual();
}));
}
}
@@ -5,228 +5,227 @@ using System.Windows.Media.Imaging;
using System.Windows.Threading;
using HandyControl.Data;
namespace HandyControl.Controls
namespace HandyControl.Controls;
public class ImageBlock : FrameworkElement
{
public class ImageBlock : FrameworkElement
private readonly DispatcherTimer _dispatcherTimer;
private BitmapSource _source;
private int _indexMax;
private int _indexMin;
private int _currentIndex;
private int _blockWidth;
private int _blockHeight;
private bool _isDisposed;
private int _columns = 1;
public ImageBlock()
{
private readonly DispatcherTimer _dispatcherTimer;
private BitmapSource _source;
private int _indexMax;
private int _indexMin;
private int _currentIndex;
private int _blockWidth;
private int _blockHeight;
private bool _isDisposed;
private int _columns = 1;
public ImageBlock()
_dispatcherTimer = new DispatcherTimer(DispatcherPriority.Render)
{
_dispatcherTimer = new DispatcherTimer(DispatcherPriority.Render)
Interval = Interval
};
IsVisibleChanged += ImageBlock_IsVisibleChanged;
}
~ImageBlock() => Dispose();
public void Dispose()
{
if (_isDisposed) return;
IsVisibleChanged -= ImageBlock_IsVisibleChanged;
_dispatcherTimer.Stop();
_isDisposed = true;
GC.SuppressFinalize(this);
}
private void ImageBlock_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (IsVisible)
{
_dispatcherTimer.Tick += DispatcherTimer_Tick;
if (IsPlaying)
{
Interval = Interval
};
IsVisibleChanged += ImageBlock_IsVisibleChanged;
_dispatcherTimer.Start();
}
}
~ImageBlock() => Dispose();
public void Dispose()
else
{
if (_isDisposed) return;
IsVisibleChanged -= ImageBlock_IsVisibleChanged;
_dispatcherTimer.Stop();
_isDisposed = true;
GC.SuppressFinalize(this);
}
private void ImageBlock_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (IsVisible)
{
_dispatcherTimer.Tick += DispatcherTimer_Tick;
if (IsPlaying)
{
_dispatcherTimer.Start();
}
}
else
{
_dispatcherTimer.Stop();
_dispatcherTimer.Tick -= DispatcherTimer_Tick;
}
}
private void UpdateDatas()
{
if (_source == null) return;
_indexMin = StartRow * _columns + StartColumn;
_indexMax = EndRow * _columns + EndColumn;
_currentIndex = _indexMin;
_blockWidth = _source.PixelWidth / _columns;
_blockHeight = _source.PixelHeight / Rows;
}
private static void OnPositionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (ImageBlock) d;
if (e.Property == ColumnsProperty)
{
ctl._columns = (int) e.NewValue;
}
ctl.UpdateDatas();
}
private void DispatcherTimer_Tick(object sender, EventArgs e) => InvalidateVisual();
public static readonly DependencyProperty StartColumnProperty = DependencyProperty.Register(
"StartColumn", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
public int StartColumn
{
get => (int) GetValue(StartColumnProperty);
set => SetValue(StartColumnProperty, value);
}
public static readonly DependencyProperty StartRowProperty = DependencyProperty.Register(
"StartRow", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
public int StartRow
{
get => (int) GetValue(StartRowProperty);
set => SetValue(StartRowProperty, value);
}
public static readonly DependencyProperty EndColumnProperty = DependencyProperty.Register(
"EndColumn", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
public int EndColumn
{
get => (int) GetValue(EndColumnProperty);
set => SetValue(EndColumnProperty, value);
}
public static readonly DependencyProperty EndRowProperty = DependencyProperty.Register(
"EndRow", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
public int EndRow
{
get => (int) GetValue(EndRowProperty);
set => SetValue(EndRowProperty, value);
}
public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register(
"IsPlaying", typeof(bool), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnIsPlayingChanged));
private static void OnIsPlayingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (ImageBlock) d;
if ((bool) e.NewValue)
{
ctl._dispatcherTimer.Start();
}
else
{
ctl._dispatcherTimer.Stop();
}
}
public bool IsPlaying
{
get => (bool) GetValue(IsPlayingProperty);
set => SetValue(IsPlayingProperty, ValueBoxes.BooleanBox(value));
}
public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register(
"Columns", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int1Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged), obj => (int) obj >= 1);
public int Columns
{
get => (int) GetValue(ColumnsProperty);
set => SetValue(ColumnsProperty, value);
}
public static readonly DependencyProperty RowsProperty = DependencyProperty.Register(
"Rows", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int1Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged), obj => (int) obj >= 1);
public int Rows
{
get => (int) GetValue(RowsProperty);
set => SetValue(RowsProperty, value);
}
public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register(
"Interval", typeof(TimeSpan), typeof(ImageBlock), new PropertyMetadata(TimeSpan.FromSeconds(1), OnIntervalChanged));
private static void OnIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (ImageBlock) d;
ctl._dispatcherTimer.Interval = (TimeSpan) e.NewValue;
}
public TimeSpan Interval
{
get => (TimeSpan) GetValue(IntervalProperty);
set => SetValue(IntervalProperty, value);
}
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
"Source", typeof(ImageSource), typeof(ImageBlock), new FrameworkPropertyMetadata(default(ImageSource),
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnSourceChanged));
private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (ImageBlock) d;
ctl._source = e.NewValue as BitmapSource;
ctl.UpdateDatas();
}
public ImageSource Source
{
get => (ImageSource) GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
protected override void OnRender(DrawingContext dc)
{
if (_source == null) return;
var croppedBitmap = new CroppedBitmap(_source, CalDisplayRect());
dc.DrawImage(croppedBitmap, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
}
private Int32Rect CalDisplayRect()
{
if (_currentIndex > _indexMax)
{
_currentIndex = _indexMin;
}
var x = _currentIndex % _columns * _blockWidth;
var y = _currentIndex / _columns * _blockHeight;
var rect = new Int32Rect(x, y, _blockWidth, _blockHeight);
_currentIndex++;
return rect;
_dispatcherTimer.Tick -= DispatcherTimer_Tick;
}
}
}
private void UpdateDatas()
{
if (_source == null) return;
_indexMin = StartRow * _columns + StartColumn;
_indexMax = EndRow * _columns + EndColumn;
_currentIndex = _indexMin;
_blockWidth = _source.PixelWidth / _columns;
_blockHeight = _source.PixelHeight / Rows;
}
private static void OnPositionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (ImageBlock) d;
if (e.Property == ColumnsProperty)
{
ctl._columns = (int) e.NewValue;
}
ctl.UpdateDatas();
}
private void DispatcherTimer_Tick(object sender, EventArgs e) => InvalidateVisual();
public static readonly DependencyProperty StartColumnProperty = DependencyProperty.Register(
"StartColumn", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
public int StartColumn
{
get => (int) GetValue(StartColumnProperty);
set => SetValue(StartColumnProperty, value);
}
public static readonly DependencyProperty StartRowProperty = DependencyProperty.Register(
"StartRow", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
public int StartRow
{
get => (int) GetValue(StartRowProperty);
set => SetValue(StartRowProperty, value);
}
public static readonly DependencyProperty EndColumnProperty = DependencyProperty.Register(
"EndColumn", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
public int EndColumn
{
get => (int) GetValue(EndColumnProperty);
set => SetValue(EndColumnProperty, value);
}
public static readonly DependencyProperty EndRowProperty = DependencyProperty.Register(
"EndRow", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
public int EndRow
{
get => (int) GetValue(EndRowProperty);
set => SetValue(EndRowProperty, value);
}
public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register(
"IsPlaying", typeof(bool), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnIsPlayingChanged));
private static void OnIsPlayingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (ImageBlock) d;
if ((bool) e.NewValue)
{
ctl._dispatcherTimer.Start();
}
else
{
ctl._dispatcherTimer.Stop();
}
}
public bool IsPlaying
{
get => (bool) GetValue(IsPlayingProperty);
set => SetValue(IsPlayingProperty, ValueBoxes.BooleanBox(value));
}
public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register(
"Columns", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int1Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged), obj => (int) obj >= 1);
public int Columns
{
get => (int) GetValue(ColumnsProperty);
set => SetValue(ColumnsProperty, value);
}
public static readonly DependencyProperty RowsProperty = DependencyProperty.Register(
"Rows", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int1Box,
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged), obj => (int) obj >= 1);
public int Rows
{
get => (int) GetValue(RowsProperty);
set => SetValue(RowsProperty, value);
}
public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register(
"Interval", typeof(TimeSpan), typeof(ImageBlock), new PropertyMetadata(TimeSpan.FromSeconds(1), OnIntervalChanged));
private static void OnIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (ImageBlock) d;
ctl._dispatcherTimer.Interval = (TimeSpan) e.NewValue;
}
public TimeSpan Interval
{
get => (TimeSpan) GetValue(IntervalProperty);
set => SetValue(IntervalProperty, value);
}
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
"Source", typeof(ImageSource), typeof(ImageBlock), new FrameworkPropertyMetadata(default(ImageSource),
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnSourceChanged));
private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (ImageBlock) d;
ctl._source = e.NewValue as BitmapSource;
ctl.UpdateDatas();
}
public ImageSource Source
{
get => (ImageSource) GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
protected override void OnRender(DrawingContext dc)
{
if (_source == null) return;
var croppedBitmap = new CroppedBitmap(_source, CalDisplayRect());
dc.DrawImage(croppedBitmap, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
}
private Int32Rect CalDisplayRect()
{
if (_currentIndex > _indexMax)
{
_currentIndex = _indexMin;
}
var x = _currentIndex % _columns * _blockWidth;
var y = _currentIndex / _columns * _blockHeight;
var rect = new Int32Rect(x, y, _blockWidth, _blockHeight);
_currentIndex++;
return rect;
}
}
File diff suppressed because it is too large. Load diff