在自定义元素内的 CollectionView 中渲染元素

问题描述 投票:0回答:1

我目前正在尝试创建一个冻结第一行的自定义 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" }
     };
     }
 }

但是,这似乎无法正确渲染,我不确定为什么。此时我有两个问题:

  1. 这甚至是在 CollectionView 中实现冻结行的好方法吗?我能找到的唯一其他有效解决方案是在滚动时修改 Translation.Y 值。但这看起来很糟糕,因为行不断移动并落后于滚动,而且我不打算使用它。

  2. 如何正确渲染项目?我尝试了更基本的渲染,例如尝试渲染 HeaderExample 字符串, 但它仍然不起作用。此外,我已经确认在使用常规 CollectionView 时我的视图模型的项目可以正确渲染。

对于此事,我将不胜感激。谢谢你。

xamarin maui maui-windows
1个回答
0
投票

您不需要自定义

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>

© www.soinside.com 2019 - 2024. All rights reserved.