MVVM not work properly

MarcoSalvatoriMarcoSalvatori USMember ✭✭✭

I have a XAML form linked to an MVVM with the binding. At the first call the form is rarely populated, from the second onwards, it works sporadically. No errors are ever generated.
This is the code:

public class IspezioneFile
        {
            public string NomeFile { get; set; } = string.Empty;
            public int NumeroIspezioni { get; set; } = 0;
            public int NumeroAnomalie { get; set; } = 0;
            public int NumeroFoto { get; set; } = 0;
            public bool ErrorFile { get; set; } = false;
            public bool CanDelete { get; set; } = false;

            ICommand UploadCloud;
            public ICommand UploadCloudCommand =>
                    UploadCloud ??
                    (UploadCloud = new Command(async () => await ExecuteUploadCloudCommand()));

            private async Task ExecuteUploadCloudCommand()
            {
                Application.Current?.MainPage?.DisplayAlert("Upload", "zzz", "Ok", "no");
            }
        }

        public class IspezioneFileRoot
        {
            public List<IspezioneFile> Items { get; set; }

        }
        public class IspezioneFilesVM : BaseViewModel
        {
            IspezioneFileRoot listFilesIsp;
            public IspezioneFileRoot ListFilesIsp
            {
                get { return listFilesIsp; }
                set { listFilesIsp = value; OnPropertyChanged(); }
            }

            ICommand getFiles;
            public ICommand GetFilesCommand =>
                    getFiles ??
                    (getFiles = new Command(async () => await ExecuteGetFilesCommand()));

            private async Task ExecuteGetFilesCommand()
            {
                if (IsBusy)
                    return;

                IsBusy = true;
                try
                {
                    VariabiliGlobali VarGlobal = VariabiliGlobali.Instance();

                    //var list = System.IO.Directory.GetFiles(VarGlobal.pathDocuments, "*.json");
                    //if (list.Length > 0)
                    //{
                    //    for (int i = 0; i < list.Length; i++)
                    //    {
                    //        System.IO.File.Delete(list[i]);
                    //    }
                    //}

                    PCLStorage.IFolder folder = await PCLStorage.FileSystem.Current.GetFolderFromPathAsync(VarGlobal.pathDocuments);
                    var ListFiles = await folder.GetFilesAsync();//istruzione per trovare tutti i dati
                    ListFilesIsp = new BmsClassi.IspezioneFileRoot();
                    ListFilesIsp.Items=new  List<BmsClassi.IspezioneFile>();

                    foreach (var item in ListFiles)
                    {
                        BmsClassi.IspezioneFile InfoFile = new BmsClassi.IspezioneFile();

                        await ExecuteGetFilesTask(InfoFile, item, folder);
                        if (VarGlobal.TipoUser=="Amministratore") { InfoFile.CanDelete = true; };
                        ListFilesIsp.Items.Add(InfoFile);
                    }
                }
                catch (Exception ex)
                {
                    //Temp = "Unable to get Weather";
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    IsBusy = false;
                }
                finally
                {
                    IsBusy = false;
                }
            }

            private async Task<BmsClassi.IspezioneFile> ExecuteGetFilesTask(BmsClassi.IspezioneFile InfoFile, PCLStorage.IFile file, PCLStorage.IFolder folder)
            {
                var jsonWork = await UtilsPCLstorage.ReadAllTextAsync(file.Name, folder);
                InfoFile.NomeFile = file.Name;
                try
                {
                    List<BmsClassi.BmsIspezioni> tempListIsp = JsonConvert.DeserializeObject<List<BmsClassi.BmsIspezioni>>(jsonWork);
                    InfoFile.NumeroIspezioni = tempListIsp.Count();
                    if (InfoFile.NumeroIspezioni > 0)
                    {
                        InfoFile.NumeroAnomalie = (from p in tempListIsp select p.AnomalieRilevateVM.AnomalieItemsList.Count).Sum();//http://www.csharp-examples.net/linq-sum/
                        InfoFile.NumeroFoto = (from p in tempListIsp select p.SegnalazioneVM.ListPhoto.Count).Sum();
                    }
                }
                catch (Exception ex)
                {
                    InfoFile.ErrorFile = true;
                }

                return InfoFile;
            }
        }

<ContentPage.Content>
        <StackLayout>
            <Grid BackgroundColor="LightGray" Padding="5">
                <Grid.RowDefinitions>
                    <RowDefinition Height="60"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.26*"/>
                    <ColumnDefinition Width="0.18*"/>
                    <ColumnDefinition Width="0.18*"/>
                    <ColumnDefinition Width="0.18*"/>
                    <ColumnDefinition Width="0.10*"/>
                    <ColumnDefinition Width="0.10*"/>
                </Grid.ColumnDefinitions>
                <Label Grid.Column="0" Text="Nome File" Style="{StaticResource LabelHeader}" HorizontalOptions="Start" />
                <Label Grid.Column="1" Text="N° Ispezioni" Style="{StaticResource LabelHeader}" TextColor="Red"/>
                <Label Grid.Column="2" Text="N° Anomalie" Style="{StaticResource LabelHeader}" TextColor="Blue"/>
                <Label Grid.Column="3" Text="N° Foto" Style="{StaticResource LabelHeader}" TextColor="Black"/>
            </Grid>
            <ListView ItemsSource="{Binding ListFilesIsp.Items}"
              HasUnevenRows="True"
              CachingStrategy="RecycleElement"
              IsPullToRefreshEnabled="True"
              RefreshCommand="{Binding GetFilesCommand}"
              IsRefreshing="{Binding IsBusy, Mode=OneWay}"
              RowHeight="75"
              x:Name="ListViewJsonFiles">
                <ListView.SeparatorColor>
                    <OnPlatform x:TypeArguments="Color" iOS="Transparent"/>
                </ListView.SeparatorColor>
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid Padding="5">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="0.26*"/>
                                    <ColumnDefinition Width="0.18*"/>
                                    <ColumnDefinition Width="0.18*"/>
                                    <ColumnDefinition Width="0.18*"/>
                                    <ColumnDefinition Width="0.10*"/>
                                    <ColumnDefinition Width="0.10*"/>
                                </Grid.ColumnDefinitions>
                                <Label Grid.Column="0" Text="{Binding NomeFile}" Style="{StaticResource LabelHeader}" FontSize="15" HorizontalOptions="Start" />
                                <Label Grid.Column="1" Grid.ColumnSpan="3" Text="Errore lettura file" IsVisible="{Binding ErrorFile}" Style="{StaticResource LabelContatore}"/>
                                <Label Grid.Column="1" Text="{Binding NumeroIspezioni}" Style="{StaticResource LabelContatore}" TextColor="Red"/>
                                <Label Grid.Column="2" Text="{Binding NumeroAnomalie}" Style="{StaticResource LabelContatore}" TextColor="Blue"/>
                                <Label Grid.Column="3" Text="{Binding NumeroFoto}" Style="{StaticResource LabelContatore}" TextColor="Black"/>
                                <Image Grid.Column="4" Source="UploadToCloud.png" >
                                    <Image.GestureRecognizers>
                                        <TapGestureRecognizer Command="{Binding UploadCloudCommand}" NumberOfTapsRequired="2"/>
                                    </Image.GestureRecognizers>
                                </Image>
                                <Image Grid.Column="5" Source="trash.png" IsVisible="{Binding CanDelete}"/>
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
    </ContentPage.Content>

public DataForm ()
        {
            InitializeComponent ();

            this.BindingContext = IspFilesVM;

            IspFilesVM.GetFilesCommand.Execute(null);

        }

What's the problem?!?

Posts

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    you are using a List instead on an ObservableCollection, and it seems you don't implement INotifyPropertyChanged

  • MarcoSalvatoriMarcoSalvatori USMember ✭✭✭

    I used BaseViewModel, a plugin by James Montemagno that implements INotifyPropertyChanged. I used the list in another context and it didn't show any problems.

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭
    edited May 7

    INotifyPropertyChanged is not INotifyCollectionChanged

    the Property is the List itself... If you don't swap out the entire list then there is no change. A change on an element of the list is not a change of the property... Its a change of the collection.

    Just use ObservableCollection like the rest of the world and the documentation shows. Its not like a List is cheap and and you have to pay money to use an ObservableCollection
    http://redpillxamarin.com/2018/03/12/2018-101-vs2017-new-solution/

  • NMackayNMackay GBInsider, University mod

    https://en.wikipedia.org/wiki/Model–view–viewmodel

    You can't say a pattern doesn't work, maybe something is lost in translation.

  • MarcoSalvatoriMarcoSalvatori USMember ✭✭✭

    @ClintStLaurent said:
    INotifyPropertyChanged is not INotifyCollectionChanged

    the Property is the List itself... If you don't swap out the entire list then there is no change. A change on an element of the list is not a change of the property... Its a change of the collection.

    Just use ObservableCollection like the rest of the world and the documentation shows. Its not like a List is cheap and and you have to pay money to use an ObservableCollection
    http://redpillxamarin.com/2018/03/12/2018-101-vs2017-new-solution/

    I'm trying to replicate a structure like the one built by Montemagno in the Myweather APP.
    https://github.com/jamesmontemagno/MyWeather.Forms
    I have always used the ObservableCollection, but in that example the List is used. In another context it works regularly.
    I have to rectify the initial post, it doesn't work only the first time. Then it always works .... it seems that the binding is not properly initialized ...

  • MarcoSalvatoriMarcoSalvatori USMember ✭✭✭

    to close the thread, I replaced the list with ObservableCollection and everything works fine.
    I also deleted the instructions for 'isbusy', because sometimes the indicator froze.

  • VovaKamishnikovVovaKamishnikov USMember ✭✭✭

    Now MVVM isn't broken, hurray!
    @AlessandroCaliaro @ClintStLaurent @NMackay together save the world one more time

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    @VovaKamishnikov said:
    Now MVVM isn't broken, hurray!
    @AlessandroCaliaro @ClintStLaurent @NMackay together save the world one more time

    Yes, sometimes it happens

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    @MarcoSalvatori said:
    I have to rectify the initial post, it doesn't work only the first time. Then it always works .... it seems that the binding is not properly initialized ...

    public List<IspezioneFile> Items { get; set; }

    Yep. The collection is not initialized on creation. You can't bind to null. I'd suggest a habit of always giving every property an initial value.

    public class whatever : BindableObject
    {
    
    ObservableCollection<IspezioneFile> _Items = new ObservableCollection<IspezioneFile>(); //Collection of 0 elements`
    public Items { get { return _Items;} 
    set
     {
       if (_Items != value) _Items = value;
       OnPropertyChanged()
    }
    
    }
    
  • MarcoSalvatoriMarcoSalvatori USMember ✭✭✭

    Everything ok but, why did Montemagno use the List?

  • VovaKamishnikovVovaKamishnikov USMember ✭✭✭
    edited May 15

    @MarcoSalvatori said:
    Everything ok but, why did Montemagno use the List?

    I think Montemagno doesn't change the content of the List but changes the entire List. Therefore there no need INotifyCollectonChanged interface
    Sometimes that approach works much faster than change the content of List. And it works surprisingly smooth... sometimes.

Sign In or Register to comment.