Xamarin : Change label text inside listview - xamarin.forms

I am new with xamarin, I am facing an issue in my xamarin forms project.
I have a Label and 2 images inside listview-viewcell. I want to change the label text onclick of images. Increase the label text value by 1 if click like and decrease by 1 if click unlike. I use the label x:name, but it is not accessible in class. How can i fix this?
<StackLayout>
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label
Text="{Binding likeCount}"
x:Name="likecount"/>
<Image Source="like.png">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="LikeOrUnlikeTweet"
CommandParameter="{Binding .}"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image
<Image Source="unlike.png">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="LikeOrUnlikeTweet"
CommandParameter="{Binding .}"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Anybody please suggest a solution with working code.
Thanks in advance

First of you need to create command in your VM and need to change as follow:
<TapGestureRecognizer
Tapped="{Binding Source={x:Reference YourListName}, Path=BindingContext.LikeOrUnlikeTweetCommand}"
CommandParameter="{Binding .}"
NumberOfTapsRequired="1" />
ViewModel Code
public ICommand LikeOrUnlikeTweetCommand { get; }
Initialise in constructor
LikeOrUnlikeTweetCommand = new Command<YourModelDto>(LikeOrUnlikeTweet);
Function code in this you change your count value and update list.
void LikeOrUnlikeTweet(YourModelDto yourModelDto)
{
....
}

I would take one of 2 paths for doing this:
Use an ObservableCollection as ItemsSource for your list, obvious when you change properties of an item they would be reflected in the list. What the list view would do is it would replace the old item with the new one modified with your new values. You can make a search about what an ObservableCollection collection is.
My actual way, as im fighting low performance of android with listviews, and this makes it: you can create a custom class for ViewCell, avoid low-speed bindings, set all properties inside your custom ViewCell by code. When the cell bindigcontext changes more likely the ItemsSource item is being assigned to your cell, so you can now take its value ans set it up.
protected override void OnBindingContextChanged()
{
SetupCell(); //assign values to named controls manually
base.OnBindingContextChanged();
}
public void SetupCell()
{
var item = BindingContext as YouItemClass;
if (item == null) return;
txtTitle.Text = item.Name;
//etc
...

Related

Observable collection is not triggering when changes the one object property in xamarin forms

I have a checkbox in my ListView. and the property "IsSelected" binded to the checkbox which is in the Assignment model.
The IsSelected property is triggering when I click on the checkbox. But "ObservableCollection ListActivities" is not triggering which is ViewModel when checkbox clicked.
How ObservableCollection ListActivities will trigger when clicks on the checkbox.
Please Help me.
Model:
public class Assignment : NotifyPropertyChanged
{
[JsonIgnore]
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set
{
_isSelected = value;
RaisePropertyChanged(nameof(IsSelected));
}
}
}
ViewModel:
private ObservableCollection<Assignment> _listActivities;
public ObservableCollection<Assignment> ListActivities
{
get => _listActivities;
set
{
RaiseAndSetIfChanged(ref _listActivities, value);
RaisePropertyChanged(nameof(ListActivities));
}
}
XAML:
<ListView x:Name="ClusteredActivities"
ItemsSource="{Binding ListActivities, Mode=TwoWay}"
Margin="20"
SeparatorVisibility="None"
HorizontalOptions="Center">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Padding="0">
<CheckBox
HorizontalOptions="Start"
VerticalOptions="Center"
Color="Black"
IsChecked="{Binding IsSelected, Mode=TwoWay}">
</CheckBox>
<Label Style="{DynamicResource ItalicLabel}">
<Label.FormattedText>
<FormattedString>
<FormattedString.Spans>
<Span Text="{Binding ParentIncident.ErpSrNumber}" />
<Span Text=", " />
<Span Text="{Binding ActivityId}" />
<Span Text=", " />
<Span Text="{Binding ActivityType}"/>
</FormattedString.Spans>
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
From document ObservableCollection Class,we know that ObservableCollection<T> Class
Represents a dynamic data collection that provides notifications when
items get added or removed, or when the whole list is refreshed.
So, we can receive notification once items get added or removed, or when the whole list is refreshed. On the other side, changing one property in the item will not trigger notification for ListActivities .
How ObservableCollection ListActivities will trigger when clicks on
the checkbox.
If we want to trigger ListActivities ,we can add relative code in the setter method.
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set
{
_isSelected = value;
RaisePropertyChanged(nameof(IsSelected));
// add relative code here for `ListActivities`
}
}

When change an object inside a CollectionView multiple objects are affected

If I hide an image visibility in CollectionView, multiple image visibility is affecting but image Tapped event fires once.
Simplified CollectionView xaml..
<CollectionView x:Name="favCollectionView"
ItemsSource="{Binding FavoriteCollection}"
RemainingItemsThresholdReachedCommand="{Binding GetNextDatas}"
RemainingItemsThreshold="1"
ItemSizingStrategy="MeasureAllItems"
ItemsLayout="VerticalList"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid VerticalOptions="FillAndExpand">
<Label Grid.Row="0" Text="{Binding TargetText}"/>
<Image Grid.Row="0" Aspect="AspectFill" Source="seeResult.png">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="Tapped_TranslatedResult"/>
</Image.GestureRecognizers>
</Image>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Code behind..
void Tapped_TranslatedResult(System.Object sender, System.EventArgs e)
{
var img = sender as Image;
if (img != null)
{
img.Opacity = 0;
}
}
For example, If I have 50 rows in CollectionView and tapped once top second image item, next ninth image's visibility is changed too and again next ninth one too, so on..
What could be the problem?
I changed the Image to ImageButton and then added Command parameter. The key was the Jason's comment. Binding the Model property to my ImageButton's IsVisibility property and it worked correctly.

Add Content Programatically to TabViewItem in TabView Xamarin forms

I am using TabView in my project. I've installed Xamarin.community.toolkit.
I am trying to add Content for TabViewitem programmatically instead of xaml because each ContentView of TabViewItem has service calls in it's constructor which is causing the issue when all the TabViewItems load at once.
Below is my code:
<xcl:TabView x:Name="MainTabView"
TabStripPlacement="Top">
<xcl:TabViewItem
x:Name="Tab1"
Text="Details"
Margin="16,0,16,0"
TextColor="Black"
FontFamily="{StaticResource SFProRegular}"
TextColorSelected="Black"
FontSize="15">
</xcl:TabViewItem>
------
</xcl:TabView>
And I 'm trying to add Content to TabViewItem programatically like below (Page1 is a ContentView)
var stackPanel = new StackLayout { Orientation = StackOrientation.Vertical };
stackPanel.Children.Add(new Page1());
DetailsTabView.Content = stackPanel;
But the UI is not rendering in my app.
The same works If I add the Page1 like below:
<xcl:TabView x:Name="MainTabView"
TabStripPlacement="Top" >
<xcl:TabViewItem
x:Name="Tab1"
Text="Details"
Margin="16,0,16,0"
TextColor="Black"
FontFamily="{StaticResource SFProRegular}"
TextColorSelected="Black"
FontSize="15">
<template:Page1 />
</xcl:TabViewItem>
------
</xcl:TabView>
Any help is appreciated!
And I 'm trying to add Content to TabViewItem programatically like below (Page1 is a ContentView)
If you want to add one COntentview in one TabViewItem by code behind, you can take a look:
<xct:TabView
x:Name="mytabview"
TabIndicatorColor="Yellow"
TabStripBackgroundColor="Blue"
TabStripHeight="60"
TabStripPlacement="Bottom">
<xct:TabViewItem
x:Name="tb1"
FontSize="12"
Text="Tab 1"
TextColor="White"
TextColorSelected="Yellow">
<StackLayout />
</xct:TabViewItem>
<xct:TabViewItem
x:Name="tb2"
FontSize="12"
Text="Tab 2"
TextColor="White"
TextColorSelected="Yellow">
</xct:TabViewItem>
</xct:TabView>
Then adding ContentView to TabViewItem.
public MainPage()
{
InitializeComponent();
mytabview.TabItems[0].Content = new contentview1();
mytabview.TabItems[1].Content = new contentview2();
}
Note: please forget to add Stacklayout or other layout inside TabViewItem by xaml, then code you add contentview will be effective.
you need to do somethig like this
<xct:TabView TabItemsSource="{Binding TabVms}"
TabStripPlacement="Top"
TabStripBackgroundColor="LightGray"
TabIndicatorColor="Gray" IsTabStripVisible="True">
<xct:TabView.TabViewItemDataTemplate>
<DataTemplate>
<Grid>
// tabs
</Grid>
</DataTemplate>
</xct:TabView.TabViewItemDataTemplate>
<xct:TabView.TabContentDataTemplate>
<DataTemplate>
<Grid>
// content`enter code here`
</Grid>
</DataTemplate>
</xct:TabView.TabContentDataTemplate>
</xct:TabView>

Binding albumArt in AlbumCollection to listbox

How can I bind AlbumArt to my listbox?
My code:
<ListBox Name="albumLb" Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="albumLb_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,17" >
<!--Replace rectangle with image-->
<Image Source="{Binding }"/>
<StackPanel Width="311">
<TextBlock Text="{Binding Name}" FontSize="28" />
<TextBlock Text="{Binding Artist}" Margin="12,-6,12,0" Foreground="#FFE5CDCD"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And in my code I use:
albumLb.ItemsSource = library.Albums;
I know that I can get the AlbumArt by library.Albums[int index].getAlbumArt() but I don't know how to bind it into my listbox.
What type does getAlbumArt() return? If it is simply a path to a file (say in Isolated Storage) then you'll have to write a converter to do the binding. Also, instead of having a function called getAlbumArt(), create a property named AlbumArt instead with a public getter, which will allow binding to it. Then you can bind the image using
<Image Source="{Binding AlbumArt}" />
Next, create a converter (by implementing the IValueConverter interface) that will take the path to a file in Isolated Storage, and load it into a BitmapImage which is then returned to the Image in your ListBox by the converter.
This question has details on how to do this.
On the other hand, if you need to download the image from some website, use WebClient.OpenReadAsync.
WebClient wc = new WebClient();
wc.OpenReadCompleted += new OpenReadCompletedEventHandler(OnImageDownloadCompleted);
wc.OpenReadAsync(new Uri("www.mywebsite.com/albumart/album1.jpg", UriKind.Relative));
void OnImageDownloadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null) {
StreamResourceInfo sri = new StreamResourceInfo(e.Result as Stream, null);
BitmapImage imgsrc = new BitmapImage();
imgsrc.SetSource(sri.Stream);
}
}

Panorama Binding on WP7, Items collection must be empty before using ItemsSource

i keep getting this error: Items collection must be empty before using ItemsSource, when i attempt to bind data to a Panorama control. below is my xaml snippet.
<controls:Panorama x:Name="panorama">
<controls:PanoramaItem >
<StackPanel>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</controls:PanoramaItem>
</controls:Panorama>
in my code behind (xaml.cs), i do something like this:
protected override void OnNavigatedTo(NavigationEventArgs e) {
string id = NavigationContext.QueryString["id"];
ObservableCollection<MyObject> list = DataAccessService.get(id);
panorama.ItemsSource = list;
base.OnNavigatedTo(e);
}
note that MyObject has a Text property. any help is appreciated.
after modifying it per the link below, the same exception is still thrown.
<controls:Panorama x:Name="panorama">
<controls:Panorama.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</controls:Panorama.HeaderTemplate>
<controls:PanoramaItem >
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</DataTemplate>
</controls:PanoramaItem>
</controls:Panorama>
finally, after continuing further with the user below's help, this is the solution that got rid of the exception.
<controls:Panorama x:Name="panorama">
<controls:Panorama.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</controls:Panorama.HeaderTemplate>
<controls:Panorama.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</DataTemplate>
</controls:Panorama.ItemTemplate>
</controls:Panorama>
Your problem is that you're building the Panorama in XAML as though it were static rather than preparing it to be data-bound.
Take a look at this quick tutorial for a Data Binding Panorama Control:
Data Binding Panorama Control WP7 MVVM
Notice the difference in how your XAML is being constructed for the control. Instead of setting the Items collection on the Panorama control, you need to set the HeaderTemplate and ItemTemplate so that the control knows how to render things once data is bound to it.

Resources