private void RectangleSelection_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            itemsPosition.Clear();
            dataGridRows.Clear();
            DependencyObjectHelpers.FindChildren <DataGridRow>(dataGridRows, uiElement);                                     // Find visible/loaded rows
            prevSelectedItems = uiElement.SelectedItems.Cast <object>().ToList();                                            // Save current selected items
            originDragPoint   = new Point(e.GetCurrentPoint(uiElement).Position.X, e.GetCurrentPoint(uiElement).Position.Y); // Initial drag point relative to the topleft corner
            var verticalOffset = (scrollBar?.Value ?? 0) - uiElement.ColumnHeaderHeight;

            originDragPoint.Y += verticalOffset; // Initial drag point relative to the top of the list (considering scrolled offset)
            if (!e.GetCurrentPoint(uiElement).Properties.IsLeftButtonPressed || e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
            {
                // Trigger only on left click, do not trigger with touch
                return;
            }

            var clickedRow = DependencyObjectHelpers.FindParent <DataGridRow>(e.OriginalSource as DependencyObject);

            if (clickedRow != null && uiElement.SelectedItems.Contains(clickedRow.DataContext))
            {
                // If the item under the pointer is selected do not trigger selection rectangle
                return;
            }

            var selectedItems = new GenericItemsCollection <object>(uiElement.SelectedItems);

            selectionStrategy = e.KeyModifiers.HasFlag(VirtualKeyModifiers.Control) ?
                                new InvertPreviousItemSelectionStrategy(selectedItems, prevSelectedItems) :
                                e.KeyModifiers.HasFlag(VirtualKeyModifiers.Shift) ?
                                (ItemSelectionStrategy) new ExtendPreviousItemSelectionStrategy(selectedItems, prevSelectedItems) :
                                new IgnorePreviousItemSelectionStrategy(selectedItems);

            if (clickedRow == null)
            {
                // If user click outside, reset selection
                if (uiElement.CurrentColumn != null)
                {
                    uiElement.CancelEdit();
                }
                DeselectGridCell();
                selectionStrategy.HandleNoItemSelected();
            }

            uiElement.PointerMoved -= RectangleSelection_PointerMoved;
            uiElement.PointerMoved += RectangleSelection_PointerMoved;
            if (selectionChanged != null)
            {
                // Unsunscribe from SelectionChanged event for performance
                uiElement.SelectionChanged -= selectionChanged;
            }
            uiElement.CapturePointer(e.Pointer);
            selectionState = SelectionState.Starting;
        }
        private void RectangleSelection_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            var selectedItems     = new GenericItemsCollection <object>(uiElement.SelectedItems);
            var selectionStrategy = e.KeyModifiers == VirtualKeyModifiers.Control ?
                                    (ItemSelectionStrategy) new ExtendPreviousItemSelectionStrategy(selectedItems, prevSelectedItems) :
                                    new IgnorePreviousItemSelectionStrategy(selectedItems);

            if (selectionState == SelectionState.Starting)
            {
                uiElement.CancelEdit();
                selectionStrategy.StartSelection();
                OnSelectionStarted();
                selectionState = SelectionState.Active;
            }
            var currentPoint = e.GetCurrentPoint(uiElement);

            if (currentPoint.Properties.IsLeftButtonPressed && scrollBar != null)
            {
                var verticalOffset         = scrollBar.Value - uiElement.ColumnHeaderHeight;
                var originDragPointShifted = new Point(originDragPoint.X, originDragPoint.Y - verticalOffset); // Initial drag point relative to the topleft corner
                base.DrawRectangle(currentPoint, originDragPointShifted);
                // Selected area considering scrolled offset
                var    rect = new System.Drawing.Rectangle((int)Canvas.GetLeft(selectionRectangle), (int)Math.Min(originDragPoint.Y, currentPoint.Position.Y + verticalOffset), (int)selectionRectangle.Width, (int)Math.Abs(originDragPoint.Y - (currentPoint.Position.Y + verticalOffset)));
                var    dataGridRowsPosition = new Dictionary <DataGridRow, System.Drawing.Rectangle>();
                double actualWidth          = -1;
                foreach (var row in dataGridRows)
                {
                    if (row.Visibility != Visibility.Visible)
                    {
                        continue; // Skip invalid/invisible rows
                    }

                    if (actualWidth < 0)
                    {
                        var temp = new List <DataGridCell>();
                        Interaction.FindChildren <DataGridCell>(temp, row); // Find cells inside row
                        actualWidth = temp.Sum(x => x.ActualWidth);         // row.ActualWidth reports incorrect width
                    }

                    var gt             = row.TransformToVisual(uiElement);
                    var itemStartPoint = gt.TransformPoint(new Point(0, verticalOffset)); // Get item position relative to the top of the list (considering scrolled offset)
                    var itemRect       = new System.Drawing.Rectangle((int)itemStartPoint.X, (int)itemStartPoint.Y, (int)actualWidth, (int)row.ActualHeight);
                    itemsPosition[row.DataContext] = itemRect;                            // Update item position
                    dataGridRowsPosition[row]      = itemRect;                            // Update ui row position
                }

                foreach (var item in itemsPosition.ToList())
                {
                    try
                    {
                        if (rect.IntersectsWith(item.Value))
                        {
                            selectionStrategy.HandleIntersectionWithItem(item.Key);
                        }
                        else
                        {
                            selectionStrategy.HandleNoIntersectionWithItem(item.Key);
                        }
                    }
                    catch (ArgumentException)
                    {
                        // Item is not present in the ItemsSource
                        itemsPosition.Remove(item);
                    }
                }
                if (currentPoint.Position.Y > uiElement.ActualHeight - 20)
                {
                    // Scroll down the list if pointer is at the bottom
                    // Check if there is a loaded row outside the viewport
                    var item = dataGridRowsPosition.OrderBy(x => x.Value.Y).SkipWhile(x => x.Value.Y <= verticalOffset + uiElement.ActualHeight).Select(x => x.Key).FirstOrDefault();
                    if (item == null)
                    {
                        if (dataGridRowsPosition.Any())
                        {
                            // Last loaded item is fully visible, ge thet next one from bound item source
                            var index  = dataGridRowsPosition.OrderBy(x => x.Value.Y).Last().Key.GetIndex();
                            var source = (System.Collections.IList)uiElement.ItemsSource;
                            uiElement.ScrollIntoView(source[Math.Min(Math.Max(index + 1, 0), source.Count - 1)], null);
                        }
                    }
                    else
                    {
                        uiElement.ScrollIntoView(item.DataContext, null);
                    }
                }
                else if (currentPoint.Position.Y < 20)
                {
                    // Scroll up the list if pointer is at the top
                    // Check if there is a loaded row outside the viewport
                    var item = dataGridRowsPosition.OrderBy(x => x.Value.Y).TakeWhile(x => x.Value.Y + x.Value.Height <= scrollBar.Value).Select(x => x.Key).LastOrDefault();
                    if (item == null)
                    {
                        if (dataGridRowsPosition.Any())
                        {
                            // First loaded item is fully visible, ge thet previous one from bound item source
                            var index  = dataGridRowsPosition.OrderBy(x => x.Value.Y).First().Key.GetIndex();
                            var source = (System.Collections.IList)uiElement.ItemsSource;
                            uiElement.ScrollIntoView(source[Math.Min(Math.Max(index - 1, 0), source.Count - 1)], null);
                        }
                    }
                    else
                    {
                        uiElement.ScrollIntoView(item.DataContext, null);
                    }
                }
            }
        }