【发布时间】:2021-10-11 11:27:05
【问题描述】:
我正在学习 Xamarin,我正在尝试制作一个应用程序,我可以在其中浏览屏幕中的一些元素,然后单击元素打开一个新屏幕。我尝试使用弹出模板,并在第一个屏幕上使用模板中的 collectionview 逻辑。但是,使用相同的逻辑,我没有在我的集合视图中看到任何数据。这是我的模型、视图、视图模型以及 xaml 和 cs 文件。 型号:
public class VehicleMake
{
public string Id { get; set; }
public string Name { get; set; }
public string Abrv { get; set; }
}
查看:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
BackgroundColor="LightCoral"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:VehicleProject.ViewModels"
xmlns:model="clr-namespace:VehicleProject.Models"
x:DataType="local:VehicleMakeViewModel"
x:Class="VehicleProject.Views.VehicleMakePage">
<RefreshView x:DataType="local:VehicleMakeViewModel" Command="{Binding LoadItemsCommand}" IsRefreshing="{Binding IsBusy, Mode=TwoWay}">
<CollectionView x:Name="ItemsListView"
ItemsSource="{Binding VehicleMakes}"
SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10" x:DataType="model:VehicleMake" BackgroundColor="White">
<Label Text="{Binding Id}"
TextColor="White"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Label Text="{Binding Name}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13" />
<StackLayout.GestureRecognizers>
<TapGestureRecognizer
NumberOfTapsRequired="1"
Command="{Binding Source={RelativeSource AncestorType={x:Type local:VehicleModelViewModel}}, Path=ItemTapped}"
CommandParameter="{Binding .}">
</TapGestureRecognizer>
</StackLayout.GestureRecognizers>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</RefreshView>
</ContentPage>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VehicleProject.ViewModels;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace VehicleProject.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class VehicleMakePage : ContentPage
{
VehicleMakeViewModel _viewModel;
public VehicleMakePage()
{
InitializeComponent();
BindingContext = _viewModel = new VehicleMakeViewModel();
}
protected override void OnAppearing()
{
base.OnAppearing();
_viewModel.OnAppearing();
}
}
}
视图模型:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using VehicleProject.Models;
using Xamarin.Forms;
namespace VehicleProject.ViewModels
{
public class VehicleMakeViewModel: BaseViewModel
{
private VehicleMake _selectedItem;
public ObservableCollection<VehicleMake> VehicleMakes { get; set; } = new ObservableCollection<VehicleMake>();
public Command LoadItemsCommand { get; }
public Command AddItemCommand { get; }
public Command<VehicleMake> ItemTapped { get; }
public VehicleMakeViewModel()
{
Title = "Vehicles";
VehicleMakes = new ObservableCollection<VehicleMake>();
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
ItemTapped = new Command<VehicleMake>(OnItemSelected);
AddItemCommand = new Command(OnAddItem);
}
async Task ExecuteLoadItemsCommand()
{
IsBusy = true;
try
{
VehicleMakes.Clear();
var vehicleMakes = await DataStore.GetItemsAsync(true);
foreach (var vehicleMake in vehicleMakes)
{
Debug.WriteLine(vehicleMake.Id);
VehicleMakes.Add(vehicleMake);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
public void OnAppearing()
{
IsBusy = true;
SelectedItem = null;
}
public VehicleMake SelectedItem
{
get => _selectedItem;
set
{
SetProperty(ref _selectedItem, value);
OnItemSelected(value);
}
}
private async void OnAddItem(object obj)
{
//await Shell.Current.GoToAsync(nameof(NewItemPage));
}
async void OnItemSelected(VehicleMake item)
{
if (item == null)
return;
// This will push the ItemDetailPage onto the navigation stack
//await Shell.Current.GoToAsync($"{nameof(ItemDetailPage)}?{nameof(ItemDetailViewModel.ItemId)}={item.Id}");
}
}
}
BaseViewModel:
public class BaseViewModel : INotifyPropertyChanged
{
public IDataStore<VehicleMake> DataStore => DependencyService.Get<IDataStore<VehicleMake>>();
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set { SetProperty(ref isBusy, value); }
}
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName] string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
IDataStore:
public interface IDataStore<T>
{
Task<bool> AddItemAsync(T item);
Task<bool> UpdateItemAsync(T item);
Task<bool> DeleteItemAsync(string id);
Task<T> GetItemAsync(string id);
Task<IEnumerable<T>> GetItemsAsync(bool forceRefresh = false);
}
MockVehicleMakeStore:
public class MockVehicleMakeStore : IDataStore<VehicleMake>
{
readonly List<VehicleMake> vehicleMakes;
public MockVehicleMakeStore()
{
vehicleMakes = new List<VehicleMake>()
{
new VehicleMake { Id = Guid.NewGuid().ToString(), Name = "First item", Abrv="This is an item description." },
new VehicleMake { Id = Guid.NewGuid().ToString(), Name = "Second item", Abrv="This is an item description." },
new VehicleMake { Id = Guid.NewGuid().ToString(), Name = "Third item", Abrv="This is an item description." },
new VehicleMake { Id = Guid.NewGuid().ToString(), Name = "Fourth item", Abrv="This is an item description." },
new VehicleMake { Id = Guid.NewGuid().ToString(), Name = "Fifth item", Abrv="This is an item description." },
new VehicleMake { Id = Guid.NewGuid().ToString(), Name = "Sixth item", Abrv="This is an item description." },
new VehicleMake { Id = Guid.NewGuid().ToString(), Name = "Sixth item", Abrv="This is an item description." },
new VehicleMake { Id = Guid.NewGuid().ToString(), Name = "Sixth item", Abrv="This is an item description." }
};
}
public async Task<bool> AddItemAsync(VehicleMake item)
{
vehicleMakes.Add(item);
return await Task.FromResult(true);
}
public async Task<bool> UpdateItemAsync(VehicleMake item)
{
var oldItem = vehicleMakes.Where((VehicleMake arg) => arg.Id == item.Id).FirstOrDefault();
vehicleMakes.Remove(oldItem);
vehicleMakes.Add(item);
return await Task.FromResult(true);
}
public async Task<bool> DeleteItemAsync(string id)
{
var oldItem = vehicleMakes.Where((VehicleMake arg) => arg.Id == id).FirstOrDefault();
vehicleMakes.Remove(oldItem);
return await Task.FromResult(true);
}
public async Task<VehicleMake> GetItemAsync(string id)
{
return await Task.FromResult(vehicleMakes.FirstOrDefault(s => s.Id == id));
}
public async Task<IEnumerable<VehicleMake>> GetItemsAsync(bool forceRefresh = false)
{
return await Task.FromResult(vehicleMakes);
}
}
我的解决方案的逻辑与模板中的逻辑相同,但似乎我正在监督一些事情。请帮忙。谢谢
【问题讨论】:
-
是自动执行,还是手动触发刷新?无论哪种方式,您都应该验证您的虚拟机确实包含数据
-
您需要使用调试器来验证您的加载命令是否正在执行,以及它是否实际正在加载数据
-
某事为空。弄清楚它是什么并修复它。堆栈跟踪应该准确地告诉您是哪一行导致它。这是基本的 C# 调试。
-
您检查过
DataStore是否为空吗? -
我第三次将相同的逻辑应用于一个新的项目模板,现在它可以工作了。 DataStore 无法正常工作,因为它没有被初始化。谢谢
标签: c# xamarin xamarin.forms collectionview