Dani
Dani

Reputation: 15069

binding different types of objects to canvas

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

Answers (1)

icebat
icebat

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

Related Questions