如何解决将分组的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);
}
}
如何在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
。
结果如下:
我必须重新构建我的应用程序,以查看是否满足所有条件和特殊情况,但是看起来很遗憾。但是我仍然很想知道您是否可以在ListView
中使用不同类型的对象……另一种选择是在StackLayout
中使用ScrollView
并逐个添加元素
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。