Search code examples
c#xamldatatemplatemaui.net-maui

Dotnet MAUI with MVMM - Dynamic dataTemplate based on ObservableCollection<T> where T is an interface


I'm trying de build a new DotNet MAUI application.

I have a datasource of this kind : public ObservableCollection<IIpxElement> IpxElements { get; }

With this in the Xaml

<CollectionView ItemsSource="{Binding IpxElements}" SelectionMode="None">
   <CollectionView.ItemsLayout>
     <GridItemsLayout Orientation="Vertical" Span="2" />
  </CollectionView.ItemsLayout>
</CollectionView>

I don't want to create a DataTemplateSelector for each type who implements IIpxElement

When i was using WPF and Caliburn Micro i could do something like that :

<ItemsControl x:Name="IpxElements">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <ContentControl cal:View.Model="{Binding}" />
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

The binding between the Name and the ItemSource was automatic but here i don't really care.

I just want to have a "dynamic" dataTemplate based on associated concrete type (of ViewModel) and view (by naming convention) since i could have a lot of implementation.

Is there anyway of doing something like this ?

Thanks you,

Cyril


Solution

  • I achieve what i want using a DataTemplateSelector and using reflection

    public class CustomDataTemplateSelector : DataTemplateSelector
    {
        protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
         {
             var viewModelConcreteType = item.GetType();
             var viewFullName = viewModelConcreteType.FullName.Replace("ViewModel", "View");
             var viewType = Type.GetType(viewFullName);
             var dataTemplate = new DataTemplate(viewType);
             dataTemplate.SetValue(BindableObject.BindingContextProperty, item);
             return dataTemplate;
         }
    }
    
    <ContentPage.Resources>
       <resources:CustomDataTemplateSelector x:Key="customDataTemplateSelector" />
    </ContentPage.Resources>
    <CollectionView ItemsSource="{Binding IpxElements}" 
                    SelectionMode="None" 
                    ItemTemplate="{StaticResource customDataTemplateSelector}">
        <CollectionView.ItemsLayout>
            <GridItemsLayout Orientation="Vertical" Span="2" />
        </CollectionView.ItemsLayout>
    </CollectionView>
    

    Since i'm using naming convention it was the easiest way to do it.

    The View used is the DataTemplate have to be a ContentView and not ContentPage.