// https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/walkthrough-enabling-drag-and-drop-on-a-user-control
        private void canvas_Drop(object sender, DragEventArgs e)
        {
            // If an element in the panel has already handled in the drop,
            // the panel should not also handle it.
            if (!e.Handled && e.Data.GetDataPresent(MyRockShape.RockViewModelDataFormatName))
            {
                bool isAllowedDragMove = false;

                // Canvas inherits Panel
                Panel         _canvas      = sender as Panel;
                RockViewModel selectedRock = rocksOnWallViewModel.SelectedRock;

                if (_canvas != null && selectedRock != null)
                {
                    Point mousePt = e.GetPosition(cameraIMG);

                    // check rock overlaps
                    if (rocksOnWallViewModel.IsOverlapWithRocksOnWallOtherThanSelectedRock(
                            mousePt, selectedRock.SizeOnCanvas)
                        == false)
                    {
                        CameraSpacePoint csp = jcWall.GetCamSpacePointFromMousePoint(mousePt, _mode);
                        if (!csp.Equals(default(CameraSpacePoint)))
                        {
                            // note:
                            // use RocksOnWallViewModel.MoveSelectedRock()
                            // instead of RockViewModel.MoveBoulder()
                            // because RocksOnWallViewModel.MoveSelectedRock()
                            // will set the selected rock indicator as well
                            isAllowedDragMove = rocksOnWallViewModel.MoveSelectedRock(csp);

                            if (!isAllowedDragMove)
                            {
                                UiHelper.NotifyUser(DepthInfoMissingWarningMsg);
                            }
                        }
                        else
                        {
                            UiHelper.NotifyUser(DepthInfoMissingWarningMsg);
                        }
                    }
                    else
                    {
                        UiHelper.NotifyUser(RockOverlapsWarningMsg);
                    }
                }

                if (isAllowedDragMove)
                {
                    e.Effects = supportedDragDropEffects;
                }
                else
                {
                    e.Effects = DragDropEffects.None;
                }
            }
        }
        private void canvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (isSnapShotTaken)
            {
                //Debug.WriteLine("canvas_MouseDown");

                Point mouseClickPt = e.GetPosition(cameraIMG);

                RockViewModel rockCorrespondsToCanvasPt =
                    rocksOnWallViewModel.GetRockInListByCanvasPoint(mouseClickPt);

                if (rockCorrespondsToCanvasPt == null)  // new rock
                {
                    Size newBoulderSizeOnCanvas = GetBoulderSizeOnCanvasFromSliders();

                    // check rock overlaps
                    if (rocksOnWallViewModel.IsOverlapWithRocksOnWall(
                            mouseClickPt, newBoulderSizeOnCanvas)
                        == false)
                    {
                        CameraSpacePoint csp = jcWall.GetCamSpacePointFromMousePoint(mouseClickPt, _mode);
                        if (!csp.Equals(default(CameraSpacePoint)))
                        {
                            rocksOnWallViewModel.AddRock(csp, newBoulderSizeOnCanvas);
                        }
                        else
                        {
                            UiHelper.NotifyUser(DepthInfoMissingWarningMsg);
                        }
                    }
                    else
                    {
                        UiHelper.NotifyUser(RockOverlapsWarningMsg);
                    }
                }
                else  // rock already in list
                {
                    rocksOnWallViewModel.SelectedRock = rockCorrespondsToCanvasPt;
                    boulderWidthSlider.Value          = rockCorrespondsToCanvasPt.RockShapeContainer.GetWidth();
                    boulderHeightSlider.Value         = rockCorrespondsToCanvasPt.RockShapeContainer.GetHeight();

                    // if rock already in list, enable drag drop!
                    rockCorrespondsToCanvasPt.RockShapeContainer.DoDragDrop();
                }
            }
            else
            {
                UiHelper.NotifyUser("Please take snap shot first.");
            }
        }
        private void canvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (isSnapShotTaken)
            {
                Point mouseClickPt = e.GetPosition(cameraIMG);
                //ColorSpacePoint _boulderCSP = new ColorSpacePoint { X = (float)mouseClickPt.X, Y = (float)mouseClickPt.Y };

                RockViewModel rockCorrespondsToCanvasPt =
                    rocksOnWallViewModel.GetRockInListByCanvasPoint(mouseClickPt);

                if (rockCorrespondsToCanvasPt == null)  // new rock
                {
                    Size newBoulderSizeOnCanvas = GetNewBoulderSizeOnCanvasFromSliders();

                    // check rock overlaps
                    if (rocksOnWallViewModel.IsOverlapWithRocksOnWall(
                            mouseClickPt, newBoulderSizeOnCanvas)
                        == false)
                    {
                        CameraSpacePoint csp = jcWall.GetCamSpacePointFromMousePoint(mouseClickPt, _mode);
                        if (!csp.Equals(default(CameraSpacePoint)))
                        {
                            rocksOnWallViewModel.AddRock(csp, newBoulderSizeOnCanvas);
                        }
                        else
                        {
                            UiHelper.NotifyUser("No depth info is captured for this point!");
                        }
                    }
                    else
                    {
                        UiHelper.NotifyUser(RockOverlapsWarningMsg);
                    }
                }
                else  // rock already in list
                {
                    rocksOnWallViewModel.SelectedRock = rockCorrespondsToCanvasPt;
                    boulderWidthSlider.Value          = rockCorrespondsToCanvasPt.BoulderShape.Width;
                    boulderHeightSlider.Value         = rockCorrespondsToCanvasPt.BoulderShape.Height;
                }
            }
            else
            {
                UiHelper.NotifyUser("Please take snap shot first.");
            }
        }
        // https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/walkthrough-enabling-drag-and-drop-on-a-user-control
        private void canvas_DragOver(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(MyRockShape.RockViewModelDataFormatName))
            {
                //Debug.WriteLine("canvas_DragOver");

                bool isAllowedDragMove = false;

                // Canvas inherits Panel
                Panel         _canvas      = sender as Panel;
                RockViewModel selectedRock = rocksOnWallViewModel.SelectedRock;

                if (_canvas != null && selectedRock != null)
                {
                    Point mousePt = e.GetPosition(cameraIMG);

                    // check rock overlaps
                    if (rocksOnWallViewModel.IsOverlapWithRocksOnWallOtherThanSelectedRock(
                            mousePt, selectedRock.SizeOnCanvas)
                        == false)
                    {
                        CameraSpacePoint csp = jcWall.GetCamSpacePointFromMousePoint(mousePt, _mode);
                        if (!csp.Equals(default(CameraSpacePoint)))
                        {
                            // note:
                            // use RocksOnWallViewModel.MoveSelectedRock()
                            // instead of RockViewModel.MoveBoulder()
                            // because RocksOnWallViewModel.MoveSelectedRock()
                            // will set the selected rock indicator as well
                            isAllowedDragMove = rocksOnWallViewModel.MoveSelectedRock(csp);
                        }
                    }
                }

                // These Effects values are used in the drag source's
                // GiveFeedback event handler to determine which cursor to display.
                if (isAllowedDragMove)
                {
                    e.Effects = supportedDragDropEffects;
                }
                else
                {
                    e.Effects = DragDropEffects.None;
                }
            }
        }
 // Base on what user click, generate the corresonding dialog type
 private async void CreateDialog(object parameter)
 {
     var str = parameter as string;
     this.ChangeView();
     switch (str)
     {
         case "Rock":
             // initialize a basic dialog and set the title
             custom = new CustomDialog() { Title = str };
             // initialize rock view model and pass the close capability, collection, and new object.
             var RockViewModel = new RockViewModel(instance => dialogCoordinator.HideMetroDialogAsync(this, custom),
                 debrisFlowCollection, new Rock());
             //set the dialog's content to the rock view page
             custom.Content = new DebrisFlowRecordDialog { DataContext = RockViewModel };
             // wait for the dialog to finish
             await dialogCoordinator.ShowMetroDialogAsync(this, custom);
             break;
         case "Slope":
             break;
         case "Plantation":
             break;
         case "Protected Object":
             break;
         case "Basic Info":
             break;
         case "Catchment":
             break;
     }
 }