/// <summary>
        ///
        /// </summary>
        /// <param name="eventPointExtractor"></param>
        /// <returns>whether the event is handled</returns>
        private bool HandleDrag(Func <IInputElement, Point> eventPointExtractor)
        {
            AnnotationGridVM agVM = DataContext as AnnotationGridVM;

            if (agVM != null)
            {
                if (agVM.DragCandidateItem != null)
                {
                    Point  localOffset  = agVM.LocalDraggedItemOffset;
                    Point  curLocation  = eventPointExtractor(LowerGrid);
                    double proposedLeft = curLocation.X - localOffset.X;
                    double proposedTop  = curLocation.Y - localOffset.Y;
                    Vector move         = agVM.DragItemInitialLocation - new Point(proposedLeft, proposedTop);
                    if (move.LengthSquared > 600 && agVM.DraggedItem == null)
                    {
                        //move far enough to trigger drag
                        //candidate is promoted to be actually dragged
                        agVM.DraggedItem = agVM.DragCandidateItem;
                        //System.Diagnostics.Trace.WriteLine(string.Format("Elem drag started at {0}:{1} as movement was {2:#.##}", proposedLeft, proposedTop, move.Length));
                    }
                    if (agVM.DraggedItem != null)
                    {
                        //actually moving dragged item on canvas
                        DraggedItemLeft = proposedLeft;
                        DraggedItemTop  = proposedTop;
                    }
                    return(true);
                }
            }
            return(false);
        }
        private bool HandleDragEnd(Func <IInputElement, Point> eventPointExtractor)
        {
            AnnotationGridVM agVM = DataContext as AnnotationGridVM;

            if (agVM != null)
            {
                if (agVM.DraggedItem != null)
                {
                    Point localOffset     = agVM.LocalDraggedItemOffset;
                    Point curLocation     = eventPointExtractor(ColumnsGrid);
                    Point droppedLocation = new Point(
                        curLocation.X - localOffset.X + agVM.DraggedItem.ActualWidth / 2, //X coord is the location of the centre of the dragged element
                        curLocation.Y - localOffset.Y);                                   //Y coord is a top of the dragged element
                    if (isMouseCaptured)
                    {
                        //ReleaseMouseCapture();
                        System.Diagnostics.Trace.WriteLine("Mouse release");
                        isMouseCaptured = false;
                    }

                    int col      = -1;
                    var htResult = VisualTreeHelper.HitTest(ColumnsGrid, droppedLocation);
                    if (htResult != null)
                    {
                        foreach (UIElement elem in ColumnsGrid.Children)
                        {
                            if (IsInVisualTree(htResult.VisualHit, elem))
                            {
                                col = Grid.GetColumn(elem);
                            }
                        }
                    }


                    ElementDropped?.Invoke(this, new ElemDroppedEventArgs(agVM.DraggedItem, col, droppedLocation.Y));

                    agVM.DraggedItem = null;
                    return(true);
                }
            }
            return(false);
        }
        private static void DataContexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            AnnotationGridVM oldVM = e.NewValue as AnnotationGridVM;
            AnnotationGrid   view  = (AnnotationGrid)d;

            if (oldVM != null)
            {
                oldVM.Columns.CollectionChanged -= view.Columns_CollectionChanged;
                //TODO: handle columns removal
            }

            AnnotationGridVM newVM = e.NewValue as AnnotationGridVM;

            if (newVM != null)
            {
                newVM.Columns.CollectionChanged += view.Columns_CollectionChanged;
                foreach (ColumnVM colVM in newVM.Columns)
                {
                    view.HandleColumnAdded(colVM);
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="eventPointExtractor"></param>
        /// <returns>whether the event is handled</returns>
        private bool HandleDrag(Func <IInputElement, Point> eventPointExtractor)
        {
            AnnotationGridVM agVM = DataContext as AnnotationGridVM;

            if (agVM != null)
            {
                if (agVM.DraggedItem != null)
                {
                    Point localOffset = agVM.LocalDraggedItemOffset;
                    Point curLocation = eventPointExtractor(LowerGrid);
                    DraggedItemLeft = curLocation.X - localOffset.X;
                    DraggedItemTop  = curLocation.Y - localOffset.Y;
                    System.Diagnostics.Trace.WriteLine(string.Format("Elem moved to {0}:{1}", DraggedItemLeft, DraggedItemTop));
                    if (!isMouseCaptured)
                    {
                        //CaptureMouse();
                        System.Diagnostics.Trace.WriteLine("Mouse captured");
                        isMouseCaptured = true;
                    }
                    return(true);
                }
            }
            return(false);
        }