Files
HandyControl/src/Shared/HandyControl_Shared/Controls/Image/ImageBlock.cs
T
2020-06-28 22:39:27 +08:00

224 lines
8.1 KiB
C#

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using HandyControl.Data;
namespace HandyControl.Controls
{
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;
public ImageBlock()
{
_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)
{
_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;
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;
}
}
}