Почему этот ListView не связан с элементами ObservableCollection? - PullRequest
0 голосов
/ 20 января 2020

Я пытаюсь связать ListView с наблюдаемыми данными сбора, но он все еще пуст. У меня есть некоторые точки разрыва, и я вижу, что ListaProfissionais (наблюдаемая коллекция) заполнена правильно. Ниже вы можете увидеть мои .cs и .xaml код (часть, которая имеет значение). Кто-нибудь видит, что здесь не так?


using System.ComponentModel;

public class Profissionais : INotifyPropertyChanged
{
    private string id;
    public string Id
    {
        get { return this.id; }
        set
        {
            if (this.id != value)
            {
                this.id = value;
                this.NotifyPropertyChanged("Id");
            }
        }
    }

    private string categoria;
    public string Categoria
    {
        get { return this.categoria; }
        set
        {
            if (this.categoria != value)
            {
                this.categoria = value;
                this.NotifyPropertyChanged("Categoria");
            }
        }
    }

    private string titulo;
    public string Titulo
    {
        get { return this.titulo; }
        set
        {
            if (this.titulo != value)
            {
                this.titulo = value;
                this.NotifyPropertyChanged("Titulo");
            }
        }
    }

    private string fotoperfil;
    public string FotoPerfil
    {
        get { return this.fotoperfil; }
        set
        {
            if (this.fotoperfil != value)
            {
                this.fotoperfil = value;
                this.NotifyPropertyChanged("FotoPerfil");
            }
        }
    }

    private string endereco;
    public string Endereco
    {
        get { return this.endereco; }
        set
        {
            if (this.endereco != value)
            {
                this.endereco = value;
                this.NotifyPropertyChanged("Endereco");
            }
        }
    }

    private string distancia;
    public string Distancia
    {
        get { return this.distancia; }
        set
        {
            if (this.distancia != value)
            {
                this.distancia = value;
                this.NotifyPropertyChanged("Distancia");
            }
        }
    }

    private string sexo;
    public string Sexo
    {
        get { return this.sexo; }
        set
        {
            if (this.sexo != value)
            {
                this.sexo = value;
                this.NotifyPropertyChanged("Sexo");
            }
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }

}



public static ObservableCollection<Profissionais> ListaProfissionais = new ObservableCollection<Profissionais>();


try
{
   using (WebClient client = new WebClient())
   {
      Uri uri = new Uri("xxxx.xxxxx.php");
      byte[] retorno = await client.UploadValuesTaskAsync(uri, DataSend);
      string resultado = System.Text.Encoding.UTF8.GetString(retorno);
      ListaProfissionais = JsonConvert.DeserializeObject<ObservableCollection<Profissionais>>(resultado);

   }
}
catch
{
  throw;
}
finally
{
  ListViewProfissionais.ItemsSource = ListaProfissionais; 
  // crashes here but I can see that ItemsSource has the 4 elements as expected
}

Мой XAML:


<ListView x:Name="ListViewProfissionais" x:FieldModifier="public static" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" VerticalScrollBarVisibility="Never" HorizontalScrollBarVisibility="Never" BackgroundColor="Transparent" SeparatorColor="Transparent">
      <ListView.ItemTemplate>
         <DataTemplate>
            <Frame HasShadow="True" CornerRadius="5" HeightRequest="215" Margin="8" Padding="4" BackgroundColor="White">
               <Grid>
                 <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"></ColumnDefinition>
                 </Grid.ColumnDefinitions>

                 <Grid.RowDefinitions>
                    <RowDefinition Height="15"></RowDefinition>
                    <RowDefinition Height="25"></RowDefinition>
                    <RowDefinition Height="105"></RowDefinition>
                    <RowDefinition Height="25"></RowDefinition>
                    <RowDefinition Height="25"></RowDefinition>
                 </Grid.RowDefinitions>

                 <Label Text="{Binding Categoria}" TextColor="#8e8e8e" FontSize="10" Grid.Column="0" Grid.Row="0" VerticalOptions="StartAndExpand" HorizontalOptions="StartAndExpand" Margin="2,0,0,0"></Label>
                 <Label Text="{Binding Titulo}" FontAttributes="Bold" TextColor="#337760" FontSize="14" Grid.Column="0" Grid.Row="1" VerticalOptions="StartAndExpand" HorizontalOptions="StartAndExpand" Margin="2,0,0,0"></Label>

                <Frame Grid.Column="0" Grid.Row="2" BackgroundColor="Transparent" CornerRadius="4" Padding="0" Margin="0">
                <Image Source="{Binding FotoPerfil}" HorizontalOptions="FillAndExpand" Aspect="AspectFill" VerticalOptions="FillAndExpand" />
                 </Frame>

                 <Label Text="{Binding Endereco}" TextColor="#8e8e8e" FontSize="10" Grid.Column="0" Grid.Row="3" VerticalOptions="EndAndExpand" HorizontalOptions="StartAndExpand"></Label>
                  <Label Text="&#xf3c5;" Grid.Column="0" Grid.Row="4" FontSize="10" HorizontalOptions="StartAndExpand" TextColor="#ff9000" Padding="0,6,0,0">
                   <Label.FontFamily>
                     <OnPlatform x:TypeArguments="x:String" Android="Font-Awesome-Free-Solid.otf#FontAwesome5Free-Solid" iOS="FontAwesome5Free-Solid" />
                   </Label.FontFamily>
                  </Label>
                  <Label Text="{Binding Distancia}" TextColor="#ff9000" FontSize="10" Grid.Column="0" Grid.Row="4" VerticalOptions="Center" HorizontalOptions="StartAndExpand" Margin="10,0,0,0"></Label>
               </Grid>
            </Frame>
         </DataTemplate>
       </ListView.ItemTemplate>
  </ListView>

Сбой при появлении сообщения «System.InvalidCastException: указанное приведение недопустимо.». Смотрите ниже:

System.InvalidCastException: Specified cast is not valid.
  at at (wrapper castclass) System.Object.__castclass_with_cache(object,intptr,intptr)
  at Xamarin.Forms.Internals.TemplatedItemsList`2[TView,TItem].ActivateContent (System.Int32 index, System.Object item) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\TemplatedItemsList.cs:534
  at Xamarin.Forms.Internals.TemplatedItemsList`2[TView,TItem].CreateContent (System.Int32 index, System.Object item, System.Boolean insert) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\TemplatedItemsList.cs:543
  at Xamarin.Forms.Internals.TemplatedItemsList`2[TView,TItem].GetOrCreateContent (System.Int32 index, System.Object item) [0x00023] in D:\a\1\s\Xamarin.Forms.Core\TemplatedItemsList.cs:602
  at Xamarin.Forms.Internals.TemplatedItemsList`2[TView,TItem].get_Item (System.Int32 index) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\TemplatedItemsList.cs:337
  at Xamarin.Forms.Platform.Android.ListViewAdapter.GetCellsFromPosition (System.Int32 position, System.Int32 take) [0x0003b] in D:\a\1\s\Xamarin.Forms.Platform.Android\Renderers\ListViewAdapter.cs:539
  at Xamarin.Forms.Platform.Android.ListViewAdapter.GetCellForPosition (System.Int32 position) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.Android\Renderers\ListViewAdapter.cs:454
  at Xamarin.Forms.Platform.Android.ListViewAdapter.GetView (System.Int32 position, Android.Views.View convertView, Android.Views.ViewGroup parent) [0x0006d] in D:\a\1\s\Xamarin.Forms.Platform.Android\Renderers\ListViewAdapter.cs:225
  at Android.Widget.BaseAdapter.n_GetView_ILandroid_view_View_Landroid_view_ViewGroup_ (System.IntPtr jnienv, System.IntPtr native__this, System.Int32 position, System.IntPtr native_convertView, System.IntPtr native_parent) [0x0001a] in <11f101b564894ca7af6c482ddc51c698>:0
  at at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.74(intptr,intptr,int,intptr,intptr)

Ответы [ 3 ]

1 голос
/ 21 января 2020

ОБНОВЛЕНИЕ - 25 ЯНВАРЯ 2020

У меня было время, чтобы еще раз проверить ваш код и выяснить, что вы помещали шаблон непосредственно в DataTemplate (что в ListView не является возможный). Вы уже сообщаете, что сами нашли это (Хорошая работа!).

Я оставляю здесь исправление, которое собирался использовать для Вас, указывая на несколько вещей:

XAML

<?xml version="1.0" encoding="utf-8"?>
<ContentPage
    x:Name="myPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:d="http://xamarin.com/schemas/2014/forms/design"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Class="Playground.MainPage">
    <ListView
        ItemsSource="{Binding ListaProfissionais, Source={x:Reference myPage}}"
        x:Name="ListViewProfissionais" HorizontalOptions="FillAndExpand"
        HasUnevenRows="True"
        VerticalOptions="FillAndExpand"
        VerticalScrollBarVisibility="Never"
        HorizontalScrollBarVisibility="Never"
        BackgroundColor="Transparent"
        SeparatorColor="Transparent">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <Frame HasShadow="True" CornerRadius="5" HeightRequest="215" Margin="8" Padding="4" BackgroundColor="White">
              <Grid>
                <Grid.ColumnDefinitions>
                  <ColumnDefinition Width="*"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                  <RowDefinition Height="15"></RowDefinition>
                  <RowDefinition Height="25"></RowDefinition>
                  <RowDefinition Height="105"></RowDefinition>
                  <RowDefinition Height="25"></RowDefinition>
                  <RowDefinition Height="25"></RowDefinition>
                </Grid.RowDefinitions>
                <Label Text="{Binding Categoria}" TextColor="#8e8e8e" FontSize="10" Grid.Column="0" Grid.Row="0" VerticalOptions="StartAndExpand" HorizontalOptions="StartAndExpand" Margin="2,0,0,0"></Label>
                <Label Text="{Binding Titulo}" FontAttributes="Bold" TextColor="#337760" FontSize="14" Grid.Column="0" Grid.Row="1" VerticalOptions="StartAndExpand" HorizontalOptions="StartAndExpand" Margin="2,0,0,0"></Label>
                <Frame Grid.Column="0" Grid.Row="2" BackgroundColor="Transparent" CornerRadius="4" Padding="0" Margin="0">
                    <Image Source="{Binding FotoPerfil}" HorizontalOptions="FillAndExpand" Aspect="AspectFill" VerticalOptions="FillAndExpand" />
                </Frame>

                <Label Text="{Binding Endereco}" TextColor="#8e8e8e" FontSize="10" Grid.Column="0" Grid.Row="3" VerticalOptions="EndAndExpand" HorizontalOptions="StartAndExpand"></Label>
                <Label Text="&#xf3c5;" Grid.Column="0" Grid.Row="4" FontSize="10" HorizontalOptions="StartAndExpand" TextColor="#ff9000" Padding="0,6,0,0">
                  <Label.FontFamily>
                    <OnPlatform x:TypeArguments="x:String" Android="Font-Awesome-Free-Solid.otf#FontAwesome5Free-Solid" iOS="FontAwesome5Free-Solid" />
                  </Label.FontFamily>
                </Label>
                <Label Text="{Binding Distancia}" TextColor="#ff9000" FontSize="10" Grid.Column="0" Grid.Row="4" VerticalOptions="Center" HorizontalOptions="StartAndExpand" Margin="10,0,0,0"></Label>
               </Grid>
            </Frame>
          </ViewCell>
         </DataTemplate>
       </ListView.ItemTemplate>
  </ListView>
</ContentPage>

Код позади:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace Playground
{
    // Learn more about making custom code visible in the Xamarin.Forms previewer
    // by visiting https://aka.ms/xamarinforms-previewer
    [DesignTimeVisible(false)]
    public partial class MainPage : ContentPage
    {
        public class Profissionais
        {
            public string Id { get; set; }

            public string Categoria { get; set; }

            public string Titulo { get; set; }

            public string FotoPerfil { get; set; }

            public string Endereco { get; set; }

            public string Distancia { get; set; }

            public string Sexo { get; set; }

        }

        private ObservableCollection<Profissionais> _listaProfissionais;
        public ObservableCollection<Profissionais> ListaProfissionais
        {
            get => _listaProfissionais;
            set
            {
                _listaProfissionais = value;
                OnPropertyChanged(nameof(ListaProfissionais));
            }
        }

        public MainPage()
        {
            InitializeComponent();
            ListaProfissionais = new ObservableCollection<Profissionais>();
        }

        private async Task Call()
        {
            // Simulating a call to the "API" and add a new element each 2 seconds
            for (int i = 0; i < 10; i++)
            {
                ListaProfissionais.Add(new Profissionais { Titulo = $"Professional {i}" });
                await Task.Delay(2000);
            }

        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            // Call the "API" when everything is ready
            Task.Factory.StartNew(Call);
        }
    }
}

Здесь, как вы можете видеть, Class Professionais не требуется наследовать от INotifyPropertyChanged. Единственное свойство, которое нужно уведомить в Binding engine - это ваша коллекция. ContentPage уже имеет метод OnPropertyChanged, который вы можете использовать. После этого ваш ListView будет прослушивать не только изменение свойства, но и саму коллекцию каждый раз, когда вы добавляете новый элемент.

Надеюсь, это поможет!

OLD

Предполагается, что вы пытаетесь связать свойство ListaProfissionais из кода:

Подход 1 (не очень хорошая практика):

Вы необходимо добавить ListaProfissionais к свойству BindingContext класса. Вы можете подойти к этому следующим образом:

... assuming you already called your API ...
ListaProfissionais = JsonConvert.DeserializeObject<ObservableCollection<Profissionais>>(resultado);
BindingContext = ListaProfissionais;

В вашем XAML вместо ItemsSource="{Binding ListaProfissionais}" используйте ItemSource="{Binding BindingContext}"

Подход 2 (лучший подход):

Установите имя на своей странице XAML для класса (Name = "listPage"). В вашем ListView вы можете сделать что-то вроде этого:

ItemsSource="{Binding ListaProfissionais, Source='{x:Reference listPage}'}"

Примечание: я проверю это позже.

Добавьте интерфейс INotifyPropertyChanged в файл cs и внедрите его метод.

Измените ListaProfissionais на свойство, подобное этому:

private ObservableCollection<Profissionais> _listaProfissionais;

public ObservableCollection<Profissionais> ListaProfissionais
{
    get => _listaProfissionais;
    set 
    {
        _listaProfissionais = value;
        // This should be the method implemented by INotifyPropertyChanged.
        OnPropertyChanged(nameof(ListaProfissionais);
    }
}

Примечания: список не будет уведомлять ListView. если вы не уведомите механизм привязки, что свойство изменилось. При этом мы проверяем, что связывающий контекст ListView прослушивает изменения свойств из ListProfessionais.

Надеюсь, это поможет.

0 голосов
/ 21 января 2020

Нашли root проблемы. Это было в xaml, я не знаю почему, но тег Grid не может быть непосредственно внутри DataTemplate, он должен быть внутри тега ViewCell, я только добавил ViewCell, и теперь он работает хорошо.

0 голосов
/ 20 января 2020

Я думаю, вы должны уведомить об изменении свойства, например, реализовать интерфейс INotifyPropertyChanged для вашего класса. Далее я не вижу, установлен ли DataContext. Хороший простой пример здесь https://www.wpf-tutorial.com/data-binding/responding-to-changes/

...