Reputation: 15069
I am trying to "throw" several objects on a canvas. I have 5 types of objects with several properties (like text, position, bitmap, and more)
Each type should be rendered differently (one type will be rendered as textblock, one as bitmapImage, ect.)
I have 5 observableCollections that holds all the objects of same type.
I can bind one of them (the one that represents text for example) to the canvas and using a data template with a textblock to bind each property to the right parameter (like visibility and localtion).
now my 2nd type should be bind to a bitmap.
How can I do that ? How can I bind 5 different types to the canvas and have each type converted to the right element ?
One possible way is to aggregate all collections to a single one... but then it tries to convert everything to the first type...
Upvotes: 1
Views: 951
Reputation: 4774
There`s a great answer to somehow related question that we can extend to make it work with your problem.
Say we have two types that can be dropped to Canvas:
public class TextClass
{
public string Text { get; set; }
}
public class RectangleClass
{
public Brush FillBrush { get; set; }
}
To facilitate the use of collection to bind to we can use the code from answer I mentioned but change ItemTemplate
for our custom DataTemplateSelector
:
<ItemsControl Name="icMain">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Left}" />
<Setter Property="Canvas.Top" Value="{Binding Top}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplateSelector>
<TestWPF:CustomTemplateSelector>
<TestWPF:CustomTemplateSelector.TextTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" />
</DataTemplate>
</TestWPF:CustomTemplateSelector.TextTemplate>
<TestWPF:CustomTemplateSelector.RectangleTemplate>
<DataTemplate>
<Rectangle Height="25" Width="25" Fill="{Binding FillBrush}" />
</DataTemplate>
</TestWPF:CustomTemplateSelector.RectangleTemplate>
</TestWPF:CustomTemplateSelector>
</ItemsControl.ItemTemplateSelector>
</ItemsControl>
And that`s the template selector I used:
public class CustomTemplateSelector: DataTemplateSelector
{
public DataTemplate TextTemplate { get; set; }
public DataTemplate RectangleTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is TextClass)
return TextTemplate;
else if (item is RectangleClass)
return RectangleTemplate;
else return base.SelectTemplate(item, container);
}
}
Well, all that`s left is to bind our collection. I used simple List
in code behind just for test:
List<object> aggregation = new List<object>()
{
new TextClass() { Text = "Some test text" },
new RectangleClass() { FillBrush = new SolidColorBrush(Colors.Tomato)}
};
icMain.ItemsSource = aggregation;
This code shows some test text and yummy tomato rectangle. These sample objects do not have any positioning logic, but I figured you have that already.
Upvotes: 4