Bind Stepper value with Label text in Xamarin - xaml

I have a ListView, and there are Label and Stepper in one ListView.ItemTemplate. How do I bind Stepper value changing to this Label?
<ListView x:Name="productsList"
ItemsSource="products"
HasUnevenRows="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout x:Name="productStack" Orientation="Vertical">
<Label x:Name="NameLabel"
Text="{Binding DisplayName}"
Font="Bold" />
<Label x:Name="count"
Text="1"/>
<Stepper x:Name="countStepper"
Minimum="1"
Increment="1" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
When I try to change Label's text in code behind
void countStepper_ValueChanged(object sender, ValueChangedEventArgs e)
{
count.Text = countStepper.Value.ToString();
}
it is said that count does not exist in the current context

How you can achieve is through below steps, if you are using MVVM
Have a model property for Label which displays the count.
In the countStepper_ValueChanged, get the object (model data) associated with that view cell and in the view model, code it to set/change the count property of label based on the value change.

Related

Cant reselect previous selected item in CollectionView in Xamarin.Forms on iOS

TLDR
CollectionView broken in iOS, cant find any solution online. Weak Google fu or just not seeing the answer.
The problem
I have a CollectionView (Lets call it A) that contains items that are only strings values for filtering on a different CollectionView (Lets call it B) containing results from selecting a filter option in CollectionView A.
I have 3 different filtering options: "All", "Close to you", "Online" in CollectionView A.
The problem is that on iOS when I select for example filter option "All" in CollectionView A for the first time on the page it does the filtering and shows the results in CollectionView B, when I choose for example filtering option "Online" in CollectionView A it filters and shows the results in CollectionView B.
But when I choose filtering option "All" for the second time in CollectionView A its not responding, no event triggers, no commands runs and its not disabled. It is only showing, but I cant do anything with it.
Expected result
Can reselect the previous item on iOS, in Android no problem.
Actual result
Cant reselect previous item on iOS, need to back to previous page in stack and then navigate back to page to reset filtering.
The xaml markup
This is the xaml markup for the CollectionView A as explained above, the only holding string values to filter on.
<CollectionView ItemsSource="{Binding FilterLocations}"
Grid.Row="2"
SelectedItem="{Binding SelectedFilterLocation}"
SelectionMode="Single"
HeightRequest="50">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal"
ItemSpacing="10" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="x:String">
<StackLayout xct:TouchEffect.NativeAnimation="True">
<Frame BorderColor="{StaticResource BorderColor}"
x:Name="subCategoryFrame"
Padding="14, 10">
<Label Text="{Binding .}"
x:Name="subCategoryName"
FontFamily="{StaticResource FontPoppinsLight}"
TextColor="{StaticResource PrimaryAlt}" />
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.Header>
<BoxView WidthRequest="0"
HeightRequest="1"
BackgroundColor="Transparent" />
</CollectionView.Header>
<CollectionView.Footer>
<BoxView WidthRequest="{StaticResource NormalSpacingDouble}"
HeightRequest="1"
BackgroundColor="Transparent" />
</CollectionView.Footer>
</CollectionView>
The CollectionView A is in SelectionMode:Single, and the SelectedItem is bound to a ICommand on its bound ViewModel. And in the ViewModel the selection of a item in CollectionView A will trigger a filtering in CollectionView B
What I done so far
I set up so if a item in the CollectionView A is disabled it become Red, but it dont become Red.
I have tried to add a event in the Code behind, to try and set SelectedItem to null, but that back fired and just made all events go twice, one for selecting the item on the screen and second for altering the SelectedItem in the code behind.
Code:
private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (Device.RuntimePlatform == Device.iOS)
{
var collectionView = sender as CollectionView;
if (collectionView == null) return;
if (collectionView.SelectedItem != null)
{
collectionView.SelectedItem = null;
}
}
}
(I know it is a big no no to do logic stuff in the Code Behind that is not design logic, but I need to get this solved or have a quick and dirty fix because of time pressure.)
Sorry for the wall of text
Use a TapGestureRecognizer.
Below, MyItemCommand is defined in MyViewModel and {Binding .} refers to the item selected in ItemsSource.
<DataTemplate ...>
<StackLayout>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type vm:MyViewModel}},
Path=MyItemCommand}"
CommandParameter="{Binding .}"/>
</StackLayout.GestureRecognizers>
...
First Bind the collection view into the event selectionchange.
<CollectionView ItemsSource="{Binding FilterLocations}"
Grid.Row="2"
SelectedItem="{Binding SelectedFilterLocation}"
SelectionMode="Single"
HeightRequest="50"
SelectionChanged="collection_SelectionChanged">
then inside the event put selected item to null.
private async void collection_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
var Sender = sender as CollectionView;
if (Sender.SelectedItem == null)
return;
Sender.SelectedItem = null;
}
catch (Exception ex)
{
}
}

Xamarin Forms Listview Rounded Corner Cell highlight grayout

I'm finding a solution to customize on-tap listview cell grayout with rounded corners
This is what I'm having now But I need to make the greyout as the next image
**This is what I'm expecting!!!
<ListView ItemSelected="ItemSelected" ItemsSource="{Binding Patients}" SeparatorVisibility="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<custom:RoundedCornerView RoundedCornerRadius="12" Margin="11,5.5,11,5.5" VerticalOptions="FillAndExpand" >
<StackLayout Orientation="Vertical" BackgroundColor="White" Padding="11" >
<Label Text="{Binding WardName}".../>
</StackLayout>
</custom:RoundedCornerView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
I believe you have a BackgroundColor property for the custom:RoundedCornerView. You can have a binding property assigned to the BackgroundColor.
eg: <custom:RoundedCornerView RoundedCornerRadius="12" BackgroundColor= {Binding CellColor} Margin="11,5.5,11,5.5" VerticalOptions="FillAndExpand" >
In your model class which is binded for this ListView, you can have this property (assume that you used INotifyPropertyChanged in the model class.
private string cellColor = "#ffffff";
public string CellColor
{
get { return cellColor;}
set { cellColor = value; OnPropertyChanged("CellColor");}
}
In the ViewModel, you can have an ICommand for triggering the tap of the list item click. In the method associated with the ICommand, you have code to change the color of the CellColor property of that particular list item to grey color.

ListView doesn't display data in xamarin

I am new to xamarin and trying to display a listview. My attempt is as follows.
<ContentPage.Content>
<StackLayout>
<ListView x:Name="ComListView" RowHeight="80">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid Margin="8">
<Label Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Grid.ColumnSpan="2" Text="hello world" FontAttributes="Bold" />
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
But when I ran the app, even I navigate to correct page; nothing display. For any other views, it will display the right output. So where could I get wrong on the listview?
You have to put items to the ListView. Currently, you only specify the ItemTemplate, which determines how an item will look (in your case, they will all look the same (i.e. Labels with 'hello world' text)). But the ListView is empty and so there are no items to show.
You can set items using the ItemsSource property of the ListView.
Usually, you use Binding inside an ItemTemplate to show item content.
Let's say we have a class Person:
class Person
{
public string Name { get; set; }
}
Then you create a List of Person objects and add it to your ListView in code:
var personnel = new List<Person>
{
new Person { Name = "Booker" },
new Person { Name = "Elizabeth" }
};
ComListView.ItemsSource = personnel;
And in your XAML, you have to set the ItemTemplate so that it shows the Name of each Person:
<Label Text="{Binding Name, Mode=OneWay}" />
Note: You can also bind to ItemsSource from XAML if you have a ViewModel.
You are not binding the data to the listview.
use the ItemSource property to bind data, either from xaml, code behind or use a binding to populate from your ViewModel

SelectedItem binding is not updating the ViewModel

I feel like I'm missing something obvious because this is so simple. Thanks in advance for the help. I'm struggling with binding the SelectedItem of a simple ListView in a Xamarin application. I'm testing on UWP and am using Prism's MVVM BindableBase base class. Here's what I'm experiencing:
The page loads and nothing in the list is selected.
I select an item in the list.
The setter of SelectedGrade is called with a value of null.
After that, selecting items does not cause the SelectedGrade setter to be called.
Here's the relevant XAML:
<ListView BackgroundColor="#7F7F7F"
CachingStrategy="RecycleElement"
IsPullToRefreshEnabled="True"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
ItemsSource="{Binding Grades, Mode=OneWay}"
SelectedItem="{Binding SelectedGrade, Mode=TwoWay}"
RefreshCommand="{Binding RefreshCommand}"
RowHeight="50">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"
Orientation="Horizontal"
Padding="10">
<Label HorizontalOptions="FillAndExpand"
Text="{Binding Title}"
TextColor="#272832"/>
<Label HorizontalOptions="FillAndExpand"
Text="{Binding Score}"
TextColor="Aquamarine" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Here's the ViewModel:
Grade _selectedGrade;
public Grade SelectedGrade
{
get { return _selectedGrade; }
set { SetProperty(ref _selectedGrade, value); } // this gets set to NULL the first time i select an item then never gets set again
}
Edit: I've also added an ItemSelected event listener in the code-behind and it is not being fired after the initial item is selected. The one time it is fired, the SelectedItemChangedEventArgs reveal that the ListView's SelectedItem is null. I can also see at this time that the ListView's ItemsSource has a collection of three items in it, as I would expect. I'm quite confused as to why the ListView thinks the SelectedItem is null and why it is not broadcasting when the selected item changes.
It looks like this was a bug in Xamarin. I upgraded from Xamarin.Forms 3.0.0.550146 to 3.1.0.637273 and now it works.
I have faced with the similar issue when List does not bind to view model with SelectedItem and Xamarin forms 5.0.0.2244.
It was resolved with setting default value of List property to new List() object instead null value in the view model before setting binding context . After that binding has became working.

how to add multiple command buttons inside of xamarin listview using MVVM?

I am trying to create a listview where users can select the list item to view the store and also be able to click on the image to take them to the product detail.
How can I add a command in the ViewCell?
<ListView ItemsSource="{Binding myData}" x:Name="myListView" SelectedItem="{Binding SelectedStore}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Label Text="{Binding Title}" />
<Image Source="product.png" >
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ItemTapCommand}" CommandParameter="Id" />
</Image.GestureRecognizers>
</Image>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
public ICommand ItemTapCommand => new Command(ShowSelectedProductAsync());
private async Task ShowSelectedProductAsync()
{
//take them to view the item detail
}
The problem is that you are attempting to bind to a command that is not located on the individual item within the ListView; the BindingContext on your Image is the individual items inside your myData collection.
With other frameworks, for example, Wpf, you would simply use the RelativeSource part of binding to tell the control to look for your command on the BindingContext of another control, however this isn't possible in Xamarin Forms (RelativeSource is not supported).
What you can do is the following, but it requires your UserControl to have an x:Name:
<TapGestureRecognizer Command="{Bindind Path=BindingContext.ItemTapCommand,
Source={x:Reference MyUserControl}}"
CommandParameter="{Binding Id}" />
What this says is to use the UserControl as the source for the binding, and the property is a nested property on that UserControl composed of BindingContext.ItemTapCommand.
As a bonus, I updated the code because I felt that you probably meant to bind the value of the Id property of each record as the command parameter, and not merely to send the string "Id" as the command parameter.