2

I'm using the code below for Hit Testing in the visual layer. I want to get hits when I click on the lines that are drawn in Drawing visual. But since lines are narrow, I'm not getting good results.

One solution that comes to my mind is increasing the area mouse covers when clicked. This way I'll make sure that the mouse hits the lines even if I click a little bit further from the line.

How can I achieve this? Or what else do you suggest to improve this situation?

var x = MousePos.RightDown.X;
var y = MousePos.RightDown.Y;

var drawing = MyCanvas.GetRebarsVisual();

var pt = new Point(x,y);

var result = VisualTreeHelper.HitTest(drawing, pt);

if (result != null)
{
    MessageBox.Show("You clicked on the line!");
}
Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
Vahid
  • 5,144
  • 13
  • 70
  • 146
  • 2
    Using `VisualTreeHelper.HitTest` where you can specify a `HitTestParameters`, use a rectangle geometry centered on `pt` but bigger than one point passed with `GeometryHitTestParameters`: `VisualTreeHelper.HitTest(drawing, null, null, new GeometryHitTestParameters(...))`. – Adriano Repetti Sep 09 '14 at 21:41
  • @AdrianoRepetti Thank you, I was just exploring that option. Can you help me with an article or example? – Vahid Sep 09 '14 at 21:43
  • 1
    Added in comment, replace `...` with `new RectangleGeometry(new Rect(x - 2, y - 2, 4, 4))`. Well...just for example. Rectangle is simplest one but, especially if you're planning to use your application with a touch screen, a circle will better represent a bigger hit test area. – Adriano Repetti Sep 09 '14 at 21:45
  • @AdrianoRepetti Thank you so much Adriano, I'm getting there, but my problem is where I should assign the VisualTreeHelper..., as you can see in my example I'm assigning it to result. I'm completely new to this. – Vahid Sep 09 '14 at 21:50

1 Answers1

3

Using VisualTreeHelper.HitTest() overloaded function where you can specify a HitTestParameters: use a rectangle geometry centered on pt (but bigger than one point) passed with GeometryHitTestParameters:

var hitRect = new Rect(x - 2, y - 2, 4, 4);
VisualTreeHelper.HitTest(drawing, null, null,
    new GeometryHitTestParameters(new RectangleGeometry(hitRect)));

Note that we're using a rectangular geometry in this example but a better approximation (especially for touch screens) is a circle (EllipseGeometry).

Now you know what to call but you need a result, that overload has not a return value instead it uses a callback function where you can accumulate multiple hits (to pick one according to more complex rules). In our example we don't need it so we just stop at first hit:

bool result = false;
var hitRect = new Rect(x - 2, y - 2, 4, 4);
VisualTreeHelper.HitTest(drawing, null,
    htr => { result = true; return  HitTestResultBehavior.Stop; },
    new GeometryHitTestParameters(new RectangleGeometry(hitRect)));

Note that you may even directly execute code:

    htr => {
        MessageBox.Show("You clicked on the line!");
        return  HitTestResultBehavior.Stop;
    },

If you use it often you may write a more generic method for that (for example with an optional parameter for rectangle size).

If you just don't want to know if there is a hit or not (but you also want to know which object) then you can use second callback function (HitTestResultCallback), its parameter (the one called htr in my previous example) is a class derived from HitTestResult and even in base class there is a property named VisualHit which is the visual object (as a generic DependencyObject then you may need casting) you're looking for.

Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
  • The code is working great, thank you so much. Only the `found = true` needs to be changed to `result = true` I guess. I really appreciate your help, I searched a lot in the MSDN but I couldn't find a full working example. Can you guide me to some examples? – Vahid Sep 09 '14 at 22:03
  • 1
    You're right, fixed! IMO MSDN examples about that methods are pretty good (even if short). To start take a look to [this](http://msdn.microsoft.com/library/system.windows.media.hittestresultcallback(v=vs.110).aspx) and [this](http://msdn.microsoft.com/library/ms608753(v=vs.110).aspx). – Adriano Repetti Sep 09 '14 at 22:06
  • Thanks Adriano, these articles helped me understand the answer better. – Vahid Sep 09 '14 at 22:10
  • You have already helped me a lot. Just one more question, if needs be, please tell me I will post it as a separate question. Before leaning to HitTest I was doing it my own way. I mean I was searching in the definitions of the lines manually and searching for the specific line that my pointer was on. This way I could for example change its color and stuff like that. Now that I'm using HitTesting how can I get the exact line that I'm pointing at. How can I get a reference or something like that so that I can make changes to it. – Vahid Sep 09 '14 at 22:18
  • 1
    Yes, you can do it in callback function. Parameter I called `htr` in lambda (OK, I have not too much fantasy) is [HitTestResult](http://msdn.microsoft.com/en-us/library/system.windows.media.hittestresult(v=vs.110).aspx) (one of its derived classes). Even in base abstract class there is a property [VisualHit](http://msdn.microsoft.com/en-us/library/system.windows.media.hittestresult.visualhit(v=vs.110).aspx) that is the matched `DependencyObject`. – Adriano Repetti Sep 09 '14 at 22:22
  • Oh I guess I will have a problem here. So to get the exact clicked line, I will need to draw each line on separate Drawing Visuals. am I right? In my program I have drawn all the lines in one single drawing visual, so that VisualHit returns that single visual with all the lines on it? – Vahid Sep 09 '14 at 22:28
  • **AFAIK** yes, when you have your visual then you have to perform your own hit testing on that. You may post this as another question, maybe someone has a good/fast/easy solution for that (no need to loop through lines manually). – Adriano Repetti Sep 09 '14 at 22:30
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/60926/discussion-between-vahid-and-adriano-repetti). – Vahid Sep 09 '14 at 22:50
  • Thanks, I asked it here. http://stackoverflow.com/questions/25754861/get-the-hittesting-result-when-lots-of-drawings-are-in-one-single-visual – Vahid Sep 09 '14 at 23:04