c# - ListView 不随分组滚动

标签 c# android xamarin uwp xamarin.forms

我只是将 ListView 更改为使用分组,但现在我无法再使用 ScrollTo

我创建了一个简单的应用程序,因此您可以看到问题。

XAML 页面看起来像(我目前没有在我的应用程序中使用 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:local="clr-namespace:ScrollListExample"
   x:Class="ScrollListExample.ProjectPage">

   <Grid>
      <Grid.RowDefinitions>
         <RowDefinition Height="Auto" />
         <RowDefinition Height="*" />
      </Grid.RowDefinitions>

      <ListView x:Name="ProjectsListView" HasUnevenRows="True" IsGroupingEnabled="True" ItemsSource="{Binding Projects}">
         <ListView.GroupHeaderTemplate>
            <DataTemplate>
               <ViewCell>
                  <Label Text="{Binding Path=Key}" />
               </ViewCell>
            </DataTemplate>
         </ListView.GroupHeaderTemplate>
         <ListView.ItemTemplate>
            <DataTemplate>
               <ViewCell>
                  <Grid>
                     <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="Auto" />
                     </Grid.ColumnDefinitions>
                     <Label Grid.Column="0" Grid.Row="0" LineBreakMode="TailTruncation" Text="{Binding Path=ProjectName}" />
                     <Label Grid.Column="0" Grid.Row="1" Text="{Binding Path=ProjectReference, StringFormat='Sag: {0}'}" />
                     <Label Grid.Column="0" Grid.Row="2" Text="{Binding Path=CustomerName}" />
                     <Label Grid.Column="0" Grid.Row="3" Text="{Binding Path=FullAddress}" />
                     <Label Grid.Column="1" Grid.Row="0" Text="{Binding Path=StartTime}" />
                  </Grid>
               </ViewCell>
            </DataTemplate>
         </ListView.ItemTemplate>
      </ListView>
   </Grid>

</ContentPage>

示例的代码隐藏文件如下所示

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ProjectPage : ContentPage
{
   public ProjectPage()
   {
      InitializeComponent();
      BindingContext = new ProjectsViewModel();
   }

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

      Acr.UserDialogs.UserDialogs.Instance.ShowLoading();

      var projects = Newtonsoft.Json.JsonConvert.DeserializeObject<IList<ProjectDto>>("[{\"ProjectName\":\"Test sag\",\"ProjectReference\":\"10072\",\"CustomerName\":\"Test firma\",\"FullAddress\":\"Testvej 3\",\"StartDate\":\"2017-02-02T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"aaa\",\"ProjectReference\":\"10077\",\"CustomerName\":\"Test firma\",\"FullAddress\":\"Testvej 12\",\"StartDate\":\"2017-02-08T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"Test\",\"ProjectReference\":\"10082\",\"CustomerName\":\"Test firma\",\"FullAddress\":\"Testvej 50\",\"StartDate\":\"2017-02-16T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"Test\",\"ProjectReference\":\"10085\",\"CustomerName\":\"Testvej boligselskab\",\"FullAddress\":\"Testvej 14\",\"StartDate\":\"2017-02-24T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"Test\",\"ProjectReference\":\"10086\",\"CustomerName\":\"Testing\",\"FullAddress\":\"Testevej 14\",\"StartDate\":\"2017-02-27T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"Test1\",\"ProjectReference\":\"10087\",\"CustomerName\":\"Plejecenter testlyst\",\"FullAddress\":\"Testlystvej 11\",\"StartDate\":\"2017-02-27T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"Test2\",\"ProjectReference\":\"10088\",\"CustomerName\":\"Charlie\",\"FullAddress\":\"Testvej 50\",\"StartDate\":\"2017-02-27T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"Test\",\"ProjectReference\":\"10089\",\"CustomerName\":\"Standard Debitor\",\"FullAddress\":\"[Mangler]\",\"StartDate\":\"2017-03-16T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"Test\",\"ProjectReference\":\"10090\",\"CustomerName\":\"Standard Debitor\",\"FullAddress\":\"[Mangler]\",\"StartDate\":\"2017-03-16T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"Test\",\"ProjectReference\":\"10091\",\"CustomerName\":\"Standard Debitor\",\"FullAddress\":\"[Mangler]\",\"StartDate\":\"2017-03-16T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"Test\",\"ProjectReference\":\"10092\",\"CustomerName\":\"Tester\",\"FullAddress\":\"Testvej 11\",\"StartDate\":\"2017-03-16T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"Test\",\"ProjectReference\":\"10093\",\"CustomerName\":\"Plejehjemmet test\",\"FullAddress\":\"Testvej 90\",\"StartDate\":\"2017-03-16T00:00:00\",\"StartTime\":\"\"},{\"ProjectName\":\"Test\",\"ProjectReference\":\"10094\",\"CustomerName\":\"Plejehjemmet test\",\"FullAddress\":\"Testvej 90\",\"StartDate\":\"2017-03-16T00:00:00\",\"StartTime\":\"\"}]");

      var viewModel = BindingContext as ProjectsViewModel;
      if (viewModel != null)
         viewModel.OriginalProjects = projects;

      Acr.UserDialogs.UserDialogs.Instance.ShowLoading("Loading");

      Task.Delay(5000).ContinueWith((x) =>
      {
          Device.BeginInvokeOnMainThread(Acr.UserDialogs.UserDialogs.Instance.HideLoading);

         Search();
      });
   }

   private void Search(string inputVal = null)
   {
      var viewModel = BindingContext as ProjectsViewModel;

      if (viewModel != null)
      {
         var projects = viewModel.OriginalProjects.Where(p => !string.IsNullOrEmpty(inputVal) ? p.ProjectName.Contains(inputVal) : true);

         var orderedProjects = projects.OrderBy(p => p.StartDate);

         Device.BeginInvokeOnMainThread(() =>
         {
            foreach (ProjectDto project in orderedProjects)
            {
               var coll = viewModel.Projects.FirstOrDefault(c => c.Key == project.StartDate);

               if (coll == null)
                  viewModel.Projects.Add(coll = new ObservableCollectionWithDateKey { Key = project.StartDate });

               coll.Add(project);
            }

            var group = viewModel.Projects.LastOrDefault();
            if (group != null)
               ProjectsListView.ScrollTo(group.First(), group.Key, ScrollToPosition.Start, false);
         });
      }
   }
}

class ProjectsViewModel : INotifyPropertyChanged
{
   private ObservableCollection<ObservableCollectionWithDateKey> _projects;

   public event PropertyChangedEventHandler PropertyChanged;

   public IEnumerable<ProjectDto> OriginalProjects { get; set; }

   public ObservableCollection<ObservableCollectionWithDateKey> Projects
   {
      get { return _projects; }
      set
      {
         _projects = value;
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Projects)));
      }
   }

   public ProjectsViewModel()
   {
      Projects = new ObservableCollection<ObservableCollectionWithDateKey>();
   }
}

public class ProjectDto : INotifyPropertyChanged
{
   public string ProjectName { get; set; }
   public string ProjectReference { get; set; }
   public string CustomerName { get; set; }
   public string FullAddress { get; set; }
   public DateTime StartDate { get; set; }
   public string StartTime { get; set; }

   public event PropertyChangedEventHandler PropertyChanged;
}

class ObservableCollectionWithDateKey : ObservableCollection<ProjectDto>
{
   public DateTime Key { get; set; }
}

我使用Task.Delay(5000)来模拟来自服务器的响应,但我认为这并不重要。

更新

我发现问题出在我的 ScrollTo 调用中,其中 ScrollTo(group.First(), group.Key, ScrollToPosition.Start, false);是用 key 调用的,而不仅仅是组。

如果您首先创建分组(没有将其添加到 ViewModel),则必须随后在 ViewModel 中找到正确的模型。否则它找不到正确的 ObservableCollection

最佳答案

我已经测试了您的代码并重现了您的问题。问题是您将错误的参数传递给 ScrollTo方法。

ProjectsListView.ScrollTo(group.First(), group.Key, ScrollToPosition.Start, false);

ScrollTo 方法的 group 参数是来自 ListView.ItemsSource 的组。但是您传递了一个group.Key。所以该方法不会像预期的那样被激发。请修改如下代码。

Device.BeginInvokeOnMainThread(() =>
 {
     foreach (ProjectDto project in orderedProjects)
     {
         var coll = viewModel.Projects.FirstOrDefault(c => c.Key == project.StartDate);

         if (coll == null)
             viewModel.Projects.Add(coll = new ObservableCollectionWithDateKey { Key = project.StartDate });

         coll.Add(project);
     }
 var group = viewModel.Projects.Last();
 if (group != null)
     ProjectsListView.ScrollTo(group.First(), group, ScrollToPosition.Start, false);
});

关于c# - ListView 不随分组滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42979878/

相关文章:

C# Web API 基于 GET 请求的 XML 或 JSON

c# - 检索动态创建的 RadioButtonList 的回发值不起作用

c# - C# 和 C++ 之间可以传输什么类型的数据

在 Android Studio 中找不到 Java 类

c# - 创建 Xamarin 插件/用户控件库

c# - 如何在 Linq Query 中获取 IndexOf() 空格

java - 无法使用Media Player在android中播放音频

android - 从静态方法调用 finish()

c# - 使用 MVVM 在 Xamarin 中的 Android 中进行 GPS 位置

xamarin - 我是否需要停止在 UI 线程中运行的方法?