Last active
June 24, 2018 01:23
-
-
Save ertugrulozcan/124b8f187e9d290ce5e984fab48fe712 to your computer and use it in GitHub Desktop.
Telerik RadGridView Excel Costume
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<UserControl x:Class="Test.Common.Components.ExcelCostume" | |
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |
xmlns:local="clr-namespace:Test.Common.Components" | |
mc:Ignorable="d" | |
d:DesignHeight="300" d:DesignWidth="300" | |
IsHitTestVisible="True"> | |
<UserControl.Resources> | |
<ControlTemplate x:Key="DraggableBorderTemplate" TargetType="{x:Type ContentControl}"> | |
<Border Background="{TemplateBinding Background}" BorderBrush="Green" BorderThickness="{TemplateBinding BorderThickness}"> | |
<ContentPresenter /> | |
</Border> | |
<ControlTemplate.Triggers> | |
<DataTrigger Binding="{Binding Path=IsManipulating, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Value="False"> | |
<Setter Property="Background" Value="{x:Null}" /> | |
<Setter Property="BorderThickness" Value="2" /> | |
</DataTrigger> | |
<DataTrigger Binding="{Binding Path=IsManipulating, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Value="True"> | |
<Setter Property="Background" Value="#33000000" /> | |
<Setter Property="BorderThickness" Value="3" /> | |
</DataTrigger> | |
</ControlTemplate.Triggers> | |
</ControlTemplate> | |
<ControlTemplate x:Key="CellClipsTemplate" TargetType="{x:Type UserControl}"> | |
<Border IsManipulationEnabled="True" Width="12" Height="12" Background="Transparent" BorderThickness="0"> | |
<local:Triangle TriangleOrientation="SE" Stroke="Green" Fill="Green" StrokeThickness="1" /> | |
</Border> | |
<ControlTemplate.Triggers> | |
<Trigger Property="IsMouseOver" Value="True"> | |
<Setter Property="Cursor" Value="Cross" /> | |
</Trigger> | |
</ControlTemplate.Triggers> | |
</ControlTemplate> | |
</UserControl.Resources> | |
<Grid x:Name="CostumeBorder" VerticalAlignment="Top" HorizontalAlignment="Left"> | |
<ContentControl Template="{StaticResource DraggableBorderTemplate}"> | |
<!--<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"> | |
<TextBlock Text="{Binding Path=TestString, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Foreground="AliceBlue" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" /> | |
<TextBlock Text="{Binding Path=TestString2, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Foreground="AliceBlue" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" /> | |
</StackPanel>--> | |
</ContentControl> | |
<UserControl x:Name="Clips" IsManipulationEnabled="True" Template="{StaticResource CellClipsTemplate}" IsHitTestVisible="True" VerticalAlignment="Bottom" HorizontalAlignment="Right" /> | |
</Grid> | |
</UserControl> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Windows; | |
using System.Windows.Controls; | |
using System.Windows.Data; | |
using System.Windows.Documents; | |
using System.Windows.Input; | |
using System.Windows.Media; | |
using System.Windows.Media.Imaging; | |
using System.Windows.Navigation; | |
using System.Windows.Shapes; | |
using Telerik.Windows.Controls; | |
using Telerik.Windows.Controls.GridView; | |
using Test.Infrastructure.Helpers; | |
namespace Test.Common.Components | |
{ | |
/// <summary> | |
/// Interaction logic for ExcelCostume.xaml | |
/// </summary> | |
public partial class ExcelCostume : UserControl, INotifyPropertyChanged | |
{ | |
#region Fields | |
private bool isDragging; | |
private Point dragStartPosition; | |
private Bounds firstBounds; | |
private ScanDirection scanDirection; | |
private TransformGroup transformGroup; | |
private ScaleTransform scaleTransform; | |
private TranslateTransform translateTransform; | |
#endregion | |
#region Properties | |
public bool IsManipulating | |
{ | |
get | |
{ | |
return isDragging; | |
} | |
set | |
{ | |
this.isDragging = value; | |
this.RaisePropertyChanged("IsManipulating"); | |
} | |
} | |
private Point ManipulationStartPoint { get; set; } | |
public TransformGroup CostumeBorderTransforms | |
{ | |
get | |
{ | |
if (this.transformGroup == null) | |
{ | |
this.transformGroup = new TransformGroup(); | |
this.translateTransform = new TranslateTransform(); | |
this.transformGroup.Children.Add(this.translateTransform); | |
this.scaleTransform = new ScaleTransform(); | |
this.transformGroup.Children.Add(this.scaleTransform); | |
this.CostumeBorder.RenderTransform = this.transformGroup; | |
} | |
return this.transformGroup; | |
} | |
} | |
#endregion | |
#region Dependency Properties | |
public RadGridView GridView | |
{ | |
get { return (RadGridView)GetValue(GridViewProperty); } | |
set { SetValue(GridViewProperty, value); } | |
} | |
// Using a DependencyProperty as the backing store for GridView. This enables animation, styling, binding, etc... | |
public static readonly DependencyProperty GridViewProperty = | |
DependencyProperty.Register("GridView", typeof(RadGridView), typeof(ExcelCostume), new PropertyMetadata(null, OnGridViewChangedCallback)); | |
public bool IsSelectScanningCells | |
{ | |
get { return (bool)GetValue(IsSelectScanningCellsProperty); } | |
set { SetValue(IsSelectScanningCellsProperty, value); } | |
} | |
// Using a DependencyProperty as the backing store for IsSelectScanningCells. This enables animation, styling, binding, etc... | |
public static readonly DependencyProperty IsSelectScanningCellsProperty = | |
DependencyProperty.Register("IsSelectScanningCells", typeof(bool), typeof(ExcelCostume), new PropertyMetadata(false)); | |
public string TestString | |
{ | |
get { return (string)GetValue(TestStringProperty); } | |
set { SetValue(TestStringProperty, value); } | |
} | |
// Using a DependencyProperty as the backing store for TestString. This enables animation, styling, binding, etc... | |
public static readonly DependencyProperty TestStringProperty = | |
DependencyProperty.Register("TestString", typeof(string), typeof(ExcelCostume), new PropertyMetadata(null)); | |
public string TestString2 | |
{ | |
get { return (string)GetValue(TestString2Property); } | |
set { SetValue(TestString2Property, value); } | |
} | |
// Using a DependencyProperty as the backing store for TestString2. This enables animation, styling, binding, etc... | |
public static readonly DependencyProperty TestString2Property = | |
DependencyProperty.Register("TestString2", typeof(string), typeof(ExcelCostume), new PropertyMetadata(null)); | |
#endregion | |
#region Constructors | |
public ExcelCostume() | |
{ | |
InitializeComponent(); | |
this.Loaded += ExcelCostume_Loaded; | |
} | |
private void ExcelCostume_Loaded(object sender, RoutedEventArgs e) | |
{ | |
var createTransforms = this.CostumeBorderTransforms; | |
this.ConfigureManipulationEvents(); | |
} | |
#endregion | |
#region Methods | |
private void ConfigureManipulationEvents() | |
{ | |
this.CostumeBorder.MouseLeftButtonDown += new MouseButtonEventHandler(Clips_MouseLeftButtonDown); | |
this.CostumeBorder.MouseLeftButtonUp += new MouseButtonEventHandler(Clips_MouseLeftButtonUp); | |
this.CostumeBorder.MouseMove += new MouseEventHandler(Clips_MouseMove); | |
this.GridView.LostMouseCapture += (sender, e) => { this.IsManipulating = false; }; | |
this.Clips.ManipulationStarting += Clips_ManipulationStarting; | |
this.Clips.ManipulationStarted += Clips_ManipulationStarted; | |
this.Clips.ManipulationDelta += Clips_ManipulationDelta; | |
this.Clips.ManipulationCompleted += Clips_ManipulationCompleted; | |
} | |
#endregion | |
#region Callback Methods | |
private static void OnGridViewChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
{ | |
var self = d as ExcelCostume; | |
if (self.GridView != null) | |
{ | |
if (e.OldValue != null && e.OldValue is RadGridView) | |
{ | |
var oldGridView = e.OldValue as RadGridView; | |
oldGridView.CurrentCellChanged -= self.GridView_CurrentCellChanged; | |
self.GridView.SelectedCellsChanged -= self.GridView_SelectedCellsChanged; | |
} | |
if (self.GridView.SelectionMode != SelectionMode.Extended || self.GridView.SelectionUnit != Telerik.Windows.Controls.GridView.GridViewSelectionUnit.Cell) | |
throw new Exception("SelectionMode is must be 'Extended' and SelectionUnit is must be 'Cell' for ExcelCostume!"); | |
self.GridView.CurrentCellChanged += self.GridView_CurrentCellChanged; | |
self.GridView.SelectedCellsChanged += self.GridView_SelectedCellsChanged; | |
} | |
} | |
#endregion | |
#region Mouse Events | |
private void Clips_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) | |
{ | |
Point pt = e.GetPosition(this.Clips); | |
// Perform the hit test against a given portion of the visual object tree. | |
HitTestResult result = VisualTreeHelper.HitTest(this.Clips, pt); | |
if (result != null) | |
{ | |
this.IsManipulating = true; | |
var draggableControl = sender as FrameworkElement; | |
var pointAsClips = e.GetPosition(this.Clips); | |
var point = e.GetPosition(this); | |
this.dragStartPosition = new Point(point.X + this.Clips.ActualWidth - pointAsClips.X, point.Y + this.Clips.ActualHeight - pointAsClips.Y); | |
this.firstBounds = this.GetScannedBounds(draggableControl); | |
draggableControl.CaptureMouse(); | |
} | |
} | |
private void Clips_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) | |
{ | |
this.IsManipulating = false; | |
var draggable = sender as FrameworkElement; | |
draggable.ReleaseMouseCapture(); | |
this.AutoFillTable(draggable); | |
} | |
private void Clips_MouseMove(object sender, MouseEventArgs e) | |
{ | |
var draggableControl = sender as FrameworkElement; | |
if (this.IsManipulating && draggableControl != null) | |
{ | |
Point currentPosition = e.GetPosition(this.Parent as UIElement); | |
double dragOffsetX = currentPosition.X - dragStartPosition.X; | |
double dragOffsetY = currentPosition.Y - dragStartPosition.Y; | |
//this.scanDirection = Math.Abs(dragOffsetY) > Math.Abs(dragOffsetX) ? ScanDirection.Vertical : ScanDirection.Horizontal; | |
this.scanDirection = this.DetectScanDirection(this.firstBounds, e.GetPosition(this.GridView)); | |
double newWidth = this.firstBounds.Width + dragOffsetX; | |
double newHeight = this.firstBounds.Height + dragOffsetY; | |
// Fill to under cell edges | |
Size differentToEdges = new Size(); | |
var underCell = this.GetCell(currentPosition) as GridViewCell; | |
if (underCell != null) | |
{ | |
Point pointAsUnderCell = e.GetPosition(underCell as UIElement); | |
double differentToEdgesWidth = Math.Abs(underCell.ActualWidth - pointAsUnderCell.X); | |
double differentToEdgesHeight = Math.Abs(underCell.ActualHeight - pointAsUnderCell.Y); | |
if (newWidth >= 0) | |
differentToEdges.Width = differentToEdgesWidth; | |
else | |
differentToEdges.Width = underCell.ActualWidth - differentToEdgesWidth; | |
if (newHeight >= 0) | |
differentToEdges.Height = differentToEdgesHeight; | |
else | |
differentToEdges.Height = underCell.ActualHeight - differentToEdgesHeight; | |
} | |
else | |
{ | |
this.TestString2 = "NULL"; | |
} | |
if (newWidth >= 0) | |
{ | |
this.scaleTransform.ScaleX = 1; | |
this.translateTransform.X = 0; | |
} | |
else | |
{ | |
this.scaleTransform.ScaleX = -1; | |
this.translateTransform.X = -this.firstBounds.Width; | |
newWidth -= this.firstBounds.Width; | |
} | |
if (underCell != null) | |
{ | |
if (this.scanDirection == ScanDirection.Horizontal) | |
draggableControl.Width = Math.Abs(newWidth) + differentToEdges.Width; | |
else | |
draggableControl.Width = this.firstBounds.Width; | |
} | |
if (newHeight >= 0) | |
{ | |
this.scaleTransform.ScaleY = 1; | |
this.translateTransform.Y = 0; | |
} | |
else | |
{ | |
this.scaleTransform.ScaleY = -1; | |
this.translateTransform.Y = -this.firstBounds.Height; | |
newHeight -= this.firstBounds.Height; | |
} | |
if (underCell != null) | |
{ | |
if (this.scanDirection == ScanDirection.Vertical) | |
draggableControl.Height = Math.Abs(newHeight) + differentToEdges.Height; | |
else | |
draggableControl.Height = this.firstBounds.Height; | |
} | |
} | |
} | |
#endregion | |
#region Manipulation Events | |
private void Clips_ManipulationStarting(object sender, ManipulationStartingEventArgs e) | |
{ | |
this.TestString = "ManipulationStarting"; | |
} | |
private void Clips_ManipulationStarted(object sender, ManipulationStartedEventArgs e) | |
{ | |
this.TestString = "ManipulationStarted"; | |
} | |
private void Clips_ManipulationDelta(object sender, ManipulationDeltaEventArgs e) | |
{ | |
this.TestString = "ManipulationDelta (" + e.DeltaManipulation.Translation.X + ", " + e.DeltaManipulation.Translation.Y + ")"; | |
} | |
private void Clips_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) | |
{ | |
this.TestString = "ManipulationCompleted"; | |
} | |
#endregion | |
#region Scanning Methods | |
private Bounds GetScannedBounds(FrameworkElement scannedArea) | |
{ | |
if (scannedArea == null || this.GridView.CurrentCell == null) | |
{ | |
return new Bounds(0, 0, 0, 0); | |
} | |
var orderedSelectedCells = this.GetSelectedCellList(); | |
if (orderedSelectedCells.Count > 0) | |
{ | |
var point = this.GetCellCoordinate(orderedSelectedCells.First()); | |
if (point != null) | |
{ | |
Point currentCellCoordinate = point.Value; | |
int x = (int)(currentCellCoordinate.X - this.translateTransform.X); | |
if (this.translateTransform.X < 0) | |
x = x - (int)scannedArea.ActualWidth; | |
int y = (int)(currentCellCoordinate.Y - this.translateTransform.Y); | |
if (this.translateTransform.Y < 0) | |
y = y - (int)scannedArea.ActualHeight; | |
return new Bounds(x, y, scannedArea.ActualWidth, scannedArea.ActualHeight); | |
} | |
} | |
return new Bounds(0, 0, 0, 0); | |
} | |
private ScanDirection DetectScanDirection(Bounds scannedBounds, Point mousePoint) | |
{ | |
if (mousePoint.X < scannedBounds.LeftTopCorner.X + scannedBounds.Width && mousePoint.X > scannedBounds.LeftTopCorner.X) | |
{ | |
if (mousePoint.Y < scannedBounds.LeftTopCorner.Y) | |
return ScanDirection.Up; | |
else if (mousePoint.Y > scannedBounds.LeftTopCorner.Y + scannedBounds.Height) | |
return ScanDirection.Down; | |
} | |
if (mousePoint.Y < scannedBounds.LeftTopCorner.Y + scannedBounds.Height && mousePoint.Y > scannedBounds.LeftTopCorner.Y) | |
{ | |
if (mousePoint.X < scannedBounds.LeftTopCorner.X) | |
return ScanDirection.Left; | |
else if (mousePoint.X > scannedBounds.LeftTopCorner.X + scannedBounds.Width) | |
return ScanDirection.Right; | |
} | |
Point metacentrePoint = this.FindMetacentre(scannedBounds); | |
double angle = this.CalculateAngle(metacentrePoint, mousePoint); | |
this.TestString = angle.ToString("N2"); | |
if (angle >= 45 && angle < 135) | |
return ScanDirection.Right; | |
else if (angle >= 135 && angle < 225) | |
return ScanDirection.Down; | |
else if (angle >= 225 && angle < 315) | |
return ScanDirection.Left; | |
else //if (angle > 315 && angle < 45) | |
return ScanDirection.Up; | |
} | |
private Point FindMetacentre(Bounds bounds) | |
{ | |
return new Point(bounds.LeftTopCorner.X + bounds.Width / 2, bounds.LeftTopCorner.Y + bounds.Height / 2); | |
} | |
private double CalculateAngle(Point origin, Point point) | |
{ | |
double x = point.X - origin.X; | |
double y = origin.Y - point.Y; | |
double angle = Math.Abs(Math.Atan(y / x) * 180 / Math.PI); | |
if (x >= 0 && y >= 0) | |
return 90 - angle; | |
if (x < 0 && y < 0) | |
return 270 - angle; | |
if (x <= 0 && y > 0) | |
return 270 + angle; | |
if (y <= 0 && x > 0) | |
return 90 + angle; | |
return 0; | |
} | |
#endregion | |
#region Auto Fill Methods | |
private void AutoFillTable(FrameworkElement scannedArea) | |
{ | |
Bounds bounds = this.GetScannedBounds(scannedArea); | |
var patternGroup = this.RecognizePattern(this.firstBounds, this.scanDirection); | |
var filledSeries = this.GenerateFilledSeries(bounds, patternGroup, this.scanDirection); | |
var targetBounds = bounds - this.firstBounds; | |
if (targetBounds != null) | |
{ | |
var targetTable = this.GetTableInBounds(targetBounds); | |
this.FillTable(filledSeries, targetTable, this.scanDirection); | |
} | |
} | |
private void FillTable(List<double[]> filledSeries, CellTable table, ScanDirection direction) | |
{ | |
if (direction == ScanDirection.Vertical) | |
{ | |
for (int columnNo = 0; columnNo < filledSeries.Count; columnNo++) | |
{ | |
var serie = filledSeries[columnNo]; | |
if (direction == ScanDirection.Up) | |
serie = serie.Reverse().ToArray(); | |
for (int rowNo = 0; rowNo < serie.Length; rowNo++) | |
{ | |
table.SetCellValue(rowNo, columnNo, serie[rowNo]); | |
} | |
} | |
} | |
else | |
{ | |
for (int rowNo = 0; rowNo < filledSeries.Count; rowNo++) | |
{ | |
var serie = filledSeries[rowNo]; | |
if (direction == ScanDirection.Left) | |
serie = serie.Reverse().ToArray(); | |
for (int columnNo = 0; columnNo < serie.Length; columnNo++) | |
{ | |
table.SetCellValue(rowNo, columnNo, serie[columnNo]); | |
} | |
} | |
} | |
} | |
private List<double[]> GenerateFilledSeries(Bounds scannedBounds, PatternGroup patternGroup, ScanDirection direction) | |
{ | |
List<double[]> filledSeries = new List<double[]>(); | |
var table = this.GetTableInBounds(scannedBounds); | |
if (table == null || patternGroup == null) | |
return filledSeries; | |
int x, y; | |
if (direction == ScanDirection.Vertical) | |
{ | |
x = patternGroup.Table.ColumnCount; | |
y = patternGroup.Table.RowCount; | |
} | |
else | |
{ | |
x = patternGroup.Table.RowCount; | |
y = patternGroup.Table.ColumnCount; | |
} | |
List<double[]> series = new List<double[]>(); | |
for (int i = 0; i < x; i++) | |
{ | |
series.Add(new double[y]); | |
for (int j = 0; j < y; j++) | |
{ | |
if (direction == ScanDirection.Vertical) | |
{ | |
var cellValue = patternGroup.Table.GetCellValue(j, i, this.GridView.Language.IetfLanguageTag); | |
if (cellValue != null) | |
series[i][j] = cellValue.Value; | |
} | |
else | |
{ | |
var cellValue = patternGroup.Table.GetCellValue(i, j, this.GridView.Language.IetfLanguageTag); | |
if (cellValue != null) | |
series[i][j] = cellValue.Value; | |
} | |
} | |
} | |
int fillLength = 0; | |
bool isInversed = false; | |
Point sourcePoint = patternGroup.Table.GetCellLocation(0, 0, this.GridView); | |
Point targetPoint = table.GetCellLocation(0, 0, this.GridView); | |
if (direction == ScanDirection.Vertical) | |
{ | |
if (sourcePoint.X > targetPoint.X) | |
{ | |
isInversed = true; | |
fillLength = (int)sourcePoint.X - (int)targetPoint.X; | |
} | |
else | |
{ | |
isInversed = false; | |
fillLength = table.RowCount - patternGroup.Table.RowCount; | |
} | |
} | |
else | |
{ | |
if (sourcePoint.Y > targetPoint.Y) | |
{ | |
isInversed = true; | |
fillLength = (int)sourcePoint.Y - (int)targetPoint.Y; | |
} | |
else | |
{ | |
isInversed = false; | |
fillLength = table.ColumnCount - patternGroup.Table.ColumnCount; | |
} | |
} | |
if (fillLength <= 0) | |
return filledSeries; | |
int patternNo = 0; | |
foreach (var pattern in patternGroup.Patterns) | |
{ | |
if (!isInversed) | |
{ | |
var serie = pattern.GenerateSerie(series[patternNo], fillLength); | |
filledSeries.Add(serie); | |
} | |
else | |
{ | |
var serie = pattern.GenerateInverseSerie(series[patternNo], fillLength); | |
filledSeries.Add(serie); | |
} | |
patternNo++; | |
} | |
return filledSeries; | |
} | |
#endregion | |
#region Manipulation Methods | |
private new void ManipulationStarting(MouseDevice mouse) | |
{ | |
} | |
private new void ManipulationStarted(MouseDevice mouse) | |
{ | |
this.IsManipulating = true; | |
this.ManipulationStartPoint = mouse.GetPosition(this.GridView); | |
} | |
private new void ManipulationDelta(MouseDevice mouse) | |
{ | |
Point mousePosition = mouse.GetPosition(this.GridView); | |
double deltaX = mousePosition.X - this.ManipulationStartPoint.X; | |
double deltaY = mousePosition.Y - this.ManipulationStartPoint.Y; | |
double newWidth = this.CostumeBorder.Width + deltaX; | |
if (newWidth >= 0.0d) | |
this.CostumeBorder.Width = newWidth; | |
double newHeight = this.CostumeBorder.Height + deltaY; | |
if (newHeight >= 0.0d) | |
this.CostumeBorder.Height = newHeight; | |
} | |
private void ManipulationComplete(MouseDevice mouse) | |
{ | |
this.IsManipulating = false; | |
} | |
#endregion | |
#region Pattern Recognition Methods | |
private PatternGroup RecognizePattern(Bounds bounds, ScanDirection direction) | |
{ | |
var table = this.GetTableInBounds(bounds); | |
if (table == null) | |
return null; | |
int x, y; | |
if (direction == ScanDirection.Vertical) | |
{ | |
x = table.ColumnCount; | |
y = table.RowCount; | |
} | |
else | |
{ | |
x = table.RowCount; | |
y = table.ColumnCount; | |
} | |
IAutoFillPattern[] patterns = new IAutoFillPattern[x]; | |
if (y == 1) | |
{ | |
for (int i = 0; i < x; i++) | |
patterns[i] = new IncrementalPattern(0.0d); | |
return new PatternGroup(patterns, table); | |
} | |
if (y == 2) | |
{ | |
for (int i = 0; i < x; i++) | |
{ | |
double? value1, value2; | |
if (direction == ScanDirection.Vertical) | |
{ | |
value1 = table.GetCellValue(0, i, this.GridView.Language.IetfLanguageTag); | |
value2 = table.GetCellValue(1, i, this.GridView.Language.IetfLanguageTag); | |
} | |
else | |
{ | |
value1 = table.GetCellValue(i, 0, this.GridView.Language.IetfLanguageTag); | |
value2 = table.GetCellValue(i, 1, this.GridView.Language.IetfLanguageTag); | |
} | |
if (value1 != null && value2 != null) | |
patterns[i] = new IncrementalPattern(value2.Value - value1.Value); | |
else | |
patterns[i] = new IrregularPattern(); | |
} | |
return new PatternGroup(patterns, table); | |
} | |
for (int i = 0; i < x; i++) | |
{ | |
bool isIncremental = false; | |
double diff = 0.0d; | |
for (int j = 1; j < y - 1; j++) | |
{ | |
double? value1, value2, value3; | |
if (direction == ScanDirection.Vertical) | |
{ | |
value1 = table.GetCellValue(j - 1, i, this.GridView.Language.IetfLanguageTag); | |
value2 = table.GetCellValue(j, i, this.GridView.Language.IetfLanguageTag); | |
value3 = table.GetCellValue(j + 1, i, this.GridView.Language.IetfLanguageTag); | |
} | |
else | |
{ | |
value1 = table.GetCellValue(i, j - 1, this.GridView.Language.IetfLanguageTag); | |
value2 = table.GetCellValue(i, j, this.GridView.Language.IetfLanguageTag); | |
value3 = table.GetCellValue(i, j + 1, this.GridView.Language.IetfLanguageTag); | |
} | |
if (value1 != null && value2 != null && value3 != null) | |
{ | |
diff = value3.Value - value2.Value; | |
if (diff == value2.Value - value1.Value) | |
{ | |
isIncremental = true; | |
continue; | |
} | |
else | |
{ | |
isIncremental = false; | |
break; | |
} | |
} | |
} | |
if (isIncremental) | |
patterns[i] = new IncrementalPattern(diff); | |
else | |
patterns[i] = new IrregularPattern(); | |
} | |
return new PatternGroup(patterns, table); | |
} | |
#endregion | |
#region GridView Events | |
private void GridView_CurrentCellChanged(object sender, GridViewCurrentCellChangedEventArgs e) | |
{ | |
if (e.NewCell != null) | |
{ | |
string cellValue = e.NewCell.DataContext.ToString(); | |
if (e.NewCell.Content is Control) | |
cellValue = (e.NewCell.Content as Control).DataContext.ToString(); | |
this.scaleTransform.ScaleX = 1; | |
this.scaleTransform.ScaleY = 1; | |
this.translateTransform.X = 0; | |
this.translateTransform.Y = 0; | |
} | |
} | |
private void GridView_SelectedCellsChanged(object sender, Telerik.Windows.Controls.GridView.GridViewSelectedCellsChangedEventArgs e) | |
{ | |
if (this.GridView.SelectedCells.Count > 0) | |
{ | |
var orderedSelectedCells = this.GetSelectedCellList(); | |
var leftTopCellPoint = this.GetCellCoordinate(orderedSelectedCells.FirstOrDefault()); | |
if (leftTopCellPoint != null) | |
{ | |
this.CostumeBorder.Margin = new Thickness(leftTopCellPoint.Value.X, leftTopCellPoint.Value.Y, 0, 0); | |
var lastCell = this.GetCell(orderedSelectedCells.Last()); | |
if (lastCell != null) | |
{ | |
var rightBottomCellPoint = this.GetCellCoordinate(orderedSelectedCells.Last()); | |
if (rightBottomCellPoint != null) | |
{ | |
double width = rightBottomCellPoint.Value.X - leftTopCellPoint.Value.X + lastCell.ActualWidth; | |
if (width >= 0) | |
this.CostumeBorder.Width = width; | |
double height = rightBottomCellPoint.Value.Y - leftTopCellPoint.Value.Y + lastCell.ActualHeight; | |
if (height >= 0) | |
this.CostumeBorder.Height = height; | |
} | |
} | |
} | |
} | |
} | |
#endregion | |
#region Helper Methods | |
private GridViewCellBase GetCell(GridViewCellInfo cellInfo) | |
{ | |
if (cellInfo == null || cellInfo.Item == null) | |
return null; | |
var cellContainer = this.GridView.ItemContainerGenerator.ContainerFromItem(cellInfo.Item); | |
if (cellContainer == null || !(cellContainer is GridViewRow)) | |
return null; | |
var row = cellContainer as GridViewRow; | |
var cell = row.Cells[cellInfo.Column.DisplayIndex]; | |
return cell; | |
} | |
private Point? GetCellCoordinate(GridViewCellInfo cellInfo) | |
{ | |
var cell = this.GetCell(cellInfo); | |
if (cell == null) | |
return null; | |
return cell.TranslatePoint(new Point(0, 0), this.GridView); | |
} | |
private double GetCellCoordinateDistance(GridViewCellInfo cellInfo) | |
{ | |
var point = this.GetCellCoordinate(cellInfo); | |
if (point != null) | |
return point.Value.X * point.Value.Y; | |
else | |
return 0; | |
} | |
private GridViewCellBase GetCell(Point point) | |
{ | |
foreach (var item in this.GridView.Items) | |
{ | |
var cellContainer = this.GridView.ItemContainerGenerator.ContainerFromItem(item); | |
if (cellContainer != null && cellContainer is GridViewRow) | |
{ | |
var row = cellContainer as GridViewRow; | |
foreach (var cell in row.Cells) | |
{ | |
Point cellPoint = cell.TranslatePoint(new Point(0, 0), this.GridView); | |
if (this.IsInBounds(point, cellPoint, cell.ActualWidth, cell.ActualHeight)) | |
{ | |
return cell; | |
} | |
} | |
} | |
} | |
return null; | |
} | |
private List<GridViewCellInfo> GetSelectedCellList() | |
{ | |
if (this.GridView.SelectedCells.Count <= 0) | |
return new List<GridViewCellInfo>(); | |
var selectedCells = this.GridView.SelectedCells.Where(x => x.Item != null).ToList(); | |
var orderedSelectedCells = selectedCells.OrderBy(x => this.GetCellCoordinateDistance(x)).ToList(); | |
return orderedSelectedCells; | |
} | |
private bool IsInBounds(Point point, Point boundStartPoint, double boundWidth, double boundHeight) | |
{ | |
return (point.X >= boundStartPoint.X && point.X < (boundStartPoint.X + boundWidth)) && | |
(point.Y >= boundStartPoint.Y && point.Y < (boundStartPoint.Y + boundHeight)); | |
} | |
private List<GridViewCellBase> GetCellsInBounds(Bounds bounds) | |
{ | |
var cells = new List<GridViewCellBase>(); | |
int startX = (int)bounds.LeftTopCorner.X + 3; | |
int startY = (int)bounds.LeftTopCorner.Y + 3; | |
var leftTopCell = this.GetCell(new Point(startX, startY)); | |
int endX = (int)(bounds.LeftTopCorner.X + bounds.Width) - 3; | |
int endY = (int)(bounds.LeftTopCorner.Y + bounds.Height) - 3; | |
var rightBottomCell = this.GetCell(new Point(endX, endY)); | |
if (leftTopCell != null && rightBottomCell != null) | |
{ | |
int firstRowIndex = this.GridView.ItemContainerGenerator.IndexFromContainer(leftTopCell.ParentRow); | |
int lastRowIndex = this.GridView.ItemContainerGenerator.IndexFromContainer(rightBottomCell.ParentRow); | |
for (int i = firstRowIndex; i <= lastRowIndex; i++) | |
{ | |
var cellContainer = this.GridView.ItemContainerGenerator.ContainerFromIndex(i); | |
if (cellContainer != null && cellContainer is GridViewRow) | |
{ | |
var row = cellContainer as GridViewRow; | |
for (int columnNo = leftTopCell.Column.DisplayIndex; columnNo <= rightBottomCell.Column.DisplayIndex; columnNo++) | |
{ | |
cells.Add(row.Cells[columnNo]); | |
} | |
} | |
} | |
} | |
return cells; | |
} | |
private CellTable GetTableInBounds(Bounds bounds) | |
{ | |
if (bounds == null) | |
return null; | |
int startX = (int)bounds.LeftTopCorner.X + 3; | |
int startY = (int)bounds.LeftTopCorner.Y + 3; | |
var leftTopCell = this.GetCell(new Point(startX, startY)); | |
int endX = (int)(bounds.LeftTopCorner.X + bounds.Width) - 3; | |
int endY = (int)(bounds.LeftTopCorner.Y + bounds.Height) - 3; | |
var rightBottomCell = this.GetCell(new Point(endX, endY)); | |
if (leftTopCell != null && rightBottomCell != null) | |
{ | |
int firstRowIndex = this.GridView.ItemContainerGenerator.IndexFromContainer(leftTopCell.ParentRow); | |
int lastRowIndex = this.GridView.ItemContainerGenerator.IndexFromContainer(rightBottomCell.ParentRow); | |
int columnCount = rightBottomCell.Column.DisplayIndex - leftTopCell.Column.DisplayIndex + 1; | |
int rowCount = lastRowIndex - firstRowIndex + 1; | |
CellTable table = new CellTable(rowCount, columnCount); | |
for (int i = firstRowIndex; i <= lastRowIndex; i++) | |
{ | |
var cellContainer = this.GridView.ItemContainerGenerator.ContainerFromIndex(i); | |
if (cellContainer != null && cellContainer is GridViewRow) | |
{ | |
var row = cellContainer as GridViewRow; | |
for (int columnNo = leftTopCell.Column.DisplayIndex; columnNo <= rightBottomCell.Column.DisplayIndex; columnNo++) | |
{ | |
table.SetCell(row.Cells[columnNo], i - firstRowIndex, columnNo - leftTopCell.Column.DisplayIndex); | |
} | |
} | |
} | |
return table; | |
} | |
return null; | |
} | |
#endregion | |
#region Manipulation Classes | |
public class ScanDirection : IEquatable<ScanDirection> | |
{ | |
private ScanOrientation direction; | |
private enum ScanOrientation | |
{ | |
Up, | |
Down, | |
Right, | |
Left, | |
Vertical, | |
Horizontal | |
} | |
private static ScanDirection up = new ScanDirection(ScanOrientation.Up); | |
private static ScanDirection down = new ScanDirection(ScanOrientation.Down); | |
private static ScanDirection right = new ScanDirection(ScanOrientation.Right); | |
private static ScanDirection left = new ScanDirection(ScanOrientation.Left); | |
private static ScanDirection vertical = new ScanDirection(ScanOrientation.Vertical); | |
private static ScanDirection horizontal = new ScanDirection(ScanOrientation.Horizontal); | |
public static ScanDirection Up { get { return ScanDirection.up; } } | |
public static ScanDirection Down { get { return ScanDirection.down; } } | |
public static ScanDirection Right { get { return ScanDirection.right; } } | |
public static ScanDirection Left { get { return ScanDirection.left; } } | |
public static ScanDirection Vertical { get { return ScanDirection.vertical; } } | |
public static ScanDirection Horizontal { get { return ScanDirection.horizontal; } } | |
private ScanDirection(ScanOrientation direction) | |
{ | |
this.direction = direction; | |
} | |
private static bool IsEquals(ScanDirection obj1, ScanDirection obj2) | |
{ | |
if (obj1.direction == obj2.direction) | |
return true; | |
switch (obj1.direction) | |
{ | |
case ScanOrientation.Up: | |
case ScanOrientation.Down: | |
return obj2.direction == ScanOrientation.Vertical; | |
case ScanOrientation.Right: | |
case ScanOrientation.Left: | |
return obj2.direction == ScanOrientation.Horizontal; | |
case ScanOrientation.Vertical: | |
return obj2.direction == ScanOrientation.Up || obj2.direction == ScanOrientation.Down; | |
case ScanOrientation.Horizontal: | |
return obj2.direction == ScanOrientation.Right || obj2.direction == ScanOrientation.Left; | |
} | |
return false; | |
} | |
public bool Equals(ScanDirection other) | |
{ | |
return IsEquals(this, other); | |
} | |
public override bool Equals(object obj) | |
{ | |
if (obj is ScanDirection) | |
return IsEquals(this, obj as ScanDirection); | |
return false; | |
} | |
public override int GetHashCode() | |
{ | |
return base.GetHashCode(); | |
} | |
public static bool operator ==(ScanDirection obj1, ScanDirection obj2) | |
{ | |
return IsEquals(obj1, obj2); | |
} | |
// this is second one '!=' | |
public static bool operator !=(ScanDirection obj1, ScanDirection obj2) | |
{ | |
return !IsEquals(obj1, obj2); | |
} | |
} | |
#endregion | |
#region Table Classes | |
private class Bounds | |
{ | |
public Point LeftTopCorner { get; private set; } | |
public double Width { get; private set; } | |
public double Height { get; private set; } | |
public Bounds(Point point, double width, double height) | |
{ | |
this.LeftTopCorner = point; | |
this.Width = width; | |
this.Height = height; | |
} | |
public Bounds(int x, int y, double width, double height) | |
{ | |
this.LeftTopCorner = new Point(x, y); | |
this.Width = width; | |
this.Height = height; | |
} | |
public static Bounds operator -(Bounds bounds1, Bounds bounds2) | |
{ | |
if (bounds1 == null || bounds2 == null) | |
return null; | |
if (bounds1.Width == bounds2.Width) | |
{ | |
if (bounds1.Height >= bounds2.Height) | |
{ | |
if (bounds1.LeftTopCorner.Y < bounds2.LeftTopCorner.Y) | |
{ | |
return new Bounds((int)bounds1.LeftTopCorner.X, (int)bounds1.LeftTopCorner.Y, bounds1.Width, bounds1.Height - bounds2.Height); | |
} | |
else | |
{ | |
return new Bounds((int)bounds1.LeftTopCorner.X, (int)bounds1.LeftTopCorner.Y + (int)bounds2.Height, bounds1.Width, bounds1.Height - bounds2.Height); | |
} | |
} | |
else | |
{ | |
//throw new Exception("Bounds2 > Bounds1"); | |
return null; | |
} | |
} | |
else if (bounds1.Height == bounds2.Height) | |
{ | |
if (bounds1.Width >= bounds2.Width) | |
{ | |
if (bounds1.LeftTopCorner.X < bounds2.LeftTopCorner.X) | |
{ | |
return new Bounds((int)bounds1.LeftTopCorner.X, (int)bounds1.LeftTopCorner.Y, bounds1.Width - bounds2.Width, bounds1.Height); | |
} | |
else | |
{ | |
return new Bounds((int)bounds1.LeftTopCorner.X + (int)bounds2.Width, (int)bounds1.LeftTopCorner.Y, bounds1.Width - bounds2.Width, bounds1.Height); | |
} | |
} | |
else | |
{ | |
//throw new Exception("Bounds2 > Bounds1"); | |
return null; | |
} | |
} | |
else | |
{ | |
//throw new Exception("Bounds sizes not compatible for extraction!"); | |
return null; | |
} | |
} | |
} | |
private class CellTable | |
{ | |
public int RowCount { get; private set; } | |
public int ColumnCount { get; private set; } | |
private GridViewCellBase[,] Table { get; set; } | |
public CellTable(int rowCount, int columnCount) | |
{ | |
this.RowCount = rowCount; | |
this.ColumnCount = columnCount; | |
this.Table = new GridViewCellBase[columnCount, rowCount]; | |
} | |
public void SetCell(GridViewCellBase cellBase, int rowNo, int columnNo) | |
{ | |
if ((rowNo < 0 || rowNo >= this.RowCount) || (columnNo < 0 || columnNo >= this.ColumnCount)) | |
return; // throw new IndexOutOfRangeException(); | |
this.Table[columnNo, rowNo] = cellBase; | |
} | |
public void SetCellValue(int rowNo, int columnNo, double value) | |
{ | |
if ((rowNo < 0 || rowNo >= this.RowCount) || (columnNo < 0 || columnNo >= this.ColumnCount)) | |
return; // throw new IndexOutOfRangeException(); | |
var cellBase = this.Table[columnNo, rowNo]; | |
if (cellBase is GridViewCell) | |
{ | |
var cell = cellBase as GridViewCell; | |
cell.ParentRow.Item.GetType().GetProperty(cell.DataColumn.DataMemberBinding.Path.Path).SetValue(cell.ParentRow.Item, value, null); | |
//cell.Value = value; | |
//cell.IsSelected = true; | |
} | |
} | |
public GridViewCellBase GetCell(int rowNo, int columnNo) | |
{ | |
if ((rowNo < 0 || rowNo >= this.RowCount) || (columnNo < 0 || columnNo >= this.ColumnCount)) | |
return null; // throw new IndexOutOfRangeException(); | |
return this.Table[columnNo, rowNo]; | |
} | |
public double? GetCellValue(int i, int j, string cultureTag) | |
{ | |
GridViewCellBase cellBase = this.GetCell(i, j); | |
if (cellBase is GridViewCell) | |
{ | |
var cell = cellBase as GridViewCell; | |
if (ReflectionHelper.IsNumericType(cell.Value)) | |
{ | |
double cellValue = Convert.ToDouble(cell.Value); | |
return cellValue; | |
} | |
else | |
{ | |
double cellValue = 0.0d; | |
bool isParsed = DoubleParsingHelper.TryParse(cell.Value.ToString(), cultureTag, out cellValue); | |
if (isParsed) | |
return cellValue; | |
else | |
return null; | |
} | |
} | |
return null; | |
} | |
public Point GetCellLocation(int i, int j, RadGridView gridView) | |
{ | |
var firstCellOfSource = this.GetCell(i, j); | |
int rowIndex = gridView.ItemContainerGenerator.IndexFromContainer(firstCellOfSource.ParentRow); | |
int columnIndex = firstCellOfSource.Column.DisplayIndex; | |
return new Point(rowIndex, columnIndex); | |
} | |
} | |
#endregion | |
#region Pattern Classes | |
private class PatternGroup | |
{ | |
private IAutoFillPattern[] patterns; | |
private CellTable table; | |
public IAutoFillPattern[] Patterns | |
{ | |
get | |
{ | |
return patterns; | |
} | |
private set | |
{ | |
this.patterns = value; | |
} | |
} | |
public CellTable Table | |
{ | |
get | |
{ | |
return table; | |
} | |
private set | |
{ | |
this.table = value; | |
} | |
} | |
public PatternGroup(IAutoFillPattern[] patterns, CellTable table) | |
{ | |
this.Patterns = patterns; | |
this.Table = table; | |
} | |
} | |
private interface IAutoFillPattern | |
{ | |
double[] GenerateSerie(double[] sourceSerie, int serieLength); | |
double[] GenerateInverseSerie(double[] sourceSerie, int serieLength); | |
} | |
private class IncrementalPattern : IAutoFillPattern | |
{ | |
public double Increase { get; private set; } | |
public IncrementalPattern(double increase) | |
{ | |
this.Increase = increase; | |
} | |
public double[] GenerateSerie(double[] sourceSerie, int serieLength) | |
{ | |
double[] serie = new double[serieLength]; | |
double lastValue = sourceSerie.Last(); | |
for (int i = 0; i < serieLength; i++) | |
{ | |
serie[i] = lastValue + this.Increase * (i + 1); | |
} | |
return serie; | |
} | |
public double[] GenerateInverseSerie(double[] sourceSerie, int serieLength) | |
{ | |
double[] serie = new double[serieLength]; | |
double firstValue = sourceSerie.First(); | |
for (int i = 0; i < serieLength; i++) | |
{ | |
serie[i] = firstValue - this.Increase * (i + 1); | |
} | |
return serie; | |
} | |
} | |
private class IrregularPattern : IAutoFillPattern | |
{ | |
public double[] GenerateSerie(double[] sourceSerie, int serieLength) | |
{ | |
double[] serie = new double[serieLength]; | |
for (int i = 0; i < serieLength; i++) | |
{ | |
serie[i] = sourceSerie[i % sourceSerie.Length]; | |
} | |
return serie; | |
} | |
public double[] GenerateInverseSerie(double[] sourceSerie, int serieLength) | |
{ | |
var inversedSourceSerie = sourceSerie.Reverse(); | |
return this.GenerateSerie(inversedSourceSerie.ToArray(), serieLength); | |
} | |
} | |
#endregion | |
#region RaisePropertyChanged | |
/// <summary> | |
/// Helper to set dependency property value. | |
/// </summary> | |
/// <typeparam name="T">Property type</typeparam> | |
/// <param name="target">Target Dependency property</param> | |
/// <param name="value">Value to set</param> | |
/// <param name="changedProperties">argument list on changed property names we going notify about notify</param> | |
/// <returns></returns> | |
protected virtual bool SetValue<T>(ref T target, T value, params string[] changedProperties) | |
{ | |
if (Object.Equals(target, value)) | |
{ | |
return false; // no changes, same value | |
} | |
target = value; | |
foreach (string property in changedProperties) | |
{ | |
RaisePropertyChanged(property); | |
} | |
return true; | |
} | |
[field: NonSerialized] | |
public event PropertyChangedEventHandler PropertyChanged; | |
protected void RaisePropertyChanged(string propertyName) | |
{ | |
if (this.PropertyChanged != null) | |
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment