微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将分组的ListView与不同的模型和DataTemplates一起使用

如何解决将分组的ListView与不同的模型和DataTemplates一起使用

我希望这种类型的ListView具有不同的ViewCell类型,不同的数据,不同的标题文本(带有自定义标题单元格),但都应合而为一ListView

**********************
* General info
**********************
| Category: Cabrio
| Type: Sportscar
**********************
* Available models
**********************
| Year: 2007
| Manufacturer: Chevrolet
| Model: Corvette
----------------------
| Year: 2009
| Manufacturer: Dodge
| Model: Charger
----------------------

因此,我使用此Grouping对象来保存节(标题标题和列表:

Grouping.cs:

public class Grouping<K,T> : ObservableCollection<T>
{
    public K Key { get; private set; }

    public Grouping(K key,IEnumerable<T> items)
    {
        Key = key;
        foreach (var item in items)
            this.Items.Add(item);
    }
}

取自this not available link

如何在ListView中使用其他数据?目前,我的

中包含此非编译代码

MainPage.xaml.cs:

public partial class MainPage : ContentPage
{
    private ObservableCollection<Model.Grouping<string,object>> itemsGrouped;

    public MainPage()
    {
        InitializeComponent();
        
        this.itemsGrouped = new ObservableCollection<Grouping<string,object>>();

        List<Category> categories = new List<Category>();
        categories.Add(new Category("Cabrio","Sportscar"));
        this.itemsGrouped.Add(new Grouping<string,Category>("General info",categories));

        List<CarInfo> cars = new List<CarInfo>();
        cars.Add(new CarInfo("2007","Chevrolet","Corvette"));
        cars.Add(new CarInfo("2009","Dodge","Charger"));
        this.itemsGrouped.Add(new Grouping<string,CarInfo>("Available models",cars));

        this.mainList.BindingContext = this.itemsGrouped;
    }
}

参数1:无法从“ TestGroupedListView.Model.Grouping ”转换为“ TestGroupedListView.Model.Grouping ”

通常的想法是使用DataTemplateSelector来使用不同类型的单元格,并使用Grouping来具有不同的自定义标题标题

这是我的完整示例项目代码

Category.cs:

public class Category
{
    public string CategoryName { get; set; }
    public string TypeOfCar { get; set; }


    public Category(string categoryName,string typeOfCar)
    {
        this.CategoryName = categoryName;
        this.TypeOfCar = typeOfCar;
    }
}

CarInfo.cs:

public class CarInfo
{
    public string Year { get; set; }
    public string Manufacturer { get; set; }
    public string Name { get; set; }

    public CarInfo(string year,string manufacturer,string name)
    {
        this.Year = year;
        this.Manufacturer = manufacturer;
        this.Name = name;
    }
}

GeneralView.xaml:

<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TestGroupedListView.CustomView.GeneralView">
    
    <Grid x:Name="mainGrid" Padding="5" VerticalOptions="CenterandExpand">


    </Grid>
    
</ViewCell>

GeneralView.xaml.cs:

[XamlCompilation(XamlCompilationoptions.Compile)]
public partial class GeneralView : ViewCell
{
    private List<keyvaluePair<string,string>> dataList;

    public GeneralView()
    {
        InitializeComponent();
    }

    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();

        var generalInfo = BindingContext as Category;

        if (generalInfo != null)
        {
            this.SetupView(generalInfo);
        }
    }

    private void SetupView(Category item)
    {
        this.dataList = new List<keyvaluePair<string,string>>();
        this.dataList.Add(new keyvaluePair<string,string>("Name",item.CategoryName));
        this.dataList.Add(new keyvaluePair<string,string>("Type",item.TypeOfCar));

        this.mainGrid.ColumnDeFinitions.Add(new ColumnDeFinition { Width = new GridLength(1,GridUnitType.Star) });
        this.mainGrid.ColumnDeFinitions.Add(new ColumnDeFinition { Width = new GridLength(1,GridUnitType.Star) });

        for (int i = 0; i < dataList.Count; i++)
        {
            this.mainGrid.RowDeFinitions.Add(new RowDeFinition { Height = GridLength.Auto });

            var keyLabel = new Label()
            {
                Text = dataList[i].Key
            };

            var valueLabel = new Label()
            {
                Text = dataList[i].Value
            };

            this.mainGrid.Children.Add(keyLabel,i);
            this.mainGrid.Children.Add(valueLabel,1,i);
        }
    }
}

InfoItemView.xaml:

<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" 
          xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
          x:Class="TestGroupedListView.CustomView.InfoItemView">
    <Grid x:Name="mainGrid" Padding="5" VerticalOptions="CenterandExpand">


    </Grid>
</ViewCell>

InfoItemView.xaml.cs:

[XamlCompilation(XamlCompilationoptions.Compile)]
public partial class InfoItemView : ViewCell
{
    private List<keyvaluePair<string,string>> dataList;

    public InfoItemView()
    {
        InitializeComponent();
    }

    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();

        var info = BindingContext as CarInfo;

        if (info != null)
        {
            this.SetupView(info);
        }
    }

    private void SetupView(CarInfo item)
    {
        this.dataList = new List<keyvaluePair<string,string>("Year",item.Year));
        this.dataList.Add(new keyvaluePair<string,string>("Manufacturer",item.Manufacturer));
        this.dataList.Add(new keyvaluePair<string,item.Name));

        this.mainGrid.ColumnDeFinitions.Add(new ColumnDeFinition { Width = new GridLength(1,i);
        }
    }
}

在我的真实项目中,两种单元格类型的差异更大,但是您应该明白这一点。

ListViewGroupHeader.cs:

public class ListViewGroupHeader : Label
{
}

MyDataTemplateSelector.cs:

public class MyDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate CarTemplate { get; set; }
    public DataTemplate GeneralTemplate { get; set; }

    protected override DataTemplate OnSelectTemplate(object item,BindableObject container)
    {
        if (item is CarInfo)
        {
            return this.CarTemplate;
        }
        else if (item is Category)
        {
            return this.GeneralTemplate;
        }

        return new DataTemplate();
    }
}

MainPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:renderer="clr-namespace:TestGroupedListView.Customrenderer;assembly=TestGroupedListView"
             xmlns:customViews="clr-namespace:TestGroupedListView.CustomView;assembly=TestGroupedListView"
             xmlns:local="clr-namespace:TestGroupedListView.Helper;assembly=TestGroupedListView"
             x:Class="TestGroupedListView.MainPage">

    <ContentPage.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="carTemplate">
                <customViews:InfoItemView />
            </DataTemplate>
            <DataTemplate x:Key="generalTemplate">
                <customViews:GeneralView />
            </DataTemplate>
            <local:MyDataTemplateSelector x:Key="myDataTemplateSelector" CarTemplate="{StaticResource carTemplate}" GeneralTemplate="{StaticResource generalTemplate}" />
        </ResourceDictionary>
    </ContentPage.Resources>

    <ListView x:Name="mainList" 
              SeparatorColor="{StaticResource PrimaryLight}"
              HasUnevenRows="True"
              GroupdisplayBinding="{Binding Key}"
              IsGroupingEnabled="True"
              CachingStrategy="RecycleElement"
              ItemTemplate="{StaticResource myDataTemplateSelector}">

        
        <ListView.GroupHeaderTemplate>
            <DataTemplate>
                <renderer:ListViewGroupHeader Text="{Binding Key}" Style="{StaticResource labelHeader}" HeightRequest="40" />
            </DataTemplate>
        </ListView.GroupHeaderTemplate>
        
        <!--
        <ListView.ItemTemplate>
            <DataTemplate>
                <customViews:InfoItemView />
            </DataTemplate>
        </ListView.ItemTemplate>
        -->
    </ListView>

</ContentPage>

就是这个想法。那行得通吗?还是应该寻找其他解决方案?我在Google找不到完全相同的问题……(也许关键字错了?)

解决方法

FreakyAli所述,TableView是一个选项。我完全忘记了这一点,因此我举了一个最小的例子。

MainPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TestGroupedListView.MainPage">

    <TableView x:Name="tableData" HasUnevenRows="True">
        
    </TableView>

</ContentPage>

MainPage.xaml.cs:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        this.tableData.Intent = TableIntent.Data;

        var category = new Category("Cabrio","Sportscar");
        var generalView = new GeneralView();
        generalView.BindingContext = category;

        this.tableData.Root = new TableRoot()
        {
            new TableSection()
            {
                new ViewCell()
                {
                    View = new ListViewGroupHeader() 
                            {
                                Text = "General info",HeightRequest = 40,FontAttributes = FontAttributes.Bold,TextColor = Color.White,BackgroundColor = Color.Blue,VerticalTextAlignment = TextAlignment.Center
                            }
                }
            },new TableSection()
            {
                generalView
            },new TableSection()
            {
                new ViewCell()
                {
                    View = new ListViewGroupHeader()
                            {
                                Text = "Available models",};

        List<CarInfo> cars = new List<CarInfo>();
        cars.Add(new CarInfo("2007","Chevrolet","Corvette"));
        cars.Add(new CarInfo("2009","Dodge","Charger"));

        foreach (var car in cars)
        {
            var carInfo = new InfoItemView();
            carInfo.BindingContext = car;
            carInfo.Tapped += CarInfo_Tapped;
            this.tableData.Root.Add(new TableSection() { carInfo });
        }

        
    }

    private void CarInfo_Tapped(object sender,EventArgs e)
    {
        var carInfo = (InfoItemView)sender;
        var car = (CarInfo)carInfo.BindingContext;
        System.Diagnostics.Debug.WriteLine(car.Name);
    }
}

对于自定义标题,this comment帮助了我。可以使用不带标题文本的TableSection

结果如下:

TableView with different TableSection

我必须重新构建我的应用程序,以查看是否满足所有条件和特殊情况,但是看起来很遗憾。但是我仍然很想知道您是否可以在ListView中使用不同类型的对象……另一种选择是在StackLayout中使用ScrollView并逐个添加元素

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。