using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.Core;
using Tango.Integration.Dispensing;
using Tango.Integration.Observables;
namespace Tango.Integration.Printing
{
public class LiquidVolume : ExtendedObject
{
private BrushStop _brushStop;
public BrushStop BrushStop
{
get { return _brushStop; }
set { _brushStop = value; RaisePropertyChangedAuto(); }
}
private Configuration _configuration;
public Configuration Configuration
{
get { return _configuration; }
set { _configuration = value; RaisePropertyChangedAuto(); }
}
private IdsPack _idsPack;
public IdsPack IdsPack
{
get { return _idsPack; }
set { _idsPack = value; RaisePropertyChangedAuto(); }
}
private Rml _rml;
public Rml RML
{
get { return _rml; }
set { _rml = value; RaisePropertyChangedAuto(); }
}
private ProcessParametersTable _processParametersTable;
public ProcessParametersTable ProcessParametersTable
{
get { return _processParametersTable; }
set { _processParametersTable = value; RaisePropertyChangedAuto(); }
}
private double _volume;
public double Volume
{
get { return _volume; }
set
{
_volume = value;
RaisePropertyChangedAuto();
OnVolumeChanged();
}
}
private DispenserStepDivisions _dispenserStepDivision;
public DispenserStepDivisions DispenserStepDivision
{
get { return _dispenserStepDivision; }
set { _dispenserStepDivision = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(PulsePerSecond)); }
}
public void Invalidate()
{
InvalidateSolo();
foreach (var liquidVolume in BrushStop.LiquidVolumes.Where(x => x != this))
{
liquidVolume.InvalidateSolo();
}
}
private void InvalidateSolo()
{
_volume = DispensingCalcService.CoerceVolume(this);
typeof(BrushStop).GetProperty("V" + Configuration.IdsPacks.IndexOf(IdsPack)).SetValue(BrushStop, Volume);
RaisePropertyChanged(nameof(LiquidMaxNanoliterPerCentimeter));
RaisePropertyChanged(nameof(NanoliterPerSecond));
RaisePropertyChanged(nameof(PulsePerSecond));
RaisePropertyChanged(nameof(NanoliterPerCentimeter));
RaisePropertyChanged(nameof(Volume));
}
public LiquidVolume(Configuration configuration, IdsPack idsPack, Rml rml, ProcessParametersTable processParametersTable, BrushStop brushStop)
{
ProcessParametersTable = processParametersTable;
BrushStop = brushStop;
IdsPack = idsPack;
Configuration = configuration;
RML = rml;
Volume = (double)typeof(BrushStop).GetProperty("V" + Configuration.IdsPacks.IndexOf(IdsPack)).GetValue(BrushStop);
}
private void OnVolumeChanged()
{
Invalidate();
}
public double LiquidMaxNanoliterPerCentimeter
{
get
{
if (Configuration != null && RML != null)
{
List<LiquidTypesRml> factors = Configuration.IdsPacks.OrderBy(x => x.PackIndex).Select(x => x.LiquidType).SelectMany(x => x.LiquidTypesRmls).Where(x => x.Rml.Guid == RML.Guid).ToList();
if (BrushStop.LiquidVolumes.IndexOf(this) > factors.Count - 1)
{
<using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using Tango.Core.EventArguments;
using Tango.DragAndDrop;
namespace Tango.Touch.Controls
{
public class LightTouchScrollViewer : ContentControl
{
private const double _min_scroll_delta = 20;
private Border _border_viewport;
private Grid _grid_content;
private Point _mouse_down_location;
private List<double> _last_manipulation_deltas;
private const double touch_inertia_coefficiant = 10;
private const double bounce_offset_max = 20;
private Thumb _thumb;
private Border _border_thumb;
private StylusDevice _moveTouchDevice;
private FrameworkElement _down_element;
private bool _is_dragging_off_view;
private DispatcherTimer _dragging_timer;
private DateTime _current_move_time;
private double _current_move_delta;
private double _last_move_delta;
private const double _min_move_delta = 10;
private const double _delta_measure_interval_milli = 10;
private const double _friction_factor_per_second = 0.9;
private DispatcherTimer _move_timer;
private double _last_scroll_position;
#region Events
public delegate void ScrollingEventHandler(object sender, DoubleValueChangedEventArgs e);
public static readonly RoutedEvent ScrollingEvent = EventManager.RegisterRoutedEvent("Scrolling", RoutingStrategy.Bubble, typeof(ScrollingEventHandler), typeof(LightTouchScrollViewer));
/// <summary>
/// Occurs when the scrolling position has changed.
/// </summary>
public event ScrollingEventHandler Scrolling
{
add { AddHandler(ScrollingEvent, value); }
remove { RemoveHandler(ScrollingEvent, value); }
}
#endregion
#region Properties
public Thickness InternalMargin
{
get { return (Thickness)GetValue(InternalMarginProperty); }
set { SetValue(InternalMarginProperty, value); }
}
public static readonly DependencyProperty InternalMarginProperty =
DependencyProperty.Register("InternalMargin", typeof(Thickness), typeof(LightTouchScrollViewer), new PropertyMetadata(default(Thickness), (d, e) => (d as LightTouchScrollViewer).RaiseScrollEvent()));
public Border GetViewportBorder()
{
return _border_viewport;
}
public Grid GetContentGrid()
{
return _grid_content;
}
/// <summary>
/// Gets or sets the scroll bar margins.
/// </summary>
public Thickness ScrollBarMargin
{
get { return (Thickness)GetValue(ScrollBarMarginProperty); }
set { SetValue(ScrollBarMarginProperty, value); }
}
public static readonly DependencyProperty ScrollBarMarginProperty =
DependencyProperty.Register("ScrollBarMargin", typeof(Thickness), typeof(LightTouchScrollViewer), new PropertyMetadata(new Thickness()));
/// <summary>
/// Gets or sets a value indicating whether the data grid is currently scrolling.
/// </summary>
public bool IsScrolling
{
get { return (bool)GetValue(IsScrollingProperty); }
set { SetValue(IsScrollingProperty, value); }
}
public static readonly DependencyProperty IsScrollingProperty =
DependencyProperty.Register("IsScrolling", typeof(bool), typeof(LightTouchScrollViewer), new PropertyMetadata(false));
/// <summary>
/// Gets or sets a value indicating whether the last mouse or touch up event was after scrolling.
/// </summary>
public bool IsAfterScrolling
{
get { return (bool)GetValue(IsAfterScrollingProperty); }
set { SetValue(IsAfterScrollingProperty, value); }
}
public static readonly DependencyProperty IsAfterScrollingProperty =
DependencyProperty.Register("IsAfterScrolling", typeof(bool), typeof(LightTouchScrollViewer), new PropertyMetadata(false));
/// <summary>
/// Gets or sets a value indicating whether this instance is mouse touch down.
/// </summary>
public bool IsMouseTouchDown
{
get { return (bool)GetValue(IsMouseTouchDownProperty); }
set { SetValue(IsMouseTouchDownProperty, value); }
}
public static readonly DependencyProperty IsMouseTouchDownProperty =
DependencyProperty.Register("IsMouseTouchDown", typeof(bool), typeof(LightTouchScrollViewer), new PropertyMetadata(false));
/// <summary>
/// Gets or sets the width of the scroll bar.
/// </summary>
/// <value>
/// The width of the scroll bar.
/// </value>
public double ScrollBarWidth
{
get { return (double)GetValue(ScrollBarWidthProperty); }
set { SetValue(ScrollBarWidthProperty, value); }
}
public static readonly DependencyProperty ScrollBarWidthProperty =
DependencyProperty.Register("ScrollBarWidth", typeof(double), typeof(LightTouchScrollViewer), new PropertyMetadata(5.0));
/// <summary>
/// Gets or sets the scroll bar background.
/// </summary>
public Brush ScrollBarBackground
{
get { return (Brush)GetValue(ScrollBarBackgroundProperty); }
set { SetValue(ScrollBarBackgroundProperty, value); }
}
public static readonly DependencyProperty ScrollBarBackgroundProperty =
DependencyProperty.Register("ScrollBarBackground", typeof(Brush), typeof(LightTouchScrollViewer), new PropertyMetadata(null));
/// <summary>
/// Gets or sets the scroll bar foreground.
/// </summary>
public Brush ScrollBarForeground
{
get { return (Brush)GetValue(ScrollBarForegroundProperty); }
set { SetValue(ScrollBarForegroundProperty, value); }
}
public static readonly DependencyProperty ScrollBarForegroundProperty =
DependencyProperty.Register("ScrollBarForeground", typeof(Brush), typeof(LightTouchScrollViewer), new PropertyMetadata(null));
/// <summary>
/// Gets or sets the scroll bar corner radius.
/// </summary>
public CornerRadius ScrollBarCornerRadius
{
get { return (CornerRadius)GetValue(ScrollBarCornerRadiusProperty); }
set { SetValue(ScrollBarCornerRadiusProperty, value); }
}
public static readonly DependencyProperty ScrollBarCornerRadiusProperty =
DependencyProperty.Register("ScrollBarCornerRadius", typeof(CornerRadius), typeof(LightTouchScrollViewer), new PropertyMetadata(default(CornerRadius)));
/// <summary>
/// Gets or sets the size of the top arc.
/// </summary>
public Size TopArcSize
{
get { return (Size)GetValue(TopArcSizeProperty); }
set { SetValue(TopArcSizeProperty, value); }
}
public static readonly DependencyProperty TopArcSizeProperty =
DependencyProperty.Register("TopArcSize", typeof(Size), typeof(LightTouchScrollViewer), new PropertyMetadata(default(Size)));
/// <summary>
/// Gets or sets the size of the bottom arc.
/// </summary>
public Size BottomArcSize
{
get { return (Size)GetValue(BottomArcSizeProperty); }
set { SetValue(BottomArcSizeProperty, value); }
}
public static readonly DependencyProperty BottomArcSizeProperty =
DependencyProperty.Register("BottomArcSize", typeof(Size), typeof(LightTouchScrollViewer), new PropertyMetadata(default(Size)));
public bool DisableScrolling
{
get { return (bool)GetValue(DisableScrollingProperty); }
set { SetValue(DisableScrollingProperty, value); }
}
public static readonly DependencyProperty DisableScrollingProperty =
DependencyProperty.Register("DisableScrolling", typeof(bool), typeof(LightTouchScrollViewer), new PropertyMetadata(false));
/// <summary>
/// Gets or sets the scroll bar visibility.
/// </summary>
public Visibility ScrollBarVisibility
{
get { return (Visibility)GetValue(ScrollBarVisibilityProperty); }
set { SetValue(ScrollBarVisibilityProperty, value); }
}
public static readonly DependencyProperty ScrollBarVisibilityProperty =
DependencyProperty.Register("ScrollBarVisibility", typeof(Visibility), typeof(LightTouchScrollViewer), new PropertyMetadata(Visibility.Visible));
#endregion
#region Constructors
public LightTouchScrollViewer()
{
_last_manipulation_deltas = new List<double>();
}
static LightTouchScrollViewer()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(LightTouchScrollViewer), new FrameworkPropertyMetadata(typeof(LightTouchScrollViewer)));
}
#endregion
#region Apply Template
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_border_viewport = GetTemplateChild("PART_Border") as Border;
_grid_content = GetTemplateChild("PART_Grid_Content") as Grid;
_thumb = GetTemplateChild("PART_Thumb") as Thumb;
_border_thumb = GetTemplateChild("PART_Thumb_Border") as Border;
ContentPresenter presenter = GetTemplateChild("PART_Content_Presenter") as ContentPresenter;
_border_viewport.RegisterForMouseOrTouchDown(OnMouseTouchDown);
_border_viewport.RegisterForMouseOrStylusMove(OnMouseTouchMove);
_border_viewport.RegisterForPreviewMouseOrTouchUp(OnMouseTouchUp);
//_border_viewport.ManipulationDelta += _grid_rows_ManipulationDelta;
//_border_viewport.ManipulationCompleted += _grid_rows_ManipulationCompleted;
_thumb.DragDelta += _thumb_DragDelta;
_thumb.DragStarted += _thumb_DragStarted;
_thumb.DragCompleted += _thumb_DragCompleted;
this.Bind(InternalMarginProperty, _grid_content, Grid.MarginProperty, System.Windows.Data.BindingMode.OneWay);
}
private void _thumb_DragCompleted(object sender, DragCompletedEventArgs e)
{
IsScrolling = false;
}
private void _thumb_DragStarted(object sender, DragStartedEventArgs e)
{
IsScrolling = true;
}
private void _thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
var step = CalculateScrollbarThumbStep();
double content_margin = _grid_content.Margin.Top + -(step * e.VerticalChange);
_grid_content.BeginAnimation(Grid.MarginProperty, null);
Canvas.SetTop(_border_thumb, Canvas.GetTop(_border_thumb) + e.VerticalChange);
_grid_content.Margin = new Thickness(0, content_margin, 0, 0);
if (content_margin > 0)
{
Canvas.SetTop(_border_thumb, 0);
_grid_content.Margin = new Thickness(0, 0, 0, 0);
}
else if (content_margin - _border_viewport.ActualHeight < -_grid_content.ActualHeight)
{
Canvas.SetTop(_border_thumb, _border_viewport.ActualHeight - _border_thumb.ActualHeight);
_grid_content.Margin = new Thickness(0, -(_grid_content.ActualHeight - _border_viewport.ActualHeight), 0, 0);
}
}
#endregion
#region Touch Manipulation Handlers
/// <summary>
/// Handles the ManipulationCompleted event of the _grid_rows control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="ManipulationCompletedEventArgs"/> instance containing the event data.</param>
//private void _grid_rows_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
//{
// //_border_viewport.IsManipulationEnabled = false;
// ReleaseMouseTouchCapture();
// e.Cancel();
// if (!IsAfterScrolling) return;
// if (_last_manipulation_deltas.Count == 0) return;
// var last_10 = _last_manipulation_deltas.TakeLast(10);
// double last_10_avg = last_10.TakeLast(10).Average();
// double max_delta = last_10.First(x => Math.Abs(x) == last_10.Max(y => Math.Abs(y)));
// if (Math.Abs(last_10_avg) > 5)
// {
// var to = (_grid_content.Margin.Top + (max_delta * touch_inertia_coefficiant));
// if (to > 0)
// {
// to = Math.Min(to, bounce_offset_max);
// }
// else
// {
// to = Math.Max(to, bounce_offset_max + -(_grid_content.ActualHeight - _border_viewport.ActualHeight));
// }
// bool bounced = false;
// ThicknessAnimation ani = new ThicknessAnimation();
// ani.Duration = TimeSpan.FromSeconds(1);
// ani.To = new Thickness(0, to, 0, 0);
// ani.CurrentTimeInvalidated += (_, __) =>
// {
// if (!bounced)
// {
// if (_grid_content.Margin.Top > 0 || (_grid_content.Margin.Top - _border_viewport.ActualHeight < -_grid_content.ActualHeight))
// {
// bounced = true;
// SnapContentToBounds();
// }
// }
// SetThumbPosition();
// };
// ani.DecelerationRatio = 1.0;
// _grid_content.BeginAnimation(Grid.MarginProperty, ani);
// _last_manipulation_deltas.Clear();
// }
//}
/// <summary>
/// Handles the ManipulationDelta event of the _grid_rows control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="ManipulationDeltaEventArgs"/> instance containing the event data.</param>
//private void _grid_rows_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
//{
// _last_manipulation_deltas.Add(e.DeltaManipulation.Translation.Y);
//}
#endregion
#region Attached Properties
#region Prevent Scroll
/// <summary>
/// The prevent scroll property
/// </summary>
public static readonly DependencyProperty PreventScrollProperty =
DependencyProperty.RegisterAttached("PreventScroll",
typeof(bool), typeof(LightTouchScrollViewer),
new FrameworkPropertyMetadata(false));
/// <summary>
/// Sets the PreventScroll attached property.
/// </summary>
/// <param name="element">The element.</param>
/// <param name="value">if set to <c>true</c> [value].</param>
public static void SetPreventScroll(FrameworkElement element, bool value)
{
element.SetValue(PreventScrollProperty, value);
}
/// <summary>
/// Gets the PreventScroll attached property.
/// </summary>
/// <param name="element">The element.</param>
/// <returns></returns>
public static bool GetPreventScroll(FrameworkElement element)
{
if (element != null)
{
return (bool)element.GetValue(PreventScrollProperty);
}
else
{
return false;
}
}
#endregion
#endregion
#region Touch / Mouse Handlers
/// <summary>
/// Called when the mouse touch has been down
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="MouseOrTouchEventArgs"/> instance containing the event data.</param>
protected virtual void OnMouseTouchDown(object sender, MouseOrTouchEventArgs e)
{
_current_move_delta = 0;
if (DisableScrolling) return;
IsAfterScrolling = false;
if (_move_timer != null)
{
Debug.WriteLine("INERTIA STOPPED!");
_move_timer.Stop();
}
_down_element = e.OriginalSource as FrameworkElement;
if (e.OriginalSource.GetType() == typeof(DragThumb))
{
return;
}
var element = e.OriginalSource as FrameworkElement;
if (element != null)
{
if (element.FindAncestor<LightTouchScrollViewer>() != this)
{
return;
}
if (GetPreventScroll(element)) return;
var parentPreventScroll = element.FindAncestor((x) => GetPreventScroll(x as FrameworkElement));
if (parentPreventScroll != null) return;
}
_mouse_down_location = new Point(e.Location.X, e.Location.Y - _grid_content.Margin.Top);
IsMouseTouchDown = true;
_last_move_delta = e.Location.Y;
_current_move_time = DateTime.Now;
}
/// <summary>
/// Called when the mouse touch has been move
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="MouseOrTouchEventArgs"/> instance containing the event data.</param>
protected virtual void OnMouseTouchMove(object sender, MouseOrTouchEventArgs e)
{
if (DisableScrolling) return;
if (_down_element is DragThumb)
{
if (e.Location.Y > ActualHeight - 100)
{
//Start animating down.
if (!_is_dragging_off_view)
{
_is_dragging_off_view = true;
_dragging_timer = new DispatcherTimer();
_dragging_timer.Interval = TimeSpan.FromMilliseconds(30);
_dragging_timer.Tick += (x, y) =>
{
ScrollToPosition(GetScrollPosition() + 15);
};
_dragging_timer.Start();
}
}
else if (e.Location.Y < 100)
{
//Start animating up.
if (!_is_dragging_off_view)
{
_is_dragging_off_view = true;
_dragging_timer = new DispatcherTimer();
_dragging_timer.Interval = TimeSpan.FromMilliseconds(30);
_dragging_timer.Tick += (x, y) =>
{
ScrollToPosition(GetScrollPosition() - 15);
};
_dragging_timer.Start();
}
}
else
{
if (_is_dragging_off_view)
{
_is_dragging_off_view = false;
_dragging_timer.Stop();
}
}
}
var a = _mouse_down_location.Y + _grid_content.Margin.Top;
if (IsMouseTouchDown && (Math.Abs((e.Location.Y - a)) > _min_scroll_delta) || IsScrolling)
{
if (!IsScrolling)
{
//_border_viewport.IsManipulationEnabled = true;
IsScrolling = true;
Mouse.Capture(_border_viewport);
if (e.StylusDevice != null)
{
_moveTouchDevice = e.StylusDevice;
e.StylusDevice.Capture(_border_viewport);
}
}
double position_y = e.Location.Y - _mouse_down_location.Y;
double bottom_offset = -(_grid_content.ActualHeight - (_border_viewport.ActualHeight + -position_y));
if (_grid_content.ActualHeight > _border_viewport.ActualHeight)
{
_grid_content.BeginAnimation(Grid.MarginProperty, null);
_grid_content.Margin = new Thickness(0, position_y, 0, 0);
if (_grid_content.Margin.Top > 0)
{
_grid_content.Margin = new Thickness(0, 0, 0, 0);
}
if (_grid_content.Margin.Top < -(_grid_content.ActualHeight - _border_viewport.ActualHeight))
{
_grid_content.Margin = new Thickness(0, -(_grid_content.ActualHeight - _border_viewport.ActualHeight), 0, 0);
}
}
if (position_y > 0)
{
BeginAnimation(TopArcSizeProperty, null);
TopArcSize = new Size(250, Math.Min(position_y / 15, 100));
}
else if (bottom_offset > 0)
{
BeginAnimation(BottomArcSizeProperty, null);
BottomArcSize = new Size(250, Math.Min(bottom_offset / 15, 100));
}
SetThumbPosition();
DateTime curDate = DateTime.Now;
if (curDate >= _current_move_time.AddMilliseconds(_delta_measure_interval_milli))
{
if (e.Location.Y - _last_move_delta != 0)
{
_current_move_delta = e.Location.Y - _last_move_delta;
}
_last_move_delta = e.Location.Y;
_current_move_time = curDate;
}
}
}
/// <summary>
/// Called when the mouse touch has been up
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="MouseOrTouchEventArgs"/> instance containing the event data.</param>
protected virtual void OnMouseTouchUp(object sender, MouseOrTouchEventArgs e)
{
if (DisableScrolling)
{
IsMouseTouchDown = false;
ReleaseMouseTouchCapture();
return;
}
if (_is_dragging_off_view)
{
_is_dragging_off_view = false;
_dragging_timer.Stop();
}
if (IsMouseTouchDown)
{
IsMouseTouchDown = false;
if (IsScrolling)
{
double max_move_delta = 120;
double strengh = Math.Abs(_current_move_delta) / max_move_delta;
Debug.WriteLine((DateTime.Now - _current_move_time).TotalMilliseconds);
Debug.WriteLine("MOVE DELTA: " + _current_move_delta);
//Emulate inertia
if (Math.Abs(_current_move_delta) > _min_move_delta && DateTime.Now <= _current_move_time.AddMilliseconds(100))
{
double pixels_per_second = _current_move_delta * (_delta_measure_interval_milli * 10);
Debug.WriteLine("INERTIA STARTED!");
DateTime cur_time = DateTime.Now;
Debug.WriteLine("FROM: " + _grid_content.Margin.Top + " TO: " + (_grid_content.Margin.Top + (pixels_per_second) / 100));
_move_timer = new DispatcherTimer();
_move_timer.Interval = TimeSpan.FromMilliseconds(10);
_move_timer.Tick += (x, y) =>
{
double to = _grid_content.Margin.Top + (pixels_per_second) / 100;
_grid_content.Margin = new Thickness(0, to, 0, 0);
if (_grid_content.Margin.Top > 0)
{
_grid_content.Margin = new Thickness(0, 0, 0, 0);
}
if (_grid_content.Margin.Top < -(_grid_content.ActualHeight - _border_viewport.ActualHeight))
{
_grid_content.Margin = new Thickness(0, -(_grid_content.ActualHeight - _border_viewport.ActualHeight), 0, 0);
}
if (_grid_content.Margin.Top > bounce_offset_max || (_grid_content.Margin.Top - _border_viewport.ActualHeight < -_grid_content.ActualHeight))
{
_move_timer.Stop();
SnapContentToBounds();
SetThumbPosition();
Debug.WriteLine("INERTIA STOPPED BY SNAPPING!");
return;
}
if (DateTime.Now > cur_time.AddMilliseconds(300 * strengh))
{
pixels_per_second *= _friction_factor_per_second;
}
SetThumbPosition();
if (pixels_per_second > -2 && pixels_per_second < 2)
{
_move_timer.Stop();
_move_timer = null;
Debug.WriteLine("INERTIA STOPPED!");
}
};
_move_timer.Start();
}
IsAfterScrolling = true;
ReleaseMouseTouchCapture();
e.Handled = true;
SnapContentToBounds();
}
else
{
IsAfterScrolling = false;
}
IsScrolling = false;
}
}
/// <summary>
/// Invoked when an unhandled <see cref="E:System.Windows.Input.Mouse.MouseWheel" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
/// </summary>
/// <param name="e">The <see cref="T:System.Windows.Input.MouseWheelEventArgs" /> that contains the event data.</param>
protected override void OnMouseWheel( MouseWheelEventArgs e)
{
base.OnMouseWheel(e);
if (DisableScrolling)
{
return;
}
base.OnMouseWheel(e);
if (!e.Handled )
{
if (e.Delta != 0)
{
var scrollPos = GetScrollPosition();
if (e.Delta > 0)
{
scrollPos -= 15;
}
else if(e.Delta < 0)
{
scrollPos += 15;
}
ScrollToPosition(scrollPos);
SetThumbPosition();
}
}
e.Handled = false;
}
#endregion
#region Private Methods
private double CalculateScrollbarThumbStep()
{
var scrollTrackSpace = _grid_content.ActualHeight - _border_viewport.ActualHeight;
var scrollThumbSpace = _border_viewport.ActualHeight - _thumb.ActualHeight;
var scrollJump = scrollTrackSpace / scrollThumbSpace;
return scrollJump;
}
private void SetThumbPosition()
{
double step = CalculateScrollbarThumbStep();
if (step != 0)
{
double content_margin = _grid_content.Margin.Top;
double thumb_top = -(content_margin / step);
Canvas.SetTop(_border_thumb, thumb_top);
if (thumb_top < 0)
{
Canvas.SetTop(_border_thumb, 0);
}
else if (thumb_top + _border_thumb.ActualHeight > _border_viewport.ActualHeight)
{
Canvas.SetTop(_border_thumb, _border_viewport.ActualHeight - _border_thumb.ActualHeight);
}
}
}
private void ReleaseMouseTouchCapture()
{
Mouse.Capture(null);
_border_viewport.ReleaseMouseCapture();
_border_viewport.ReleaseAllTouchCaptures();
if (_moveTouchDevice != null)
{
_border_viewport.ReleaseStylusCapture();
_moveTouchDevice = null;
}
}
public Rect GetViewPortRect()
{
return new Rect(0, -_grid_content.Margin.Top, _border_viewport.ActualWidth, _border_viewport.ActualHeight);
}
private Rect GetElementRect(FrameworkElement element)
{
if (element != null)
{
return new Rect(element.TranslatePoint(new Point(0, 0), _grid_content), new Size(element.ActualWidth, element.ActualHeight));
}
return new Rect();
}
#endregion
#region Public Methods
public void ScrollToElement(FrameworkElement element)
{
if (element != null)
{
var e = this.FindVisualChildren<FrameworkElement>().SingleOrDefault(x => x == element);
if (e != null)
{
var location = e.TranslatePoint(new Point(0, 0), _grid_content);
Rect elementRect = new Rect(location, new Size(e.ActualWidth, e.ActualHeight));
Rect viewPortRect = new Rect(0, 0, _border_viewport.ActualWidth, _border_viewport.ActualHeight);
ScrollToPosition((location.Y - (viewPortRect.Height / 2)) + (elementRect.Height / 2));
}
}
}
public void ScrollToTop()
{
ScrollToPosition(0);
}
public void ScrollToPosition(double y)
{
if (_grid_content != null)
{
if (_grid_content.ActualHeight > _border_viewport.ActualHeight)
{
if (y < 0)
{
y = 0;
}
if (-y - _border_viewport.ActualHeight < -_grid_content.ActualHeight)
{
y = (_grid_content.ActualHeight - _border_viewport.ActualHeight);
}
_grid_content.BeginAnimation(Grid.MarginProperty, null);
_grid_content.Margin = new Thickness(0, -y, 0, 0);
}
SnapContentToBounds();
}
}
public double GetScrollPosition()
{
double position = -_grid_content.Margin.Top;
if (position < 0)
{
position = 0;
}
if (position > (_grid_content.ActualHeight - _border_viewport.ActualHeight))
{
position = (_grid_content.ActualHeight - _border_viewport.ActualHeight);
}
return position;
}
/// <summary>
/// Snaps the content if it's out of bounds.
/// </summary>
public void SnapContentToBounds()
{
ThicknessAnimation ani = new ThicknessAnimation();
ani.Duration = TimeSpan.FromSeconds(0.2);
ani.AccelerationRatio = 1;
SizeAnimation sizeAni = new SizeAnimation();
sizeAni.Duration = TimeSpan.FromSeconds(0.5);
sizeAni.AccelerationRatio = 1;
sizeAni.To = new Size(250, 0);
BeginAnimation(TopArcSizeProperty, sizeAni);
BeginAnimation(BottomArcSizeProperty, sizeAni);
if (_grid_content.Margin.Top > 0 || _grid_content.ActualHeight < _border_viewport.ActualHeight)
{
//ani.To = new Thickness(0);
_grid_content.Margin = new Thickness(0);
//_grid_content.BeginAnimation(Grid.MarginProperty, ani);
}
else if (_grid_content.Margin.Top - _border_viewport.ActualHeight < -_grid_content.ActualHeight)
{
//ani.To = new Thickness(0, -(_grid_content.ActualHeight - _border_viewport.ActualHeight), 0, 0);
_grid_content.Margin = new Thickness(0, -(_grid_content.ActualHeight - _border_viewport.ActualHeight), 0, 0);
//_grid_content.BeginAnimation(Grid.MarginProperty, ani);
}
}
/// <summary>
/// Gets the most visible element.
/// </summary>
/// <returns></returns>
public FrameworkElement GetMostVisibleElement()
{
var elements = _grid_content.FindVisualChildren<FrameworkElement>().ToList();
if (elements.Count > 0)
{
var viewPort = GetViewPortRect();
var mostVisible = elements.OrderBy(x => Rect.Intersect(viewPort, GetElementRect(x)).Height).Last();
return mostVisible;
}
return null;
}
public Point GetElementPosition(FrameworkElement element)
{
return element.TranslatePoint(new Point(0, 0), this);
}
public T GetMostVisibleElementDataContext<T>() where T : class
{
var elements = _grid_content.FindVisualChildren<FrameworkElement>().Where(x => x.DataContext is T).ToList();
if (elements.Count > 0)
{
var viewPort = GetViewPortRect();
var mostVisible = elements.OrderBy(x => Rect.Intersect(viewPort, GetElementRect(x)).Height).Last();
return mostVisible.DataContext as T;
}
return null;
}
#endregion
#region Virtual Methods
/// <summary>
/// Raises the scroll event.
/// </summary>
protected virtual void RaiseScrollEvent()
{
double position = GetScrollPosition();
if (_last_scroll_position != position)
{
_last_scroll_position = position;
DoubleValueChangedEventArgs e = new DoubleValueChangedEventArgs(ScrollingEvent, this, position);
RaiseEvent(e);
}
}
#endregion
}
}