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
CodePudding user response:
Depending on the specific situation, we generally use two methods to achieve it.
If the gap in the layout of the items is large, we recommend using DataTemplateSelector.
If the layout of the items does not vary much, you can try to add some fields(e.g. bool isVisible
) to display or hide some controls based on the associated concrete type (of ViewModel) and view (by naming convention) you mentioned above.
Of course, you can also use it in conjunction with the above methods.
CodePudding user response:
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.