views:

540

answers:

1

In my WPF application I have a Canvas in which I do some drawing. Earlier I handled the drawing in the code behind, but now I've factored everything out to a ViewModel. This gives me some challenges..

I have a few InkPresenter objects holding Strokes. Earier I added them as children to the Canvas in the code behind - like this:

// Build an InkPresenter: 
var someInkPresenter = BuildInkPresenter(..); 
//_myCanvas is the <Canvas> I want to display it in: 
_myCanvas.Children.Add(someInkPresenter); 

Now - not building the InkPresenter in the code-behind of the XAML that holds _myCanvas I need to do this differently. What I'd like to do is to create an InkPresenter and add it to a collection:

public ObservableCollection<InkPresenter> Drawings;

My problem now is how to bind the Canvas to this ObservableCollection - and have the InkPresenters displayed when added to the collection. Can I achieve this using Data Bindings somehow?

+2  A: 

Hi Stian,

I think you can do this with ItemsControl + ItemsPanelTemplate. Like this:

  <ItemsControl ItemsSource="{Binding YourCollection}">
    <ItemsControl.ItemsPanel>
     <ItemsPanelTemplate>
      <Canvas />
     </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
   </ItemsControl>

To read more about this approach refer to Dr.WPF: ItemsControl: A to Z (P is for Panel)

Anvaka
Thx! Sounds reasonable. Will have a look at it!
stiank81
This is normally the approach you'd take but in this case you're probably going to run into issues because the InkPresenters are not going to be direct children of the Canvas like they are when you add them in code. Instead the Visual Tree is going to have an additional ContentPresenter injected around each InkPresenter item. To get this method to work you should look at pulling out the actual data (Strokes) from each InkPresenter and storing a collection of those in your VM. You can then create a custom ItemsControl that overrides GetContainerForItemOverride to return an InkPresenter.
John Bowen
Cant agree with you John... It's an ItemsControl. It uses UIElement as default container...
Anvaka
Anvaka - No. It doesn't. If you look at ItemsControl in Reflector or Snoop an instance at runtime you can see it uses a ContentPresenter (which does derive from UIElement) as the default container. Even if it was using a base UIElement it's still modifying the Canvas visual tree from Stian's original.
John Bowen
John, I've tried that before posting disagreement :). InkPresenter is direct child of a Canvas. If a UIElement is added to the Items collection of an explicit ItemsControl instance (as opposed to an instance of a derived class like ListBox), it will become a direct child of the items panel. If a non-UIElement is added, it will be wrapped within a ContentPresenter. Check the table at the end of this post http://drwpf.com/blog/2008/03/25/itemscontrol-i-is-for-item-container.
Anvaka