1

I’m tying to generically draw an ObservableCollection of System.Windows.Shapes.Shape on a canvas using an ItemsControl but I am not sure about how to write the XAML to do it properly.

I've seen many posts regarding this topic, but they all seem to be tied to specific shape types. For example, from this example I realize I could define an ItemsContainer and set its template to draw lines, circles, etc.

<ItemsControl ItemsSource="{Binding Lines}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Line X1="{Binding From.X}" Y1="{Binding From.Y}"
                  X2="{Binding To.X}" Y2="{Binding To.Y}"
                  Stroke="DarkGray" StrokeThickness="3"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

But this requires me to expose my shapes as separately typed collections of lines, circles, etc. -- or at least write some sort of filtering properties that do that. I was hoping to just expose just one collection of shapes. (I will be adding new shape types later on and don't want to have to keep adding new collection properties)

  1. Is there a simple, "best" approach I can take to achieve this without exposing separate collection types?
  2. Should I be looking at ItemTemplateSelector? It seems to me that would have the same problem of needing specific shape types.
  3. Some other approach?
Joe
  • 5,394
  • 3
  • 23
  • 54
  • 1
    Why can't you have one collection of a common base class, with implicit datatemplates for the various subclasses? Or just use Paths for everything. – 15ee8f99-57ff-4f92-890c-b56153 Jun 01 '17 at 01:13
  • The paths thing is a good alternative, thanks. But as for one collection of a common base class, that's what I have now. But I don't understand how I can use datatemplates with that. Data templates are based on the target type, right? So if all it gets is a base class reference, how can data template selection work? Perhaps I'm misunderstanding data templates? – Joe Jun 01 '17 at 01:20
  • 1
    The datatemplate is selected based on the actual runtime type of the object. It's all reflection. That's what's so powerful about WPF. Everything in WPF takes Object, non-generic IList, etc., and then figures out what it really is. – 15ee8f99-57ff-4f92-890c-b56153 Jun 01 '17 at 01:23
  • Ah. Of course. I think I've spent way too many years in C++. I keep thinking that all types are hard-bound at build-time. Thank you. – Joe Jun 01 '17 at 01:29
  • C++ has RTTI doesn't it? – 15ee8f99-57ff-4f92-890c-b56153 Jun 01 '17 at 01:37
  • It does. But its use usually indicates poor design. And its generics are still hard-bound at compile time. The ability to dynamic cast is not the same thing as reflection – Joe Jun 01 '17 at 01:59
  • 1
    True. And the same design principles apply in C#. I don't think generics are all that different though, at least in the respect you mention, if I understand you. – 15ee8f99-57ff-4f92-890c-b56153 Jun 01 '17 at 02:35
  • The difference (which I clearly missed by posting this question) is that generics are resolved at run time, not build time. Different language, different goals. Both awesome – Joe Jun 01 '17 at 04:31
  • 2
    You shouldn't have UIElements in your source collection. Better use a Geometry to define a shape, and a Path element in the ItemTemplate, as e.g. shown here: https://stackoverflow.com/a/30766339/1136211 – Clemens Jun 01 '17 at 06:27
  • Generics are resolved at compile time in C#. – 15ee8f99-57ff-4f92-890c-b56153 Jun 01 '17 at 11:10
  • They are? Then how does this MSDN article (comparing c++ templates with generics) not contradict that? https://blogs.msdn.microsoft.com/branbray/2003/11/19/templates-and-generics/ – Joe Jun 01 '17 at 11:29
  • @Clemens I don't think anbody's suggesting putting ui elements anywhere but in the template. I sure hope not. – 15ee8f99-57ff-4f92-890c-b56153 Jun 01 '17 at 11:52
  • You have both been very helpful, thank you. I'll admit I still don't quite "grok" C# generics -- I keep trying to force them into my C++ mindset. But I'll get it eventually – Joe Jun 01 '17 at 13:42
  • If you want your models to be all the same type and be able to, at runtime, determine the template to use based on a property or attribute of an instance, you'll have to create a custom DataTemplateSelector. –  Jun 01 '17 at 15:30
  • 1
    @Ed I wasn't referring to any suggestion made in a comment, just to "ObservableCollection of System.Windows.Shapes.Shape" from the question. – Clemens Jun 01 '17 at 18:26
  • @Clemens Whoops, I totally missed that! Derp. Thanks. – 15ee8f99-57ff-4f92-890c-b56153 Jun 01 '17 at 18:27

0 Answers0