-1

I can't seem to find this with Google. In WPF using MVVM, I have an InkCanvas for the view. Under this InkCanvas there are several more canvases providing different textual information.

Binding the InkCanvas with a PreviewMouseDown to the view model provides the viewmodel with the MouseButtonEventArgs from which I believe I can get the mouse position (relative to what?)

But, what is the best way to get the text elements from the lower canvases when the viewmodel does not have a reference to the view? How to do hit testing in the viewmodel???

ViewModel:

private RelayCommand inkCanvas_PreviewMouseDown;
    public RelayCommand InkCanvas_PreviewMouseDown
    {
        get
        {

            if (inkCanvas_PreviewMouseDown == null)
            {                   
              inkCanvas_PreviewMouseDown = new RelayCommand( (p) => { this.method(p); 
                });
            }
            return inkCanvas_PreviewMouseDown;
        }
    }

    private void method(Object e)
    {
        MouseButtonEventArgs args = e as MouseButtonEventArgs;
        Point pt = args.GetPosition(null);

      ??? How to find the elements  below the point on the other layers?
      HitTestResult hit = VisualTreeHelper.HitTest(args.Source, pt);  <--This is wrong.
    }

XAML

  <ink:CustomInkCanvas x:Name="inkcanvas" Panel.ZIndex="4" 
                        Width="{x:Static h:Constants.widthCanvas}"
                        Height ="{x:Static h:Constants.heightCanvas}"          
                        Background="Transparent" 
                        DefaultDrawingAttributes="{Binding DDA}" 
                        EditingMode="{Binding EditingMode}" 
                        Strokes="{Binding Strokes}"
                        h:MouseBehaviour.PreviewMouseDownCommand="{Binding InkCanvas_PreviewMouseDown}"                                   
                        >
 </ink:CustomInkCanvas>
Alan Wayne
  • 5,122
  • 10
  • 52
  • 95
  • 4
    That's not MVVM. UI concerns live in the UI, not the VM. So do your hit testing in the UI (notably-where it is easiest handled) and present the results to your VM. Remember--MVVM != no codebehind. –  Aug 25 '14 at 13:26

1 Answers1

0

Since I have no takers as yet, I will explain what I ended up doing in the hope of helping somebody else.

As far as I can find, HitTesting requires the visuals from the view. So the intent of the question does not make sense--my newbie mistake. Ultimately, the code for the hittesting can be put in the view model, but at some point the starting visual must also be added to the view model.

The easiest way for me was:

in Code-Behind:

  inkcanvas.PreviewMouseLeftButtonDown += vm.OnPreviewLeftMouseDown;

and in the View Model:

 public void OnPreviewLeftMouseDown (object sender, MouseButtonEventArgs e)
    { 
        // get visual parent to the inkcanvas. this parent contains all the canvases.
         DependencyObject visualparent = VisualTreeHelper.GetParent((DependencyObject)sender);

         GetVisualHeap( e.GetPosition((UIElement)sender), VisualTreeHelper.GetParent((DependencyObject)sender));
    }

where vm is the viewmodel and GetVisualHeap is my method to actually do the hit testing (and is extremely well documented here on SO).

Hope this helps somebody. I would sure be interested in a better solution.

Alan Wayne
  • 5,122
  • 10
  • 52
  • 95
  • 2
    As @will said in the comment to your question, what you are describing aren't things that should concern the VM anyway: they are view concerns, so live in the view code behind. Hit testing visual elements is definitely a view concern. – Mashton Aug 27 '14 at 14:21
  • @Mashton So correct. My answer should probably be deleted as redundant, but the comments did not sink in until after the understanding of what hit testing is all about.. Thanks – Alan Wayne Aug 27 '14 at 22:30
  • You could call the GetParent once and save the result :) – Roman Ambinder Mar 01 '15 at 14:49