Search code examples
c#uwpuwp-xamldatatemplateselectoritemsource

How to dynamically bind the ItemSource of a ListView which has ItemTemplateSelector containing Multiple DataTemplates which have Different DataTypes?


I have an ItemTemplateSelector which contains Multiple DataTemplates which have Different DataTypes. I thus have multiple ItemSources based on Module Selected. How to bind my ListView with multiple ItemSources based on the module selected?

Explanation:

1)ViewModel_A is my ItemSource and DataTemplateA is my DataTemplate when my Module A is Selected

2)ViewModel_B is my ItemSource DataTemplateB is my DataTemplate when my Module B is Selected

I tried Implementing a BaseViewModel and tried binding the BaseViewModel Type in my ItemSource But this doesn't allow the access of derived class properties.

How to Dynamically Select My ItemSource?


Solution

  • Step 1

    First Create a UserControl which contains your ListView in your Xaml and two DependancyProperty for ItemSource and DataTemplate

    DataList.Xaml

    <UserControl
    x:Class="MultipleDataTemplate.DataList"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
    
       <Grid>
       <ListView ItemsSource="{x:Bind ItemsSource,Mode=OneWay}"></ListView>
       </Grid>
    </UserControl>
    

    DataList.xaml.cs

    public sealed partial class DataList : UserControl
    {
        public DataList()
        {
            this.InitializeComponent();
        }
        #region ItemsSource
        public object ItemsSource
        {
            get { return (object)GetValue(ItemsSourceProperty); }
            set {  SetValue(ItemsSourceProperty, value); }
        }              
        public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(DataList), new PropertyMetadata(null));
        #endregion
        #region ItemTemplate
        public DataTemplate ItemTemplate
        {
            get { return (DataTemplate)GetValue(ItemTemplateProperty); }
            set { SetValue(ItemTemplateProperty, value); }
        }
    
        public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register(nameof(ItemTemplate), typeof(DataTemplate), typeof(DataList), new PropertyMetadata(null));
        #endregion
    }
    

    Step 2

    Now you can you this usercontrol with any multiple DataTemplate's and multiple itemsource as below

    MainPage.xaml

    <Page
        x:Class="MultipleDataTemplate.Cars"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    
        xmlns:controls="using:MultipleDataTemplate">
        <Page.Resources>
            <DataTemplate x:Key="CarKey" x:DataType="controls:Car">
                <Grid>
                    <TextBlock Text="{x:Bind carprop1}"></TextBlock>
                    <TextBlock Text="{x:Bind carprop2}"></TextBlock>
    
                </Grid>
            </DataTemplate>
            <DataTemplate x:Key="BikeKey" x:DataType="controls:Bike">
                <Grid>
                    <TextBlock Text="{x:Bind Bikeprop1}"></TextBlock>
                    <TextBlock Text="{x:Bind Bikeprop2}"></TextBlock>
    
                </Grid>
            </DataTemplate>
        </Page.Resources>
        <Grid>        
            <controls:DataList ItemsSource="{x:Bind ItemSource,Mode=OneWay}" ItemTemplate="{x:Bind ItemTemplate}"></controls:DataList>
            <StackPanel>
                <Button Content="Cars" Click="CarsClick"/>
                <Button Content="Bike" Click="BikeClick"/>
            </StackPanel>
        </Grid>
    </Page>
    

    MainPage.xaml.cs

    public sealed partial class Cars : Page, INotifyPropertyChanged
    {
        public object _ItemSource { get; set; }
    
        public object ItemSource
        {
            get { return _ItemSource; }
            set
            {
                _ItemSource = value;
                this.OnPropertyChanged();
            }
        }
        public DataTemplate _itemTemplate { get; set; }
    
        public DataTemplate ItemTemplate
        {
            get { return _itemTemplate; }
            set
            {
                _itemTemplate = value;
                this.OnPropertyChanged();
            }
        }
        public Cars()
        {
            this.InitializeComponent();
        }
        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    
    
        private void CarsClick(object sender, RoutedEventArgs e)
        {
            ItemSource = new List<Car>() { new Car() { carprop1 = "1", carprop2 = "2" } };
            ItemTemplate = this.Resources["CarKey"] as DataTemplate;
        }
    
        private void BikeClick(object sender, RoutedEventArgs e)
        {
            ItemSource = new List<Bike>() { new Bike() { Bikeprop1 = "1", Bikeprop2 = "2" } };
            ItemTemplate = this.Resources["BikeKey"] as DataTemplate;
        }
    }
    public class Car
    {
        public string carprop1 { get; set; }
        public string carprop2 { get; set; }
    }
    public class Bike
    {
        public string Bikeprop1 { get; set; }
        public string Bikeprop2 { get; set; }
    }