Monday, 20 December 2010

How to place items on a Canvas using ItemsControl and PrepareContainerForItemOverride method

If you have to place some items on a canvas and the whole process has to be performed automatically using binding and ItemsControl, so you have to be aware that ItemsControl wraps each item with ContentPresenter before adding it to the canvas. It means that defining bindings between Canvas.Left/Top attached properties and your bound objects will not reflect their position on the canvas because your binding should be defined one level higher in ItemsControl visual tree.There are at least two ways how you can solve this problem:
  • harder one - to find a parent element (using VisualTreeHepler because there is no direct access to the ContentPresenter) of your visual data representation and bind it to the coordinates. The main disadvantage of this solution is that you have to modify your control because of the need to find a parent container. It makes an additional dependency and narrows the way how your control can be used in the future.
  • simpler one - to create a class which derives from ItemsControl class and override PrepareContainerForItemOverride method where you  can create necessary bindings to pass information about coordinates. 

   1:          protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
   2:          {
   3:              FrameworkElement contentitem = element as FrameworkElement;
   4:              Binding leftBinding = new Binding("X");
   5:              Binding topBinding = new Binding("Y");
   6:              contentitem.SetBinding(Canvas.LeftProperty, leftBinding);
   7:              contentitem.SetBinding(Canvas.TopProperty, topBinding);
   8:              base.PrepareContainerForItemOverride(element, item);
   9:          }

If you look at input parameters of PrepareContainerForItemOverride method you will find a DependencyObject  parameter which represents a wrapper (ContentPresenter) and an object parameter which represents bound data, so you have direct access to the data and you can bind whichever parameter you want (in this case coordinates).
If you would like to see this solution in action you can download it from source code section in this article: Convex Hull Algorith.

No comments:

Post a Comment