Xamarin Change 2 Image sources on click - c#

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;
}
}

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;
}
}

Row set in 'Auto' takes me all the screen even if it is blank

In a CollectionView I have 4 rows, 2 of which are set to "Auto".
In one I have a Label in Binding, in the other I have another CollectionView with objects in Binding. In the Row where I have the Label, the height is automatically set correctly, while where I have the CollectionView it becomes an "infinite" height, in the sense that even if empty, it takes up the whole screen.
<DataTemplate>
<yummy:PancakeView CornerRadius="5" BackgroundColor="Transparent">
<Grid BackgroundColor="Gainsboro" RowSpacing="0.2">
<Grid.RowDefinitions>
<RowDefinition Height="21"/>
<RowDefinition Height="16"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3"/>
<ColumnDefinition Width="65"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<BoxView Grid.Column="0" Grid.RowSpan="4" BackgroundColor="{Binding ColoreUmore}"/>
<Label Grid.Row="0" Grid.Column="2" Text="{Binding GiornoTrascritto}" FontSize="14" TextColr="Gray" Margin="0,5,0,0"/>
<Label Grid.Row="1" Grid.Column="2" Text="{Binding Orario}" FontSize="14" TextColr="Gray"/>
<Image Grid.Row="0" Grid.RowSpan="3" Grid.Column="1" Margin="8" Source="{Binding Umore}" VerticalOptions="Start" HeightRequest="45"/>
<Label Grid.Row="3" Grid.Column="2" TextColor="Black" FontSize="16" Text="{Binding Nota}" Margin="0,0,10,0" VerticalOptions="Start" HorizontalTextAlignment="Start" VerticalTextAlignment="Start"/>
<CollectionView
Grid.Row="2"
Margin="0,0,10,0"
Grid.Column="2"
SelectionMode="None"
ItemsSource="{Binding IconDiaries}"
VerticalOptions="Start">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" VerticalItemSpacing="5" HorizontalItemSpacing="5"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid RowSpacing="0.5">
<Grid.RowDefinitions>
<RowDefinition Height="17"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="18"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<BoxView BackgroundColor="Gray" Grid.ColumnSpan="2" Grid.Row="0" CornerRadius="5" Opacity="0.6" />
<Image Grid.Row="0" Grid.Column="0" Source="{Binding isSource}" Margin="3"/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding id}" TextColor="Black" FontSize="12" VerticalTextAlignment="Center" Margin="0,0,3,0"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</yummy:PancakeView>
</DataTemplate>
while where I have the CollectionView it becomes an "infinite" height, in the sense that even if empty, it takes up the whole screen.
From your code and description, you have one collectionview in datatemplate, now you want to adjust collectionview height according to its content, am I right?
If yes, I suggest you can binding collectionview HeightRequest like the following code:
<StackLayout >
<CollectionView
x:Name="assessmentsCollectionView"
BackgroundColor="Blue"
HeightRequest="{Binding rowHeigth}"
ItemsSource="{Binding letters}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="5" Spacing="10">
<Frame
Padding="0"
CornerRadius="5"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal">
<Frame
Padding="5"
CornerRadius="0"
WidthRequest="50">
<Label
FontSize="24"
HorizontalTextAlignment="Center"
Text="{Binding TypeLetter}"
TextColor="#37474f"
VerticalTextAlignment="Center" />
</Frame>
<StackLayout Padding="10">
<Label
FontSize="24"
Text="{Binding Name}"
TextColor="Black" />
<StackLayout Orientation="Horizontal">
<Image
HeightRequest="12"
Source="c1.png"
WidthRequest="12" />
<Label
FontSize="12"
Text="{Binding Date}"
TextColor="Gray" />
</StackLayout>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Button
x:Name="btn1"
Command="{Binding AddCommand}"
Text="btn1" />
</StackLayout>
public partial class Page4 : ContentPage
{
public Page4()
{
InitializeComponent();
this.BindingContext = new letterviewmodel(); ;
}
}
public class letterviewmodel: INotifyPropertyChanged
{
public ObservableCollection<lettermodel> letters { get; set; }
private int _rowHeigth;
public int rowHeigth
{
get { return _rowHeigth; }
set
{
_rowHeigth = value;
RaisePropertyChanged("rowHeigth");
}
}
public ICommand AddCommand { protected set; get; }
public letterviewmodel()
{
letters = new ObservableCollection<lettermodel>()
{
new lettermodel(){TypeLetter="A",Name="letter 1",Date="2021-01-01"},
new lettermodel(){TypeLetter="B",Name="letter 2",Date="2021-01-01"},
new lettermodel(){TypeLetter="C",Name="letter 3",Date="2021-01-01"}
};
rowHeigth = letters.Count * 100 ;
AddCommand = new Command<lettermodel>(async (key) => {
letters.Add(new lettermodel() { TypeLetter = "D", Name = "test letter ", Date = "2021-01-01" });
rowHeigth = letters.Count * 100 ;
});
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class lettermodel
{
public string TypeLetter { get; set; }
public string Name { get; set; }
public string Date { get; set; }
}
The screenshot:
If I understand correctly, you want the CollectionView to take an automatic height and adapt to the row, right?
In order to make this happen you will need to:
Set the property
ItemSizingStrategy="MeasureFirstItem" in the CollectionView, so the CollectionView has the proper height you're looking for.
Set the Row Height to *, so the CollectionView height sets automatically for the remaining size of the page.
Set VerticalOptions to FillAndExpand in Collection View so the CollectionView can adapt to the size of the Row.
Finally, put the label with Row 3 below the CollectionView to avoid any issues with the Layout order.
Let me know if this does any help!

IsVisible not loading correctly in ListView

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?

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>

Get index of data binding from ItemsControl

Is there any way to get the index of the data which is binded to the ItemsControl, when a button is clicked?
<ItemsControl x:Name="ic_schranke" DataContext="{Binding Schranke}" >
<ItemsControl.ItemTemplate>
<DataTemplate >
<Button Height="80" x:Name="btn_open" Click="btn_open_Click" HorizontalAlignment="Stretch" Style="{StaticResource TransparentStyle}">
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="30*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Rectangle x:Name="rect" Grid.ColumnSpan="3" Grid.Row="1" Opacity="0.65" Grid.Column="0" Fill="#FFCEEAFF"/>
<Border CornerRadius="25" Height="50" Width="50" HorizontalAlignment="Center" Grid.Column="0" Grid.Row="1">
<Border.Background>
<ImageBrush ImageSource="/Assets/schranken.jpg" />
</Border.Background>
</Border>
<TextBlock Name="schranken_name" Grid.Column="1" Grid.Row="1" Text="{Binding name}" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="ExtraLight" Foreground="Black" />
</Grid>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Here is the sample data which is binded to the IC:
List<Schranke> elements;
public UserPage()
{
this.InitializeComponent();
elements = new List<Schranke>();
for (var i = 1; i < 15; i++)
elements.Add(new Schranke() { name = $"Schranke NR:{i}" });
this.ic_schranke.ItemsSource = elements;
}
And here is the code in the button click event:
private async void btn_open_Click(object sender, RoutedEventArgs e)
{
Grid grid = (sender as Button).Content as Grid;
//Debug.WriteLine($"content {tb.Text} clicked");
var tmp_background = grid.Background;
grid.Background = new SolidColorBrush(new Windows.UI.Color() { A = 255, R = 78, G = 170, B = 44 });
VibrationDevice testVibrationDevice = VibrationDevice.GetDefault();
testVibrationDevice.Vibrate(System.TimeSpan.FromMilliseconds(150));
await Task.Delay(3000);
grid.Background = tmp_background;
}
Maybe something along the lines of this:
the presenter - put this in the data context
public class SchrankePresenter : INotifyPropertyChanged
{
private List<Schranke> _elements;
public List<Schranke> Elements
{
get { return _elements; }
set
{
_elements = value;
OnPropertyChanged("Elements");
}
}
public ICommand ClickCommand { get; set; }
private void OnPropertyChanged(string propName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
public event PropertyChangedEventHandler PropertyChanged;
public SchrankePresenter()
{
var elements = new List<Schranke>();
for (var i = 1; i < 15; i++)
elements.Add(new Schranke() { Name = $"Schranke NR:{i}" });
Elements = elements;
ClickCommand = new DelegateCommand(ClickAction);
}
public void ClickAction(Schranke item)
{
VibrationDevice.GetDefault().Vibrate(TimeSpan.FromMilliseconds(150));
}
}
public class Schranke
{
public string Name { get; set; }
}
the template:
<ListView ItemsSource="{Binding Elements}">
<ListView.ItemTemplate>
<DataTemplate>
<Button Height="80"
HorizontalAlignment="Stretch"
Command="{Binding ClickCommand}"
Style="{StaticResource TransparentStyle}">
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="30*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Rectangle x:Name="rect"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="3"
Fill="#FFCEEAFF"
Opacity="0.65" />
<Border Grid.Row="1"
Grid.Column="0"
Width="50"
Height="50"
HorizontalAlignment="Center"
CornerRadius="25">
<Border.Background>
<ImageBrush ImageSource="/Assets/schranken.jpg" />
</Border.Background>
</Border>
<TextBlock Name="schranken_name"
Grid.Row="1"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="ExtraLight"
Foreground="Black"
Text="{Binding Name}" />
</Grid>
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
you can do the background animation using a storyboard/visualstate
EDIT : regarding the DelegateCommand, it's a simple implementation I use for my WPF apps -
internal class DelegateCommand<T> : ICommand
{
private Action<T> _clickAction;
public DelegateCommand(Action<T> clickAction)
{
_clickAction = clickAction;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_clickAction((T)parameter);
}
}

Categories