using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.Core;
using Tango.Core.Components;
using Tango.PPC.Common.Connection;
namespace Tango.PPC.Common.RemoteAssistance
{
/// <summary>
/// Represents the default remote assistance provider.
/// </summary>
/// <seealso cref="Tango.Core.ExtendedObject" />
/// <seealso cref="Tango.PPC.Common.RemoteAssistance.IRemoteAssistanceProvider" />
public class DefaultRemoteAssistanceProvider : ExtendedObject, IRemoteAssistanceProvider
{
private IMachineProvider _machineProvider;
private String _installer_path = "C:\\Installers\\TeamViewer_Host.msi";
private bool _isEnabled;
/// <summary>
/// Gets a value indicating whether the remote assistance service is enabled.
/// </summary>
public bool IsEnabled
{
get { return _isEnabled; }
private set { _isEnabled = value; RaisePropertyChangedAuto(); }
}
/// <summary>
/// Initializes a new instance of the <see cref="DefaultRemoteAssistanceProvider"/> class.
/// </summary>
/// <param name="machineProvider">The machine provider.</param>
public DefaultRemoteAssistanceProvider(IMachineProvider machineProvider)
{
_machineProvider = machineProvider;
}
/// <summary>
/// Enables the remote assistance.
/// </summary>
/// <returns></returns>
public async Task EnableRemoteAssistance()
{
if (!IsEnabled)
{
try
{
CmdCommand command = new CmdCommand("sc.exe", "config TeamViewer start=auto");
command.Timeout = TimeSpan.FromSeconds(10);
await command.Run();
command = new CmdCommand("net", "start TeamViewer");
command.Timeout = TimeSpan.FromSeconds(10);
await command.Run();
IsEnabled = true;
}
catch (Exception ex)
{
LogManager.Log(ex, "Error enabling remote assistance.");
}
}
}
/// <summary>
/// Disables the remote assistance.
/// </summary>
/// <returns></returns>
public async Task DisableRemoteAssistance()
{
if (IsEnabled)
{
try
{
CmdCommand command = new CmdCommand("sc.exe", "config TeamViewer start=disabled");
command.Timeout = TimeSpan.FromSeconds(10);
await command.Run();
command = new CmdCommand("net", "stop TeamViewer");
command.Timeout = TimeSpan.FromSeconds(10);
await command.Run();
IsEnabled = false;
}
catch (Exception ex)
{
LogManager.Log(ex, "Error disabling remote assistance.");
}
}
}
/// <summary>
/// Installs the remote assistance.
/// </summary>
/// <param name="machineSerialNumber">The machine serial number.</param>
/// <param name="group">The remote assistance group.</param>
/// <param name="environment">The machine working environment.</param>
/// <returns></returns>
/// <exception cref="FileNotFoundException"></exception>
/// <exception cref="ApplicationException">The remote assistance service was installed but could not be found.</exception>
public async Task InstallRemoteAssistance(String machineSerialNumber, String group, String environment)
{
try
{
if (!File.Exists(_installer_path))
{
throw new FileNotFoundException($"The remote assistance installer file could not be found at {_installer_path}.");
}
String q = "\"";
//CmdCommand command = new CmdCommand("msiexec.exe", $"/i \"{_installer_path}\" /qn CUSTOMCONFIGID=ke43ann APITOKEN=4765529-gon1LwO1N1TTrlLI21ji ASSIGNMENTOPTIONS=\" --reassign --alias {"TANGO-" + machineSerialNumber}-{environment} --grant-easy-access\"");
CmdCommand command = new CmdCommand("msiexec.exe", $"/i {q}{_installer_path}{q} /qn CUSTOMCONFIGID=ke43ann APITOKEN=4765529-gon1LwO1N1TTrlLI21ji ASSIGNMENTOPTIONS={q} --group {q}{q} {group} {q}{q} --reassign --alias TANGO-{machineSerialNumber}-{environment} --grant-easy-access{q}");
command.Timeout = TimeSpan.FromSeconds(30);
await command.Run();
bool exist = await IsRemoteAssistanceInstalled();
if (exist)
{
await DisableRemoteAssistance();
}
else
{
throw new ApplicationException("The remote assistance service was installed but could not be found.");
}
}
catch (Exception ex)
{
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */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
}
}