IsVisible not loading correctly in ListView - c#

I've got a ListView with some items inside, each item have some buttons but depends by his own data.
My xaml:
<ListView
x:Name="ListViewRepartos"
Margin="10"
CachingStrategy="RecycleElement"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame Margin="10" BackgroundColor="{Binding ColorVisita}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label
Grid.Row="0"
Grid.Column="0"
Text="Cliente:" />
<Label
Grid.Row="1"
Grid.Column="0"
Text="Direccion:" />
<Label
Grid.Row="3"
Grid.Column="0"
Text="Importe:" />
<Label
Grid.Row="0"
Grid.Column="1"
LineBreakMode="WordWrap"
Text="{Binding Cliente}" />
<Label
Grid.Row="1"
Grid.RowSpan="2"
Grid.Column="1"
LineBreakMode="CharacterWrap"
Text="{Binding Direccion}" />
<Label
Grid.Row="3"
Grid.Column="1"
LineBreakMode="WordWrap"
Text="{Binding Importe}" />
<StackLayout
Grid.Row="5"
Grid.ColumnSpan="2"
Orientation="Horizontal">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
Grid.Row="0"
Grid.Column="0"
Command="{Binding Entregar}"
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding BotonesVisibles}"
Text="Entregar" />
<Button
Grid.Row="0"
Grid.Column="1"
Command="{Binding Llevame}"
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding BotonesVisibles}"
Text="Llevame" />
<Button
Grid.Row="0"
Grid.Column="0"
Command="{Binding Cobrar}"
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding BotonCobrosVisible}"
Text="Cobros" />
<Button
Grid.Row="0"
Grid.Column="1"
Command="{Binding Modificar}"
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding BotonModificarVisible}"
Text="Modificar" />
</Grid>
</StackLayout>
</Grid>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
.cs loading items for ListView:
var resultado = new ObservableCollection<Modelos.Reparto>(Utils.Campos.Repartos.Select(q => ActivarBotones(q)).Where(q => q != null).ToList());
Utils.UIHandler.RunOnUI(() => {
this.ListViewRepartos.ItemsSource = null;
this.ListViewRepartos.ItemsSource = resultado;
ListViewRepartos.EndRefresh();
});
I load the item and activate the buttons with ActivarBotones:
private Modelos.Reparto ActivarBotones(Modelos.Reparto q)
{
try
{
q.SetBotones(this);
return q;
}
catch (Exception ex)
{
Utils.UIHandler.ErrorDebug("ListaRepartos: Warning", ex.Message, Utils.UIHandler.MessageLevel.Warning);
}
return null;
}
Where SetBotones is in my model:
public bool BotonesVisibles
{
get { return Visitado == EstadoVisita.NoVisitado; }
}
public bool BotonCobrosVisible
{
get {
return Visitado == EstadoVisita.Entregado || Visitado == EstadoVisita.EntregadoMod;
}
}
public bool BotonModificarVisible
{
get
{
return Visitado == EstadoVisita.EntregadoMod;
}
}
public void SetBotones(Controladores.Controlador Host)
{
this.Entregar = new Command(() => {
Host.Unico(async () => {
Utils.UIHandler.NavPush(new Vistas.Entregar(this.DatosCabecera, this.DatosCobro, this));
});
});
this.Llevame = new Command(() => {
Host.Unico(async () => {
Utils.UIHandler.RunOnUI(() => {
....
});
});
this.Cobrar = new Command(() => {
Host.Unico(async () => {
Utils.UIHandler.NavPush(new Vistas.DatosPago(this.DatosCabecera));
});
});
this.Info = new Command(() => {
Host.Unico(async () => {
Utils.UIHandler.NavPush(new Vistas.DatosCliente(this.DatosCliente));
});
});
this.Modificar = new Command(() => {
Host.Unico(async () => {
Utils.UIHandler.NavPush(new Vistas.AlbaranFactura(this.DatosCabecera,this.DatosCliente));
});
});
}
But when i see the View in with real data, sometimes it display correctly, and sometimes not, also if go into item tapped and comes back by back button, it loads correctly fitted the buttons.
This image is an example image:
Any idea what i am doing wrong or why is not displaying correctly always the buttons ?
EDIT:
I've change the projecto to mvvm but still getting white spaces because don't display the correct buttons:
xaml:
<StackLayout
Grid.Row="5"
Grid.ColumnSpan="2"
Orientation="Horizontal">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
Grid.Row="0"
Grid.Column="0"
Command="{Binding Entregar}"
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding BotonesVisibles}"
Text="Entregar" />
<Button
Grid.Row="0"
Grid.Column="1"
Command="{Binding Llevame}"
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding BotonLlevarVisible}"
Text="Llevame" />
<Button
Grid.Row="0"
Grid.Column="0"
Command="{Binding Cobrar}"
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding BotonCobrosVisible}"
Text="Cobros" />
<Button
Grid.Row="0"
Grid.Column="1"
Command="{Binding Modificar}"
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding BotonModificarVisible}"
Text="Modificar" />
</Grid>
</StackLayout>
Model:
public EstadoVisita visitado = EstadoVisita.NoVisitado;
public EstadoVisita Visitado
{
get
{
return visitado;
}
set
{
if(visitado == EstadoVisita.NoVisitado) { botonesvisibles = true; botonllevarvisible = true; }
if(visitado == EstadoVisita.Entregado || visitado == EstadoVisita.EntregadoMod) { botoncobrosvisible = true; botonllevarvisible = false; botonesvisibles = false; }
if(visitado == EstadoVisita.EntregadoMod) { botonmodificarvisible = true; botonllevarvisible = false; botonesvisibles = false; }
}
}
public bool botonesvisibles = true;
public bool BotonesVisibles
{
get { return botonesvisibles; }
set { botonesvisibles = value; }
}
public bool botoncobrosvisible;
public bool BotonCobrosVisible
{
get { return botoncobrosvisible; }
set { botoncobrosvisible = value; }
}
public bool botonmodificarvisible;
public bool BotonModificarVisible
{
get { return botonmodificarvisible; }
set { botonmodificarvisible = value; }
}
public bool botonllevarvisible = true;
public bool BotonLlevarVisible
{
get { return botonllevarvisible; }
set { botonllevarvisible = value; }
}
Any other thing to consider?

Related

Why does the listview display the items incorrectly after I remove them in .NET MAUI?

Firstscreen with all the notes.
After I deleted the first note!
I have recently started programming with .NET MAUI. The elements are correctly removed in the C# list. However, after deleting the remaining elements are only partially displayed. That means that only e.g. the 4th element is displayed. For the other elements only an empty bar is displayed.
My code so far:
XAML:
<VerticalStackLayout>
<ScrollView>
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image
Grid.Column="0"
Source="logo.png"
WidthRequest="150"
HorizontalOptions="Start"
VerticalOptions="Start"/>
<Label
TextColor="Black"
Grid.Column="1"
Text="TODO"
FontSize="35"
HorizontalOptions="Start"
VerticalOptions="Start"
Margin="23"/>
</Grid>
<Grid BackgroundColor="#24D4A3">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView
Grid.ColumnSpan="2"
Grid.RowSpan="2"
RowHeight="100"
x:Name="listview">
<ListView.ItemTemplate>
<DataTemplate >
<ViewCell >
<Grid BackgroundColor="#24D4A3">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Button BackgroundColor="#DEABF5"
Text="{Binding Title}"
Clicked="onNoteSelected"
BorderWidth="2"
TextColor="Black"
FontSize="28"
Margin="20"
CornerRadius="100"
WidthRequest="350"
HeightRequest="70"
HorizontalOptions="Center"
VerticalOptions="Start"/>
<Button
BindingContext="{Binding Id}"
Clicked="ToDoSolved"
BorderWidth="2"
BorderColor="Black"
BackgroundColor="White"
WidthRequest="45"
HeightRequest="45"
CornerRadius="35"
Margin="0,0,260,0"
/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ImageButton
Clicked="Settings"
Source="settings.png"
Grid.Row="0"
Grid.Column="2"
BorderColor="#2b3c3c"
BorderWidth="0"
BackgroundColor="#34A4EB"
CornerRadius="35"
HorizontalOptions="End"
WidthRequest="70"
HeightRequest="70"
Margin="0,10, 10, 0"
VerticalOptions="Start"/>
<ImageButton
Clicked="CreateNote"
Source="add.png"
Grid.Row="1"
Grid.Column="2"
BorderColor="#2b3c3c"
BorderWidth="0"
BackgroundColor="#34A4EB"
CornerRadius="35"
HorizontalOptions="End"
WidthRequest="70"
HeightRequest="70"
Margin="0,0,10,10"
Padding="2,0,0,0"/>
</Grid>
</StackLayout>
</ScrollView>
</VerticalStackLayout>
C#:
public partial class MainPage : ContentPage
{
private ObservableCollection<Note> notes = new ObservableCollection<Note>();
public ObservableCollection<Note> Notes
{
get { return notes; }
set { notes = value; }
}
public MainPage()
{
InitializeComponent();
notes.Add(new Note(1, "My Note1", "I'm ugly"));
notes.Add(new Note(2, "My Note2", "I'm short"));
notes.Add(new Note(3, "My Note3", "I'm smart"));
notes.Add(new Note(4, "My Note4", "I'm smart"));
//notes.Add(new Note(6, "My Note6", "I'm smart"));
//notes.Add(new Note(7, "My Note7", "I'm smart"));
//notes.Add(new Note(8, "My Note8", "I'm smart"));
//notes.Add(new Note(9, "My Note9", "I'm smart"));
this.BindingContext= Notes;
listview.ItemsSource= Notes;
}
private async void CreateNote(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("//CreateNote");
}
private async void Settings(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("//Settings");
}
private void ToDoSolved(object sender, EventArgs e)
{
Button button= (Button) sender ;
var id = (int)button.BindingContext;
var item = Notes.SingleOrDefault(x => x.Id == id);
if (item != null)
{
Notes.Remove(item);
Console.WriteLine(id);
}
}
async void onNoteSelected(object sender, EventArgs e)
{
Button button= (Button) sender ;
var id = (int)button.BindingContext;
//await Shell.Current.GoToAsync("NotePage" + id);
}
}
I would be grateful for any help :)
To delete the item, since you are using ListView, you can delete the via
Button click. However, you need to delete the item from bottom to top in order.
Code-behind:
public partial class MainPage : ContentPage
{
public ObservableCollection<Note> Notes { get; private set; } = new ObservableCollection<Note>();
public MainPage()
{
InitializeComponent();
AddNotes();
BindingContext = this;
}
private void AddNotes()
{
Notes.Add(new Note("0", "My Note1"));
Notes.Add(new Note("1", "My Note2"));
Notes.Add(new Note("2", "My Note3"));
Notes.Add(new Note("3", "My Note4"));
}
private void Button_Clicked(object sender, EventArgs e)
{
var note = (Button)sender;
Note listnote = (from itm in Notes
where itm.Id == note.CommandParameter.ToString()
select itm).FirstOrDefault<Note>();
Notes.Remove(listnote);
}
}
Xaml:
<VerticalStackLayout>
<ScrollView>
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image
Grid.Column="0"
Source="logo.png"
WidthRequest="150"
HorizontalOptions="Start"
VerticalOptions="Start"
/>
<Label
TextColor="Black"
Grid.Column="1"
Text="TODO"
FontSize="35"
HorizontalOptions="Start"
VerticalOptions="Start"
Margin="23"
/>
</Grid>
<Grid BackgroundColor="#24D4A3">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView
Grid.ColumnSpan="2"
Grid.RowSpan="2"
RowHeight="100"
x:Name="listview"
ItemsSource="{Binding Notes}" >
<ListView.ItemTemplate>
<DataTemplate >
<ViewCell>
<Grid BackgroundColor="#24D4A3" >
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Button BackgroundColor="#DEABF5"
Text="{Binding Title}"
BorderWidth="2"
TextColor="Black"
FontSize="28"
Margin="20"
CornerRadius="100"
WidthRequest="350"
HeightRequest="70"
HorizontalOptions="Center"
VerticalOptions="Start"/>
<Button
Text="Delete"
Clicked="Button_Clicked"
CommandParameter="{Binding Id}"
BorderWidth="2"
BorderColor="Black"
BackgroundColor="White"
WidthRequest="45"
HeightRequest="45"
CornerRadius="35"
Margin="0,0,260,0"
/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</StackLayout>
</ScrollView>
</VerticalStackLayout>
Note:
public class Note
{
public string Id { get; set; }
public string Title { get; set; }
public Note(string id, string title)
{
Id = id;
Title = title;
}
}

Why this Xamarin CollectionView doesn't update UI when changing element property?

I have a chat application that have a list of chat members which should change property Lida/BgFrame when the last message is seen. Adding new elements to this list works fine, but changing properties of existing elements do nothing.
See my code below(relevant parts only, I have omitted a lot of irrelevant code for this question):
namespace MasterDetailPageNavigation.XAML
{
public static ObservableCollection<ChatMembers> Lista { get; set; } = new ObservableCollection<ChatMembers>();
public static ReaderWriterLockSlim valuesLock = new ReaderWriterLockSlim();
void ObservableCollectionCallback(IEnumerable collection, object context, Action accessMethod, bool writeAccess)
{
var collectionLock = (ReaderWriterLockSlim)context;
Action enterLock = writeAccess ? new Action(collectionLock.EnterWriteLock) : new Action(collectionLock.EnterReadLock);
Action exitLock = writeAccess ? new Action(collectionLock.ExitWriteLock) : new Action(collectionLock.ExitReadLock);
enterLock();
try { accessMethod(); } finally { exitLock(); }
}
public class ChatMembers : INotifyPropertyChanged // THIS IS THE BINDABLE OBJECT
{
public Color WhiteAlpha = new Color(255, 255, 255, 0.7);
public Color GreenAlpha = new Color(160.0f / 255.0f, 255.0f / 255.0f, 160.0f / 255.0f, 0.2);
private Guid _talk { get; set; }
public Guid talk
{
get { return _talk; }
set
{
_talk = value;
NotifyPropertyChanged("talk");
}
}
private string _Username { get; set; }
public string Username
{
get { return _Username; }
set
{
_Username = value;
this.NotifyPropertyChanged("Username");
}
}
private bool _Lida { get; set; }
public bool Lida
{
get { return _Lida; }
set
{
_Lida = Convert.ToBoolean(value);
FrameBg = !_Lida ? (UserFrom == MainPage.MeuID ? WhiteAlpha : GreenAlpha) : WhiteAlpha;
this.NotifyPropertyChanged("Lida");
}
}
private Color _FrameBg { get; set; }
public Color FrameBg
{
get { return _FrameBg; }
set
{
_FrameBg = value;
this.NotifyPropertyChanged("FrameBg");
}
}
private string _Msg { get; set; }
public string Msg
{
get { return _Msg; }
set
{
_Msg = value;
this.NotifyPropertyChanged("Msg");
}
}
public event PropertyChangedEventHandler PropertyChanged;
void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
// Code that updates property "Lida":
tasks.Add(Task.Run(() =>
{
Color GreenAlpha = new Color(160.0f / 255.0f, 255.0f / 255.0f, 160.0f / 255.0f, 0.2);
bool itemExists = false;
valuesLock.EnterReadLock();
try
{
itemExists = Lista.Any(i => i.talk == guid);
}
finally { valuesLock.ExitReadLock(); }
if (itemExists)
{
ChatMembers item;
int indexof;
valuesLock.EnterReadLock();
try
{
item = Lista.Single(i => i.talk == guid);
indexof = Lista.IndexOf(item);
}
finally { valuesLock.ExitReadLock(); }
_ = Device.InvokeOnMainThreadAsync(() =>
{
valuesLock.EnterWriteLock();
try
{
Lista[indexof].Lida = true;
Lista[indexof].FrameBg = new Color(255, 255, 255, 0.7); //desperate try but no success
}
finally { valuesLock.ExitWriteLock(); }
});
}
}));
}
VIEW CODE BEHIND(relevant part):
CollectionViewMembers.BindingContext = MainPage.Lista;
VIEW XAML(relevant part):
<CollectionView x:Name="CollectionViewMembers" SelectionMode="None"
HorizontalScrollBarVisibility="Never" ItemsSource="{Binding .}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="6,10,5,1" Margin="0,0,0,0" BackgroundColor="{Binding FrameBg}">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Evento}" />
</StackLayout.GestureRecognizers>
<Grid HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<Frame IsClippedToBounds="True" Grid.Row="0" Grid.Column="0" CornerRadius="30" Padding="0" Margin="0">
<ffimageloading:CachedImage DownsampleToViewSize="True" HeightRequest="100" IsOpaque="True" Source="{Binding Imagem}" Aspect="AspectFill" LoadingPlaceholder="resource://MasterDetailPageNavigation.shared.icon_default.png" ErrorPlaceholder="resource://MasterDetailPageNavigation.shared.icon_default.png" />
</Frame>
<Grid Grid.Row="0" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="15" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="20" />
<RowDefinition Height="15" />
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Text="" TextColor="{Binding ColorOnline}" HorizontalOptions="Center" VerticalOptions="Center" FontSize="15">
<Label.FontFamily>
<OnPlatform x:TypeArguments="x:String" Android="Font-Awesome-Free-Solid.otf#FontAwesome5Free-Solid" iOS="FontAwesome5Free-Solid" />
</Label.FontFamily>
</Label>
<Label Grid.Column="1" Grid.Row="0" Text="{Binding Username}" HorizontalOptions="StartAndExpand" VerticalOptions="Center" FontSize="18" FontAttributes="Bold" LineBreakMode="TailTruncation" />
<Label Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="1" Text="{Binding Msg}" FontSize="15" HorizontalOptions="StartAndExpand" VerticalOptions="Start" LineBreakMode="TailTruncation" />
<Label Grid.ColumnSpan="1" Grid.Column="1" Grid.Row="2" Text="{Binding DataHora}" FontSize="11" TextColor="#CACACA" HorizontalOptions="End" VerticalOptions="Start" />
</Grid>
</Grid>
<BoxView Margin="0,10,0,0" HeightRequest="0.05" WidthRequest="100" BackgroundColor="#CCE5E5E5"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I also tried to do Lista[indexOf]=item; but no UI update.
Where is my mistake?

Xamarin Change 2 Image sources on click

I have a problem. I created a Image_OnClick event, but in that Event I want to change 2 images. I gave 1 image a x:Name="DislikeImage". Now my code doesn't recognise the x:Name. Here is my code:
protected void imgLike_Clicked(object sender, EventArgs args)
{
var i = (Image)sender;
string CurrentImageSource = i.Source.ToString();
if (CurrentImageSource.Contains("Like.png") == true)
{
i.Source = "Like_Selected.png";
DislikeImage.Source = "Dislike.png";
}
else if (CurrentImageSource.Contains("Like_Selected.png") == true)
{
i.Source = "Like.png";
}
}
Error is on this line:
DislikeImage.Source = "Dislike.png";
How can I fix this?
EDIT
Here is the xaml:
<ContentPage.Content>
<StackLayout>
<ListView x:Name="ListViewMain" VerticalOptions="FillAndExpand" BackgroundColor="#212121" SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label HeightRequest="1" BackgroundColor="#E3E3E3" />
<Grid x:Name="GridMain">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="160"/>
<RowDefinition Height="40"/>
<RowDefinition Height="160"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5" x:Name="Column0_Width" />
<ColumnDefinition Width="*" x:Name="Column1_Width" />
<ColumnDefinition Width="5" x:Name="Column2_Width" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Creator}" TextColor="White" FontSize="Body" FontAttributes="Bold" Grid.Column="1" Grid.Row="0" VerticalOptions="Center" HorizontalOptions="Start"/>
<Label Text="Subscribe" TextColor="#3897F0" FontSize="Body" Margin="0, 0, 10, 0" Grid.ColumnSpan="2" FontAttributes="Bold" Grid.Column="1" Grid.Row="0" VerticalOptions="Center" HorizontalOptions="End"/>
<Image Source="{Binding ImageLocation}" Margin="0, 0, 10, 0" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="1" Grid.RowSpan="3" BackgroundColor="AliceBlue" VerticalOptions="Fill" HorizontalOptions="Fill"/>
<Grid Grid.Row="4" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="38" />
<ColumnDefinition Width="38" />
<ColumnDefinition Width="38" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="38" />
<ColumnDefinition Width="38" />
</Grid.ColumnDefinitions>
<Image Source="Favorite.png" Grid.Row="0" HeightRequest="37" Grid.Column="2" HorizontalOptions="Start" VerticalOptions="Center">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="imgFavorite_Clicked" />
</Image.GestureRecognizers>
</Image>
<Image Source="Like.png" HeightRequest="37" VerticalOptions="Center" HorizontalOptions="Center" Grid.Row="0" Grid.Column="0" x:Name="LikeImage">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="imgLike_Clicked" />
</Image.GestureRecognizers>
</Image>
<Image Source="Dislike.png" HeightRequest="37" VerticalOptions="Start" Grid.Row="0" Grid.Column="1" x:Name="DislikeImage">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="imgDislike_Clicked" />
</Image.GestureRecognizers>
</Image>
<Image Source="Send_Dark.png" HeightRequest="40" Grid.Row="0" Grid.Column="4" HorizontalOptions="Center" VerticalOptions="Center"/>
<Image Source="Save_Dark.png" HeightRequest="40" Grid.Row="0" Grid.Column="5" HorizontalOptions="Center" VerticalOptions="Center"/>
</Grid>
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
You can access image control like this:
protected void imgLike_Clicked(object sender, EventArgs args)
{
var i = (Image)sender;
var parentGrid = i.Parent as Grid;
var dislikeImage = parentGrid.Children[2] as Image;
string CurrentImageSource = i.Source.ToString();
if (CurrentImageSource.Contains("Like.png") == true)
{
i.Source = "Like_Selected.png";
dislikeImage.Source = "Dislike.png";
}
else if (CurrentImageSource.Contains("Like_Selected.png") == true)
{
i.Source = "Like.png";
}
}
Hope this will resolve your issue.
According to your description, you want to change two image source by check one image source, I suggest you can use binding, I do one sample you can take a look:
<StackLayout>
<!-- Place new controls here -->
<ListView ItemsSource="{Binding models}" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout >
<Label Text="{Binding name}"/>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Source="{Binding url}" Grid.Row="0" HeightRequest="60">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="OnTapGestureRecognizerTapped"
NumberOfTapsRequired="2" />
</Image.GestureRecognizers>
</Image>
<Image Source="{Binding url1}" Grid.Row="1" HeightRequest="60"/>
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
public partial class MainPage : ContentPage
{
public ObservableCollection<model1> models { get; set; }
public MainPage()
{
InitializeComponent();
models = new ObservableCollection<model1>()
{
new model1(){name="image 1",url="image1.png",},
new model1(){name="image 2",url="image2.png"},
new model1(){name="image 3",url="image1.png"},
new model1(){name="image 4",url="image2.png"},
new model1(){name="image 5",url="image1.png"}
};
this.BindingContext = this;
}
private void OnTapGestureRecognizerTapped(object sender, EventArgs e)
{
var imageSender = (Image)sender;
var grid= (Grid)imageSender.Parent;
var stacklayout = (StackLayout)grid.Parent;
var label = (Label)stacklayout.Children[0];
model1 m = models.Where(o => o.name == label.Text).FirstOrDefault();
string url = imageSender.Source.ToString();
if(url.Contains("image1.png"))
{
m.url = "image2.png";
m.url1 = "image3.png";
}
else if(url.Contains("image2.png"))
{
m.url = "image1.png";
}
}
}
public class model1:BaseViewModel
{
public string name { get; set; }
private string _url;
public string url
{
get { return _url; }
set
{
_url = value;
OnPropertyChanged("url");
}
}
private string _url1;
public string url1
{
get { return _url1; }
set
{
_url1 = value;
OnPropertyChanged("url1");
}
}
}
You need to implement inotifyproperty to notify.
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs((propertyName)));
}
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(storage, value))
{
return false;
}
storage = value;
OnPropertyChanged(propertyName);
return true;
}
}

Binding individual property based of sqlite local database

I have created a ListView with items based on data saved in database. Its computer list with few properties as name, ipAdress, port and selected. If selected = true computer is marked as default and I need to change his appearance in ListView.
I need to create a binding to property which isnt part of the table.
I have simple list of computers (XAML)
<ListView x:Name="CompListView" HasUnevenRows="true" Grid.Row="1" SeparatorColor="Black" ItemsSource="{Binding ComputerList}"
SelectedItem="{Binding SelectedComputerItem, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding ComputerName}" Grid.Row="1" Font="20" TextColor="{Binding Selected_Color}" />
<Label Text="{Binding IPAddress}" Grid.Row="0" Font="20" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="{Binding Selected_Color}"/>
<Label Text="{Binding Port}" Grid.Row="1" Font="13" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="{Binding Selected_Color}"/>
<Image Source="computerpng.png" Grid.Row="0" Grid.Column="0" WidthRequest = "24" HeightRequest = "24" HorizontalOptions = "Start"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Base computer View connected to database.
public class BaseComputerView : INotifyPropertyChanged
{
public Computer _computer;
public INavigation _navigation;
public IComputer _computerRepository;
public string ComputerName
{
get => _computer.ComputerName;
set
{
_computer.ComputerName = value;
NotifyPropertyChanged("Computer_Name");
}
}
public string IPAddress
{
get => _computer.IPAddress;
set
{
_computer.IPAddress = value;
NotifyPropertyChanged("IPAddress");
}
}
public string Port
{
get => _computer.Port;
set
{
_computer.Port = value;
NotifyPropertyChanged("Port");
}
}
public bool Selected
{
get => _computer.Selected;
set
{
_computer.Selected = value;
NotifyPropertyChanged("Selected");
}
}
Based on _Selected I added property "Selected_Color" within the same class. Goal is to change back color of controls if the item is selected.
public string Selected_Color
{
get
{
string Text_Color = string.Empty;
try
{
if (Selected == true)
{
Text_Color = "#33cc33";
}
else
{
Text_Color = "#000000";
}
}
catch (Exception ex)
{
return "#000000";
}
return Text_Color;
}
}
This code however looks up for property "Selected_Color" in Computer table, which is wrong.
use the Ignore attribute to tell SQLite to ignore your new property
[Ignore]
public string Selected_Color
alternately, you could use a ValueConverter to set the color based on the Selected property
Thanks for your answer,
I figured it out by adding Selected_Color as Computer Table property.
[Table("Computer")]
public class Computer
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string ComputerName { get; set; }
public string IPAddress { get; set; }
public string Port { get; set; }
public bool Selected { get; set; }
[Ignore]
public string Selected_Color
{
get
{
string Text_Color = string.Empty;
try
{
if (Selected == true)
{
//Green color
Text_Color = "#33cc33";
}
else
{
Text_Color = "#000000";
}
}
catch (Exception ex)
{
return "#000000";
}
return Text_Color;
}
}
}
App_ComputerList_Image
Works fine until I open one of the computers for edit and come back to computer list. What is weird is fact that I get Java exception not for the first time I do that but only for the second time. So I am able to open one of the items and came back to computer list. If I repeat that then I get this Java exception.
just wanted to add answer for everyone who would fight with similar problem, that I found a better way to do this. You can define data templates based on your property and then use it to draw your Listview like this. Difference in this case is textcolor of the labels.
<ResourceDictionary>
<DataTemplate x:Key="SelectedComputer">
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding ComputerName}" Grid.Row="1" Font="20" TextColor="Green" />
<Label Text="{Binding IPAddress}" Grid.Row="0" Font="20" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="Green"/>
<Label Text="{Binding Port}" Grid.Row="1" Font="13" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="Green"/>
<Image Source="computerpng.png" Grid.Row="0" Grid.Column="0" WidthRequest = "24" HeightRequest = "24" HorizontalOptions = "Start"/>
</Grid>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="Computer">
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding ComputerName}" Grid.Row="1" Font="20" TextColor="Black" />
<Label Text="{Binding IPAddress}" Grid.Row="0" Font="20" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="Black"/>
<Label Text="{Binding Port}" Grid.Row="1" Font="13" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="Black"/>
<Image Source="computerpng.png" Grid.Row="0" Grid.Column="0" WidthRequest = "24" HeightRequest = "24" HorizontalOptions = "Start"/>
</Grid>
</ViewCell>
</DataTemplate>
<local:ComputerTemplateSelector x:Key="ComputerTemplateSelector" SelectedComputer="{StaticResource SelectedComputer}" Computer="{StaticResource Computer}" />
</ResourceDictionary>
Template selector:
public class ComputerTemplateSelector : DataTemplateSelector
{
public DataTemplate SelectedComputer { get; set; }
public DataTemplate Computer { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return ((SQLite_Database.Computer)item).Selected == true ? SelectedComputer : Computer;
}
}

Binding Itemsource in ListView inside of CarouselView - Xamarin

I have tried to put a ListView inside a CarouselView, but the element binding does not work.
If I comment out the ListView, the project will work fine.
The error is
Binding: 'Contenido' property not found on
'App.ViewModels.FeedListViewModel', target property:
'Xamarin.Forms.ListView.ItemsSource'
The code is as follows:
VIEWMODEL
public class Feed
{
public int IdFeed { get; set; }
public String Title { get; set; }
public bool HasNewElements { set; get; }
public ObservableCollection<NewsFeedDocument> Contenido { get; set; }
}
public class FeedListViewModel : MenuViewModel
{
public ObservableCollection<Feed> Feeds { get; set; }
public FeedListViewModel()
{
Feeds = new ObservableCollection<Feed>();
for (int i = 0; i <= 12; i++)
{
//Creamos lista de elementos Feed
NewsFeedDocument documento = new NewsFeedDocument();
documento.Titulo = "TITULO dasd dsa dsa dsa dsa";
ObservableCollection<NewsFeedDocument> ElementsX = new ObservableCollection<NewsFeedDocument>();
ElementsX.Add(documento);
Feeds.Add(new Feed
{
IdFeed = i ,Title = "SECTOR" + i,
Contenido = ElementsX
});
}
Position = 0;
}
private int _position = 0;
public int Position
{
get { return _position; }
set { _position = value; RaisePropertyChanged(() => Position); }
}
}
}
XAML
<cv:CarouselView x:Name="FeedsItemsCarousel" Grid.Row="2" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
Position="{Binding Position, Mode=TwoWay}"
ItemsSource="{Binding Feeds}">
<cv:CarouselView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!--<Image Grid.RowSpan="2" Aspect="AspectFill" Source="{Binding ImageUrl}"/>-->
<StackLayout Grid.Row="1" BackgroundColor="#80000000" Padding="12">
<Label TextColor="White" Text="{Binding Title}" FontSize="16" HorizontalOptions="Center" VerticalOptions="CenterAndExpand"/>
</StackLayout>
</Grid>
<StackLayout>
<ListView x:Name="FeedListItem" ItemsSource="{Binding Contenido}" RowHeight="120">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand" HorizontalOptions="Fill" BackgroundColor="White" Padding="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Titulo}" Style="{StaticResource TituloL}" Grid.Row="0" Grid.Column="0" />
</Grid>
<StackLayout Orientation="Horizontal">
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</DataTemplate>
</cv:CarouselView.ItemTemplate>

Categories