Alex
Alex

Reputation: 389

How to determine the specifix type of a item in a ObservableCollection<object> and bind to a property of the item in wpf?

I've got a ObservableCollection<IContainers> Containers which defines the property ObservableCollection<object> Content.

public interface IContainers
{
   public double Height {get; set;}
   public double Width {get; set;}
   public ObservableCollection<object> Content {get; set;}
}

public class SetupStep
{
   public ObservableCollection<IContainer> Containers {get; set;}
}

The types of items in the Content Property can vary. These types define their own properties to which I want to bind.

This is my .xaml code:

<c:ScatterView
   ItemsSource="{Binding Containers}">
   <c:ScatterView.ItemTemplate>
      <DataTemplate>
         <ListBox
            ItemsSource="{Binding Content}">
            <!--A way to determine my types in Contents?!?!-->
            <ListBox.Resources>
               <DataTemplate x:Key="{x:Type myObjects:Picture}">
                  <Image Source="{Binding Picture.FullFileName}"/>
               </DataTemplate>
               <DataTemplate x:Key="{x:Type myObjects:Parameter}">
                  <myControl:ParameterControl Id="{Binding Parameter.Id}"/>
               </DataTemplate>
            </ListBox.Resources>
            <!--A way to determine my types in Contents?!?!-->
         </ListBox>
      </DataTemplate>
   </c:ScatterView.ItemTemplate>
</c:ScatterView>

I found no working solution to bind to the properties of myObjects like Picture or Parameter.

I hope for some ideas :) Thanks, Alex

Upvotes: 0

Views: 53

Answers (2)

Clemens
Clemens

Reputation: 128060

Data Templates and Binding source properties are resolved by reflection. So if the Content collection contains a Picture, a DataTemplate for Picture can be applied automatically.

The only thing you need to do is to set the DataType property of the DataTemplate:

<ListBox.Resources>
    <DataTemplate DataType="{x:Type myObjects:Picture}">
        <Image Source="{Binding Picture.FullFileName}"/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type myObjects:Parameter}">
        <myControl:ParameterControl Id="{Binding Parameter.Id}"/>
    </DataTemplate>
</ListBox.Resources>

Everything else should work out of the box.

While you could also use a DataTemplateSelector, the above approach is far simpler. Using a DataTemplateSelector isn't necessary unless you want to have different DataTemplates for different items of the same type, e.g. depending on the value of some property of the item class.

Upvotes: 3

andreask
andreask

Reputation: 4298

You might want to take a look at the DataTemplateSelector class. This allows you to switch DataTemplate depending on different criteria - in your case, this criteria could be the list item type:

public class CustomDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is MainWindow.Picture)
            return PictureTemplate;
        if (item is MainWindow.Parameter)
            return ParameterTemplate;

        // return some default template as fall-back
    }

    public DataTemplate PictureTemplate { get; set; }
    public DataTemplate ParameterTemplate { get; set; }
    // ...add other template references here...
}

You can now define all templates as XAML resources, and simply reference the TemplateSelector within the ListBox:

<Window.Resources>
    <DataTemplate x:Key="PictureTemplate">
        <Image Source="{Binding FullFileName}"/>
    </DataTemplate>
    <DataTemplate x:Key="ParameterTemplate">
        <myControl:ParameterControl Id="{Binding Id}"/>
    </DataTemplate>
    ...add other templates here...
    <local:CustomDataTemplateSelector x:Key="CustomDataTemplateSelector" 
                                      PictureTemplate="{StaticResource PictureTemplate}" 
                                      ParameterTemplate="{StaticResource ParameterTemplate}"/>
</Window.Resources>

<ListBox
    ItemsSource="{Binding Content}"
    ItemTemplateSelector="{StaticResource CustomDataTemplateSelector}">
</ListBox>

Upvotes: 1

Related Questions