Sunday, April 26, 2009

ListView.GetItemAt() in WPF Application

At present (.NET 3.5 SP 1) a GetItemAt() method doesn't exist for the ListView class that is part of WPF. At least I couldn't find it. I always found it handy in Forms based development for instance when handling mouse events. Please note that the WPF class ListView is in System.Windows.Controls while the forms based class of the same name is in System.Windows.Forms. Don't confuse the two! In this post I'm referring to the WPF class ListView. I wanted a similar behavior to the method of the same name in the forms based library. As a result I want the client code to look like this:
      private void _replacementsListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
         var mousePosition = e.GetPosition(_replacementsListView);
         var item = _replacementsListView.GetItemAt(mousePosition);
         if (item != null
            && item.Content != null) {
            EditTokenReplacement((TokenReplacement) item.Content);
         }
      }
Since the WPF class ListView doesn't come with a built-in method I decided to implement an extension method as follows:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Foo.Gui {
   internal static class Extensions {
      public static ListViewItem GetItemAt(this ListView listView, Point clientRelativePosition) {
         var hitTestResult = VisualTreeHelper.HitTest(listView, clientRelativePosition);
         var selectedItem = hitTestResult.VisualHit;
         while (selectedItem != null) {
            if (selectedItem is ListViewItem) {
               break;
            }
            selectedItem = VisualTreeHelper.GetParent(selectedItem);
         }
         return selectedItem != null ? ((ListViewItem) selectedItem) : null;
      }
   }
}
Please note that the position is passed into the method as an object of class Point. This means that the coordinates need to be relative to the list view object. In an event handler for a mouse button event, e.g. a double click, these can be calculated by using a method on MouseButtonEventArgs object that is passed into the mouse event handler. It's already shown in the first code snippet above but just to be on the safe side here are the relevant lines again:
      private void _replacementsListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
         var mousePosition = e.GetPosition(_replacementsListView); // gets position relative to ListView
         var item = _replacementsListView.GetItemAt(mousePosition);
         ...
      }

0 comments:

Post a Comment

All comments, questions and other feedback is much appreciated. Thank you!