ViewModel 中的 ObservableCollection 在筛选后不会呈现 - Maui/WinUI



我正在玩一个MAUI应用程序,并在XamlContentPage中将ObservableCollection绑定到FlexLayout。集合最初显示良好,但我添加了一些过滤逻辑,过滤后集合无法呈现。这似乎只发生在WinUI上,因为它在Android模拟器上过滤和渲染正确,我还没有设置IoS模拟器。这个问题似乎也特定于FlexLayout,因为当我将flex布局更改为ListView时,它也会正确过滤和渲染。

任何关于如何解决这个问题并继续使用flex布局的建议将不胜感激。

ContentPage

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:Views="clr-namespace:Views"
x:Class="Collection"
Title="Collection">
<ContentPage.Content>
<ScrollView>
<StackLayout>
<!--Search-->
<Views:SearchAndFilterView x:Name="SearchView"
Placeholder="Search collection..." 
TextChanged="SearchView_TextChanged"/>

<!-- Collection-->
<FlexLayout x:Name="CollectionFlexLayout"
BindableLayout.ItemsSource="{Binding Collection}"
HorizontalOptions="CenterAndExpand"
Wrap="Wrap">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Views:CollectionCardView 
IconImageSource="{Binding Image}"
CardTitle="{Binding Name}"
Designer="{Binding Designers[0]}"
Publisher="{Binding Publishers[0]}"
YearPublished="{Binding YearPublished}"
PlayCount="{Binding NumPlays}"
MaxPlayers="{Binding MaxPlayers}"
MinPlayers="{Binding MinPlayers}"
PlayTime="{Binding PlayTime}"
MinAge="{Binding MinAge}"/>
</DataTemplate>
</BindableLayout.ItemTemplate>                    
</FlexLayout>
</StackLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>

背后的ContentPage代码

public partial class Collection : ContentPage
{
public ICollectionViewModel collectionViewModel;
public Collection()
{
InitializeComponent();
Init();
InitAsync();
}
public void Init()
{
collectionViewModel = BootStrapper.Resolve<ICollectionViewModel>();
BindingContext = collectionViewModel;
}
public async void InitAsync()
{
await collectionViewModel.GetCollection("testAcct");
}

private void SearchView_TextChanged(object sender, TextChangedEventArgs e)
{
collectionViewModel.FilterCollection(SearchView.SearchText, SearchView.AgeText, SearchView.PlayerCountText, SearchView.PlayTimeText);
}

ViewModel:

public class CollectionViewModel : ViewModelBase, ICollectionViewModel
{
private readonly ILogger _logger;
private readonly ICollectionHandler _collectionHandler;
private readonly ICollectionHelper _collectionHelper;
private readonly IThingHandler _thingHandler;
private ObservableCollection<CollectionPageItem> _collection = new();
private IEnumerable<CollectionPageItem> _fullCollection;
private bool _isBusy;
public CollectionViewModel(ILogger logger, ICollectionHandler collectionHandler, IThingHandler thingHandler,
ICollectionHelper collectionHelper)
{
_logger = logger;
_collectionHandler = collectionHandler;
_collectionHelper = collectionHelper;
_thingHandler = thingHandler;
}
/// <summary>
/// True if the ViewModel is querying data.
/// </summary>
public bool IsBusy
{
get => _isBusy;
set { _isBusy = value; OnPropertyChanged(nameof(IsBusy)); }
}
/// <summary>
/// The Collection to display.
/// </summary>
public ObservableCollection<CollectionPageItem> Collection
{
get { return _collection; }
set { _collection = value; OnPropertyChanged(nameof(Collection)); }
}
/// <summary>
/// Loads the <see cref="Collection"/> property for the given user.
/// </summary>
/// <param name="userName">The user to load a collection for.</param>
public async Task GetCollection(string userName)
{
IsBusy = true;
try
{
var collectionResponse = await _collectionHandler.GetCollectionByUserName(userName);
var things = await _thingHandler.GetThingsById(collectionResponse.Item.Items.Select(x => x.Id).ToList());
_fullCollection = _collectionHelper.CoalesceCollectionData(collectionResponse.Item.Items, things.Item.Things);
Collection = _fullCollection.ToObservableCollection();
}
catch (Exception ex)
{
_logger.Error(ex.Message);
}
finally
{
IsBusy = false;
}
}
//TODO: Make this work
public void FilterCollection(string name, string age, string playercount, string time)
{
IEnumerable<CollectionPageItem> query = _fullCollection;
if (!string.IsNullOrWhiteSpace(name))
{
query = query.Where(x => x.Name.ToLower().Contains(name));
}
if (int.TryParse(age, out int parsedAge))
{
query = query.Where(x => x.MinAge >= parsedAge);
}
if (int.TryParse(playercount, out int parsedPlayercount))
{
query = query.Where(x => x.MinPlayers >= parsedPlayercount);
}
if (int.TryParse(time, out int parsedTime))
{
query = query.Where(x => x.PlayTime <= parsedTime);
}
Collection = query.ToObservableCollection();
}
}

FlexLayout在Windows中似乎有一些间距问题。一个解决方法是为FlexLayout设置HorizontalOptions="Center",并给它HeightRequestWidthRequest值。

最新更新