gpt4 book ai didi

c# - 为什么 ObservableCollection 更新 Android 上的 UI 而不是 iOS?[待定]

转载 作者:行者123 更新时间:2023-11-29 05:38:22 27 4
gpt4 key购买 nike

我在 Xamarin 表单上有一个适用于 Android 和 iOS 的跨平台应用程序。

在某些 View 中,我使用 ObservableCollection 作为 ListView 的源。

在 ListView 中,有一些按钮可供用户交互和更改 UI。

在 Android 上一切正常,但当我在 iOS 上测试时,只有单击 1 次后才会执行更改。

我使用 MVVM 架构来满足我的需求,它在 Android 上运行得很好。唯一的问题是 iPhone。

C# 代码:

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ConvidarAmigosEmail : ContentView
{
public ConvidarAmigosEmail ()
{
BindingContext = new ConvidarAmigosEmailViewModel();
InitializeComponent ();
}

private void ListaEmail_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null) return;
listaEmail.SelectedItem = null;
}

private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{

}
}

public class ConvidarAmigosEmailViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

private ObservableCollection<Contacto> _contactosComEmail;
public ObservableCollection<Contacto> ContactosComEmail { get => _contactosComEmail; set { _contactosComEmail = value; OnPropertyChanged(nameof(ContactosComEmail)); } }

public ICommand SeleccionarContacto
{
get => new Command<Contacto>((contacto) =>
{
if (!contacto.Seleccionado)
{
contacto.Seleccionado = !contacto.Seleccionado;
contacto.Opcao = AppResource.Seleccionado;
ContactosSeleccionadosEmail.Add(contacto);
}
else
{
contacto.Seleccionado = !contacto.Seleccionado;
contacto.Opcao = AppResource.Select;
ContactosSeleccionadosEmail.Remove(contacto);
}
});
}

public ICommand SeleccionarTodos
{
get => new Command(() =>
{
if (ContactosComEmail.Count != ContactosSeleccionadosEmail.Count)
{
ContactosSeleccionadosEmail.Clear();
foreach (var obj in ContactosComEmail)
{
obj.Seleccionado = true;
obj.Opcao = AppResource.Seleccionado;
ContactosSeleccionadosEmail.Add(obj);
}
}
else
{
ContactosSeleccionadosEmail.Clear();
foreach (var obj in ContactosComEmail)
{
obj.Seleccionado = false;
obj.Opcao = AppResource.Select;
}
}
});
}

public List<Contacto> ContactosSeleccionadosEmail { get; set; } = new List<Contacto>();

private string _textoSelectTodos = AppResource.SelTodos;
public string TextoSelectTodos
{
get
{

if (ContactosSeleccionadosEmail.Count == ContactosComEmail.Count)
{
_textoSelectTodos = AppResource.Anull;
OnPropertyChanged(nameof(TextoSelectTodos));
return _textoSelectTodos;
}
_textoSelectTodos = AppResource.SelTodos;
OnPropertyChanged(nameof(TextoSelectTodos));
return _textoSelectTodos;
}
}

private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged == null)
return;

PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

public ConvidarAmigosEmailViewModel()
{
ContactosComEmail = new ObservableCollection<Contacto>();
ObterContactos();
}

#region ObterContactos
/*
Params Entrada => nenhum
Params Saída => nenhum
Lógica => Passo 1 : Acede a lista de contactos do telefone e extrai os dados;
Passo 2 : Coloca os contactos com email na variável ContactosE; os que não têm email em ContactosT
Passo 3 : ContentLoader para aceder ao caminho real do ficheiro de imagem (foto) do contacto;
Passo 4 : Adiciona os contactos com Email a uma lista da classe "Contacto", Contactos#. Os sem email para ContactosT
Plugins : Obter permissoes => https://www.nuget.org/packages/plugin.permissions/;
Aceder aos contactos =>
*/
public async void ObterContactos()
{
//verifica se aplicacao tem permissao pra aceder a lista de contactos
var statusPermissao = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Contacts);

//requisitar permissao
if (statusPermissao == PermissionStatus.Unknown)
{
var resposta = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Contacts);
statusPermissao = resposta[Permission.Contacts];
}

if (statusPermissao == PermissionStatus.Denied)
{
var op = await App.Current?.MainPage?.DisplayAlert(AppResource.contactosNegados, AppResource.SemFuncionalidade, AppResource.Definicoes, AppResource.MaisTarde);

if (op == true)
{
CrossPermissions.Current.OpenAppSettings();
}

else
{
await App.Current?.MainPage?.Navigation?.PopAsync();
}
}

if (statusPermissao == PermissionStatus.Granted)
{
var contactos = await Plugin.ContactService.CrossContactService.Current.GetContactListAsync();
//contactos com email
var contactosE = contactos.Where(x => x.Email != null).OrderBy(x => x.Name).ToList();

//imagem inicial de cada contacto, caso esta não tenha imagem de perfil.
var aux = ImageSource.FromResource("KiaiDay.Images.user.png");
foreach (var c in contactosE)
{
aux = ImageSource.FromResource("KiaiDay.Images.user.png");
if (c.PhotoUri != null)
{
//caso tenho imagem de perfil, aceder ao caminho real no ficheiro e extrair a imagem
var contentLoader = DependencyService.Get<IContentLoader>();
var uri = new Uri(c.PhotoUri);
aux = contentLoader.LoadFromContentUri(uri);
}

ContactosComEmail.Add(
new Contacto()
{
Email = c.Email,
Foto = aux,
Numero = c.Number,
Nome = c.Name,
Opcao = AppResource.Select
});
}
}
else
{
//await App.Current?.MainPage?.DisplayAlert(AppResource.contactosNegados, AppResource.SemFuncionalidade, AppResource.ok);
//App.Current?.MainPage?.Navigation?.PopAsync();
}
}
#endregion
}

xaml 代码:

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="KiaiDay.Views.PosLogin.ConvidarAmigosEmail" x:Name="pagina"
xmlns:FFIL="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
xmlns:FFT="clr-namespace:FFImageLoading.Transformations;assembly=FFImageLoading.Transformations">
<ContentView.Content>
<Grid BackgroundColor="White" RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="7*"/>
</Grid.RowDefinitions>

<Grid ColumnSpacing="0" Grid.Row="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Frame Grid.Row="0" Grid.Column="2" Padding="8" BackgroundColor="#f2f2f2" Margin="-25,0,0,0"
HorizontalOptions="CenterAndExpand" VerticalOptions="Center" BorderColor="LightGray" HasShadow="False">
<Frame.CornerRadius>
<OnPlatform Android="80" iOS="10"/>
</Frame.CornerRadius>
<Label Grid.ColumnSpan="2" Text="{Binding TextoSelectTodos}" FontFamily="{StaticResource RegularFont}" TextColor="{Binding CorSelectTodos}" FontSize="10" VerticalOptions="FillAndExpand" HorizontalTextAlignment="Center" VerticalTextAlignment="Center"/>
<Frame.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Command="{Binding SeleccionarTodos}"/>
</Frame.GestureRecognizers>
</Frame>
</Grid>


<ListView SeparatorColor="LightGray" ItemsSource="{Binding ContactosComEmail}" HasUnevenRows="True" x:Name="listaEmail"
Margin="30,0,30,0" ItemSelected="ListaEmail_ItemSelected" IsGroupingEnabled="False" Grid.Row="1" CachingStrategy="RetainElement">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid ColumnSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="3"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="3"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<FFIL:CachedImage Grid.Row="1" Grid.Column="0" Grid.RowSpan="2"
Source="{Binding Foto}" DownsampleToViewSize="True" BitmapOptimizations="False"
Aspect="AspectFit" RetryCount="0" RetryDelay="250" HeightRequest="50"
LoadingPriority="Highest" HorizontalOptions="Center" VerticalOptions="Center"
FadeAnimationForCachedImages="False" WidthRequest="50">
<FFIL:CachedImage.Transformations>
<FFT:CircleTransformation/>
</FFIL:CachedImage.Transformations>
</FFIL:CachedImage>
<Label Grid.Row="1" Grid.Column="1" Text="{Binding Nome}" FontFamily="{StaticResource RegularFont}" TextColor="#3c3c3b" LineBreakMode="TailTruncation"/>
<Label Grid.Row="2" Grid.Column="1" Text="{Binding Email}" FontFamily="{StaticResource RegularFont}" TextColor="#3c3c3b" LineBreakMode="TailTruncation"/>
<Frame Grid.Row="1" Grid.Column="2" Padding="8" BackgroundColor="#f2f2f2" Grid.RowSpan="2"
HorizontalOptions="CenterAndExpand" VerticalOptions="Center" BorderColor="LightGray" HasShadow="False">
<Frame.CornerRadius>
<OnPlatform Android="80" iOS="10"/>
</Frame.CornerRadius>
<Grid HorizontalOptions="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="6*"/>
</Grid.ColumnDefinitions>
<FFIL:CachedImage Source="{Binding Icone}" HeightRequest="8" WidthRequest="8" BackgroundColor="Transparent" Grid.Column="0"
VerticalOptions="Center" LoadingPriority="Highest" RetryCount="0" RetryDelay="250" DownsampleToViewSize="True" BitmapOptimizations="False"/>
<Label Text="{Binding Opcao}" FontFamily="{StaticResource RegularFont}" FontSize="8" TextColor="{Binding Cor}" Grid.Column="1" VerticalOptions="Center"/>
</Grid>


<Frame.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Command="{Binding Source={x:Reference pagina},Path=BindingContext.SeleccionarContacto}" CommandParameter="{Binding .}" Tapped="TapGestureRecognizer_Tapped"/>
</Frame.GestureRecognizers>
</Frame>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</ContentView.Content>
</ContentView>

我希望 ObservableCollection 能够更新 iOS 上的 UI,而无需单击。

编辑:使用的插件 => https://github.com/jamesmontemagno/PermissionsPlugin ; https://github.com/jamesmontemagno/ContactsPlugin ;

模型定义

 public class Contacto : INotifyPropertyChanged, IEntity
{

public event PropertyChangedEventHandler PropertyChanged;

[PrimaryKey, AutoIncrement]
public int Id { get; set; }

public string Nome { get; set; }

public string Email { get; set; }

public string Numero { get; set; }


[Ignore]
public ImageSource Foto { get; set; }

private ImageSource _icone = ImageSource.FromFile("mais.png");
[Ignore] public ImageSource Icone
{
get
{
if (Seleccionado)
{
_icone = ImageSource.FromFile("certo.png");
OnPropertyChanged(nameof(Icone));
return _icone;
}
_icone = ImageSource.FromFile("mais.png");
OnPropertyChanged(nameof(Icone));
return _icone;
}
set
{
_icone = value;
OnPropertyChanged(nameof(Icone));
}
}

private string _opcao;
[Ignore]
public string Opcao
{
get
{
return _opcao;
}
set
{
_opcao = value;
OnPropertyChanged(nameof(Opcao));
}
}


private bool _seleccionado = false;
public bool Seleccionado
{
get
{
return _seleccionado;
}
set
{
_seleccionado = value;
OnPropertyChanged(nameof(Seleccionado));
}
}


private Color _cor = Color.FromHex("#3c3c3b");
[Ignore]
public Color Cor
{
get
{
if (Seleccionado)
{
_cor = Color.FromHex("#4297d3");
OnPropertyChanged(nameof(Cor));
return _cor;
}
_cor = Color.FromHex("#3c3c3b");
OnPropertyChanged(nameof(Cor));
return _cor;
}
set
{
_cor = value;
OnPropertyChanged(nameof(Cor));
}
}

#region INotifyPropertyChanged Implementation
void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged == null)
return;

PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion

}
}

编辑2:更改 View 模型的构造函数后, View 正在更新,但我无法做任何其他事情。好像被屏蔽了。

        public ConvidarAmigosEmailViewModel()
{
ContactosComEmail = new ObservableCollection<Contacto>();
Task.Run(async () => { await ObterContactos(); });
}

EDIT3:在花了很多时间试图弄清楚发生了什么之后,我得出的结论是问题出在这部分代码上:

                                <Frame Grid.Row="1" Grid.Column="2" Padding="8" BackgroundColor="#f2f2f2" Grid.RowSpan="2" HorizontalOptions="CenterAndExpand" VerticalOptions="Center" HasShadow="False">
<Frame.CornerRadius>
<OnPlatform Android="80" iOS="10"/>
</Frame.CornerRadius>
<Grid HorizontalOptions="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="6*"/>
</Grid.ColumnDefinitions>
<FFIL:CachedImage Source="{Binding Icone}" HeightRequest="8" WidthRequest="8" BackgroundColor="Transparent" Grid.Column="0"
DownsampleToViewSize="True" BitmapOptimizations="False" Aspect="AspectFit" RetryCount="0" RetryDelay="250"
LoadingPriority="Highest" HorizontalOptions="Center" VerticalOptions="Center" FadeAnimationForCachedImages="False"/>
<Label Text="{Binding Opcao}" FontFamily="{StaticResource RegularFont}" FontSize="8" TextColor="{Binding Cor}" Grid.Column="1" VerticalOptions="Center"/>
</Grid>


<Frame.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Command="{Binding Source={x:Reference pagina},Path=BindingContext.SeleccionarContacto}" CommandParameter="{Binding .}"/>
</Frame.GestureRecognizers>
</Frame>

我不知道为什么会发生这种情况...

最佳答案

我认为这已经足够了,没有调试器和源代码就很困难。

ConvidarAmigosEmail.xaml

  [XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ConvidarAmigosEmail : ContentView
{
public ConvidarAmigosEmailViewModel ViewModel { get; set; }
public ConvidarAmigosEmail ()
{
ViewModel = new ConvidarAmigosEmailViewModel();
InitializeComponent ();
BindingContext = new ConvidarAmigosEmailViewModel();
}

public async override OnAppearing()
{
// will be good that you show loading icon while processing data
await ViewModel.LoadData();
}
private void ListaEmail_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null) return;
listaEmail.SelectedItem = null;
}

private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{

}
}

View 模型创建

    public ConvidarAmigosEmailViewModel()
{
ContactosComEmail = new ObservableCollection<Contacto>();

}

public async Task LoadData()
{
await ObterContactos();
}

ObterContactos 内部

      //imagem inicial de cada contacto, caso esta não tenha imagem de perfil.
var aux = ImageSource.FromResource("KiaiDay.Images.user.png");
var ListContactos = new List<Contacto>();
foreach (var c in contactosE)
{
aux = ImageSource.FromResource("KiaiDay.Images.user.png");
if (c.PhotoUri != null)
{
//caso tenho imagem de perfil, aceder ao caminho real no ficheiro e extrair a imagem
var contentLoader = DependencyService.Get<IContentLoader>();
var uri = new Uri(c.PhotoUri);
aux = contentLoader.LoadFromContentUri(uri);
}

// Add method inside foreach generate too many innecesary property changed
// notifications
ListContactos.Add(
new Contacto()
{
Email = c.Email,
Foto = aux,
Numero = c.Number,
Nome = c.Name,
Opcao = AppResource.Select
});
}

ObterContactos = new ObservableCollection<Contacto>(ListContactos);
}
else
...

关于c# - 为什么 ObservableCollection 更新 Android 上的 UI 而不是 iOS?[待定],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56804410/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com