我目前正在尝试创建一个冻结第一行的自定义 CollectionView 元素,以便用户在向下滚动时可以看到第一个条目。经过一番尝试和错误后,我得出的结论是,最好的方法是将第一个元素与其余元素分开渲染。所以我创建了一个自定义类,如下所示:
internal class CustomCollectionView : StackLayout
{
public static readonly BindableProperty FirstItemProperty = BindableProperty.Create(
nameof(FirstItem),
typeof(string),
typeof(CustomCollectionView),
null);
public string FirstItem
{
get => (string)GetValue(FirstItemProperty);
set => SetValue(FirstItemProperty, value);
}
public static readonly BindableProperty RemainingItemsProperty = BindableProperty.Create(
nameof(RemainingItems),
typeof(ObservableCollection<Person>),
typeof(CustomCollectionView),
new ObservableCollection<Person>());
public ObservableCollection<Person> RemainingItems
{
get => (ObservableCollection<Person>)GetValue(RemainingItemsProperty);
set => SetValue(RemainingItemsProperty, value);
}
public CustomCollectionView()
{
var frozenRow = new Frame {
BackgroundColor = Colors.LightGray,
Padding = new Thickness(10),
Content = new Label { FontSize = 24, VerticalOptions = LayoutOptions.Center }
};
frozenRow.SetBinding(Label.TextProperty, new Binding(nameof(FirstItem), source: this.FirstItem));
var collectionView = new CollectionView
{
ItemsSource = RemainingItems,
ItemTemplate = new DataTemplate(() =>
{
return new Label { FontSize = 18, VerticalOptions = LayoutOptions.Center };
})
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, new Binding(nameof(RemainingItems), source: this.RemainingItems));
Children.Add(frozenRow);
Children.Add(collectionView);
}
}
在 XAML 中,我尝试通过以下方式呈现:
<Grid>
<local:CustomCollectionView FirstItem="{Binding HeaderExample}" RemainingItems="{Binding People}"></local:CustomCollectionView>
</Grid>
我的 ViewModel 定义为
class PersonViewModel
{
public ObservableCollection<Person> People { get; set; }
public ObservableCollection<Person> HeaderItem { get; set; }
public string HeaderExample;
public PersonViewModel()
{
// Sample data
HeaderExample = "This is a header";
HeaderItem = new ObservableCollection<Person> { new Person { Name = "Header", Age = 10, Location = "Korea" } };
People = new ObservableCollection<Person>
{
new Person { Name = "Person A", Age = 30, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" },
new Person { Name = "Person B", Age = 31, Location = "Seoul" }
};
}
}
但是,这似乎无法正确渲染,我不确定为什么。此时我有两个问题:
这甚至是在 CollectionView 中实现冻结行的好方法吗?我能找到的唯一其他有效解决方案是在滚动时修改 Translation.Y 值。但这看起来很糟糕,因为行不断移动并落后于滚动,而且我不打算使用它。
如何正确渲染项目?我尝试了更基本的渲染,例如尝试渲染 HeaderExample 字符串, 但它仍然不起作用。此外,我已经确认在使用常规 CollectionView 时我的视图模型的项目可以正确渲染。
对于此事,我将不胜感激。谢谢你。
您不需要自定义
CollectionView
元素来保留 FirstItem(向下滚动时冻结的第一行)。您可以只使用 Grid
,然后将 FirstItem
放在第一行,然后将 CollectionView
放在其下方,这与 Jason 在上面评论中建议的类似。
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid ColumnSpacing="0" RowSpacing="0" Grid.Row="0" Grid.Column="0" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Entry BackgroundColor="Gray" Text="This ia a header"/>
</Grid>
<CollectionView ItemsSource="{Binding People}" Grid.Row="1" Grid.Column="0" HeightRequest="800">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Column="0" Text ="{Binding Name}" ></Label>
<Label Grid.Column="1" Text ="{Binding Age}" ></Label>
<Label Grid.Column="2" Text ="{Binding Location}" ></Label>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>