Xamarin.forms MVVM。列表视图仍然为空

Posted

技术标签:

【中文标题】Xamarin.forms MVVM。列表视图仍然为空【英文标题】:Xamarin.forms MVVM. Listview remains empty 【发布时间】:2018-10-17 02:35:36 【问题描述】:

我对 Xamarin.Forms 和 MVVM 非常陌生,并且在 *** 上发布了问题,所以请多多包涵。我正在尝试在 Xamarin.Forms 中填充列表视图。我第一次在没有 MVVM 的情况下对其进行了编程,一切都像我想要的那样工作,但现在我想进入 MVVM,这就是它出错的地方,现在我的列表不会再填满了。 我做了一个viewmodel,只把所有的绑定都放在了viewmodel中,还没有实现eventhandlers。

这是背后的代码的一部分(我还有几个事件处理程序,但现在不相关):

    namespace CCXamarinApp
    
        [XamlCompilation(XamlCompilationOptions.Compile)]
        public partial class PatientsWithTagPage : ContentPage
        
            public PatientsWithTagPage()
            
                BindingContext = new PatientsWithTagViewModel();

                InitializeComponent();
                (BindingContext as PatientsWithTagViewModel).GetAllPatients();

                if((BindingContext as PatientsWithTagViewModel).IsEmptyPatientList)
                    HandleEmptyList();
                else
                    (BindingContext as PatientsWithTagViewModel).SortAndShowPatients();
            

            private void SearchBar_OnTextChanged(object sender, TextChangedEventArgs e)
            
            (BindingContext as PatientsWithTagViewModel).Searching(e.NewTextValue);
            
           ...

这是我的 XAML 页面

        <SearchBar x:Name="SearchBar" Placeholder="Zoek op naam of plaats..." HeightRequest="25" Margin="10"
                TextChanged="SearchBar_OnTextChanged"/>

        <Label Text="Binding LastRefreshed" FontAttributes="Italic" FontSize="15" />

        <Label x:Name="LabelEmptyList" FontSize="17" Text="Geen gegevens gevonden" FontAttributes="Bold"
                IsVisible="False" />

        <ListView x:Name="PatientListView" HasUnevenRows="True" SeparatorColor="Accent"
                VerticalOptions="FillAndExpand" IsPullToRefreshEnabled="True" IsRefreshing="Binding IsFetchingData, Mode=TwoWay"
                Refreshing="PatientListView_OnRefreshing" SelectedItem="Binding SelectedPatient, Mode=TwoWay"
                ItemSelected="PatientListView_OnItemSelected" ItemsSource="Binding Patients"
                  IsVisible="True" BackgroundColor="Aqua">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Spacing="4">
                            <StackLayout Orientation="Horizontal" Margin="10,7,10,1">
                                <Label Text="Binding FullName" FontAttributes="Bold" FontSize="16" />
                                <Label Text="Binding DisplayTimeOfLastScan, StringFormat='0'"
                                        HorizontalOptions="EndAndExpand" />
                            </StackLayout>
                            <StackLayout Orientation="Horizontal" Margin="10,0,10,7">
                                <Label Text="Binding LastLocation" HorizontalOptions="Start" />
                                <Label Text="Binding DisplayDurationSinceLastScan, StringFormat='al 0'"
                                        HorizontalOptions="EndAndExpand" />
                            </StackLayout>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage.Content>

这是我的 viewmodel(不是所有代码,而是最相关的代码)。它派生的 BaseViewModel 来自 nuget 包“Refractored.Mvvmhelpers”:

class PatientsWithTagViewModel : BaseViewModel
    
    public ObservableCollection<PatientViewModel> Patients  get; private set;  = new ObservableCollection<PatientViewModel>();

    private PatientViewModel selectedPatient;
    public PatientViewModel SelectedPatient
    
        get => selectedPatient;
        set => SetProperty(ref selectedPatient, value);
    

    private readonly JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings
    
        DateFormatString = "dd-MM-yyyTH:mm",
        DateTimeZoneHandling = DateTimeZoneHandling.Utc,
    ;

    public bool IsEmptyPatientList => Patients.Count == 0;

    private string testJson = "[\"firstName\":\"P.\",\"lastName\":\"Selie\",\"tag\":\"tagId\":\"124\",\"tagSerialNumber\":\"ABC135\",\"scans\":[\"location\":\"Tuin\",\"dateTime\":\"May01,2018,10:10\",\"location\":\"Eetzaal\",\"dateTime\":\"May02,2018,10:15\",\"location\":\"Gang\",\"dateTime\":\"May02,2018,11:10\",\"location\":\"Kamer23\",\"dateTime\":\"May02,2018,12:09\"],\"id\":\"dcc4fe9929b3681f\"," +
                              "\"firstName\":\"W.\",\"lastName\":\"Janssens\",\"tag\":\"tagId\":\"132\",\"tagSerialNumber\":\"ABC167\",\"scans\":[\"location\":\"Kamer23\",\"dateTime\":\"May01,2018,23:39\",\"location\":\"Gang\",\"dateTime\":\"May02,2018,04:10\",\"location\":\"Eetzaal\",\"dateTime\":\"May02,2018,04:11\",\"location\":\"Gang\",\"dateTime\":\"May02,2018,04:20\",\"location\":\"Kamer23\",\"dateTime\":\"May02,2018,04:22\"],\"id\":\"a6dac28475327922\"]";

    public void GetAllPatients()
    
        IsFetchingData = true;
        try
        
            Patients = new ObservableCollection<PatientViewModel>(
                JsonConvert.DeserializeObject<ObservableCollection<PatientViewModel>>(testJson,
                    jsonSerializerSettings));
        
        catch(Exception e)
        
            Console.WriteLine("*****ERROR kon API niet ophalen");
            Console.WriteLine(e.Message);
        
        finally
        
            IsFetchingData = false;
        
    

这是我使用的模型

public class Patient : ObservableObject
    
        public string FirstName  get; set; 
        public string LastName  get; set; 
        public Tag Tag  get; set; 
        public List<Scan> Scans  get; set; 
        public string Id  get; set; 

        public override string ToString()
        
            return LastName + ", " + FirstName;
        

    

它也有自己的自己的视图模型,具有DisplayDurationSinceLastScan 之类的属性,但我认为这里不相关,如果您认为相关,请告诉我。

因此,使用此代码,我得到了我的页面,但列表中似乎没有项目,如果我调试,患者充满了项目,所以它根本不是空的,但我猜绑定出了点问题,但没有报错。

Here is a picture of what I get: the listview is shown (I added a blue background so I would know if the listview was visible or not), but there are no items in there. Still Patients is filled when I debug the app.

有人看到我犯的错误吗?

【问题讨论】:

【参考方案1】:

从可维护性的角度来看,我发现您的代码存在一些问题。尝试将所有代码保留在视图模型中,而不是同时保留视图模型和代码。理想情况下,您的代码不包含任何内容,如果有的话,它与视觉事物完全相关。

无论如何,关于你的问题:你每次都在创建一个新的ObservableCollection。这打破了绑定。只需将新的ObservableCollection 保留在顶部,然后当新数据进入时,清除它并重新填充它。像这样:

public void GetAllPatients()

    IsFetchingData = true;
    try
    
        var resultPatients =         JsonConvert.DeserializeObject<ObservableCollection<PatientViewModel>>(testJson, jsonSerializerSettings);

        Patients.Clear(); 

        foreach (var patient in resultPatients)
            Patients.Add(patient);
    
    catch(Exception e)
    
        Console.WriteLine("*****ERROR kon API niet ophalen");
        Console.WriteLine(e.Message);
    
    finally
    
        IsFetchingData = false;
    

您的数据现在应该会显示出来。

【讨论】:

谢谢,这成功了!你对我背后的代码有一个很好的观点,但我试图指出我还没有完成 MVVM 的实现,但显然我不够清楚:) 所以我很清楚我的代码背后需要一些重构,无论如何谢谢指出来! 现在我知道为什么我做了新的 ObservableCollection:如果我使用 linq 然后填充列表视图并将其转换为 observablecollection 我得到“System.InvalidExcpetion:指定的转换无效”。这就是我放置 new ObservableCollection 的原因,因为它没有给出任何错误。知道如何解决这个问题吗? 我并不是想变得聪明,实际上只是指出可以改进一些事情以使您走上正轨,但很高兴听到您在这方面!让我们将您的下一个问题离线。您可以直接通过 gerald@verslu.is 与我联系吗?我们也可以说荷兰语;-)

以上是关于Xamarin.forms MVVM。列表视图仍然为空的主要内容,如果未能解决你的问题,请参考以下文章

在 Xamarin.Forms 项目中实现 MVVM

Xamarin.forms 中的响应式网格

Xamarin.Forms MVVM TapGestureRecognizer 到 ListView 的 ViewCell 中的标签(在部分文件中)

Xamarin Forms Bind Array 元素在 listView 内

Xamarin Forms 如何制作可拖动的列表视图

Xamarin.Forms:获取列表视图的所有单元格/项目