Xamarin Xaml bind more than 2 properties to a TextCell - xaml

I'm wanting to bind more than 2 properties to my list is this even possible check my code below
<ListView x:Name="APRListView"
Grid.Row="4"
Grid.RowSpan="5"
Grid.Column="0"
Grid.ColumnSpan="4"
Margin="10,-20,-50,-300">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell
Text="{Binding ProductName}"
Detail="{Binding Monthly}"
/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Is there another approach to this?
I would also like to add text to the detail also ie on Detail="{Binding Monthly}" I'd like it to return on the frontend - Monthly: {Monthly}

use a ViewCell to compose your own layout, and use a Label with FormattedText to include multiple sources of text in one Label
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding ProductName}" />
<Label Text="{Binding Monthly}" />
<Label.FormattedText>
<FormattedString>
<Span Text="Monthly: " />
<Span Text="{Binding Monthly}" />
</FormattedString>
</Label.FormattedText>
</StackLayout>
</ViewCell>
</DataTemplate>

According to Jason's code, you can also try to use StringFormat binding in label, please take a look:
<ListView HasUnevenRows="True" ItemsSource="{Binding products}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Margin="10" Text="{Binding ProductName}" />
<Label Text="{Binding Monthly, StringFormat='Monthly: {0:N}'}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The Screenshot is :

Please check my code it will help you to find multiple bindings to textcell :
XAML Code
<ListView HasUnevenRows="True" ItemsSource="{Binding DemoItems}" SeparatorVisibility="None">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding name}" TextColor="Red" Detail="{Binding details}" DetailColor="Green">
</TextCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Binding ViewModel
this.BindingContext = new TestPageViewModel();
ViewModel Code:
public class TestPageViewModel : PlusDoctor.ViewModels.BaseViewModel
{
private ObservableCollection<DemoDTO> demoItems;
public ObservableCollection<DemoDTO> DemoItems
{
get { return demoItems; }
set
{
demoItems = value;
OnPropertyChanged();
}
}
public TestPageViewModel()
{
DemoItems = new ObservableCollection<DemoDTO>() {
new DemoDTO(){ name="abc", details="ABC details" }, new DemoDTO(){ name="xyz", details="XYZ details" } };
}
}
Data Model
public class DemoDTO
{
public string name { get; set; }
public string details { get; set; }
}
Output :
Hope it will work for you
Thanks

Related

Define listview in resource file which can be used in different places with same model

I have created the following ListView to display data
<dataControls:RadListView x:Name="ItemsListView"
ItemsSource="{Binding StudyResults,Mode=TwoWay}"
MinimumHeightRequest="70"
HeightRequest="{Binding Height}"
SelectedItem="{Binding SelectedItem,Mode=TwoWay}">
<dataControls:RadListView.ItemTemplate>
<DataTemplate>
<listView:ListViewTemplateCell>
<listView:ListViewTemplateCell.View>
<Grid Padding="2,2,2,5" HorizontalOptions="FillAndExpand">
<StackLayout Padding="5,1,1,5" Grid.Column="0">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<maxline:XfMaxLinesLabel MaxLines="2" Text="{Binding BriefTitle, Mode=TwoWay}" Style="{StaticResource ListViewLabelStyle}" TextColor="Black"/>
</Grid>
<StackLayout Padding="0,0,0,0" HorizontalOptions="Fill">
<BoxView Margin="0"
BackgroundColor="Gray"
HeightRequest=".25" />
<Label Text="{Binding ClosestFacility.Name, Mode=TwoWay}" Style="{StaticResource ListViewLabelStyle}"/>
<BoxView Margin="0"
BackgroundColor="Gray"
HeightRequest=".25" />
</StackLayout>
</StackLayout>
</Grid>
</listView:ListViewTemplateCell.View>
</listView:ListViewTemplateCell>
</DataTemplate>
</dataControls:RadListView.ItemTemplate>
</dataControls:RadListView>
I want to reuse this exact same ListView + markup in a other screens/view, just with a different ItemsSource it will be bound to same model. I need to use different item source in different screens.
Is there a better way to create some type of resource so I can reuse this?
As lvan's opinion, you can set DataTemplate in ContentPage.Resource or ResourceDictionary, Some code like this:
<ContentPage.Resources>
<DataTemplate x:Key="Radtemplate">
<listView:ListViewTemplateCell>
<listView:ListViewTemplateCell.View>
<Grid Padding="2,2,2,5" HorizontalOptions="FillAndExpand">
<StackLayout Padding="5,1,1,5" Grid.Column="0">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<maxline:XfMaxLinesLabel MaxLines="2" Text="{Binding BriefTitle, Mode=TwoWay}" Style="{StaticResource ListViewLabelStyle}" TextColor="Black"/>
</Grid>
<StackLayout Padding="0,0,0,0" HorizontalOptions="Fill">
<BoxView Margin="0"
BackgroundColor="Gray"
HeightRequest=".25" />
<Label Text="{Binding ClosestFacility.Name, Mode=TwoWay}" Style="{StaticResource ListViewLabelStyle}"/>
<BoxView Margin="0"
BackgroundColor="Gray"
HeightRequest=".25" />
</StackLayout>
</StackLayout>
</Grid>
</listView:ListViewTemplateCell.View>
</listView:ListViewTemplateCell>
</DataTemplate>
</ContentPage.Resources>
<StackLayout>
<!-- Place new controls here -->
<dataControls:RadListView x:Name="ItemsListView" ItemTemplate="{StaticResource Radtemplate}"
ItemsSource="{Binding StudyResults,Mode=TwoWay}"
MinimumHeightRequest="70"
HeightRequest="{Binding Height}"
SelectedItem="{Binding SelectedItem,Mode=TwoWay}">
</dataControls:RadListView>
</StackLayout>
About DateTemplate detailed info, you can take a look the following article:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/data-templates/creating
Update:
Because RadListView is the third party control, I can not install it, so I use ListView as an example, it is the same, you can take a look how to use TapGestureRecognizer.
Please give the Page an x:name=listviewpage firstly, then
<ContentPage
x:Class="demo3.listviewsample.Page2"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="listviewpage"
mc:Ignorable="d">
<ContentPage.Resources>
<DataTemplate x:Key="datatemplate1">
<ViewCell>
<StackLayout Margin="5" VerticalOptions="FillAndExpand">
<BoxView BackgroundColor="AliceBlue" HeightRequest="30" />
<Label Text="{Binding username}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.command, Source={x:Reference listviewpage}}" CommandParameter="{Binding Email}" />
</Label.GestureRecognizers>
</Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<ListView
HasUnevenRows="True"
ItemTemplate="{StaticResource datatemplate1}"
ItemsSource="{Binding models}" />
</StackLayout>
</ContentPage.Content>
Or you can give ViewCell an x:Name viewcell1 firstly, then:
<ContentPage.Resources>
<DataTemplate x:Key="datatemplate1">
<ViewCell x:Name="viewcell">
<StackLayout Margin="5" VerticalOptions="FillAndExpand">
<BoxView BackgroundColor="AliceBlue" HeightRequest="30" />
<Label Text="{Binding username}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Parent.BindingContext.command, Source={x:Reference viewcell}}" CommandParameter="{Binding Email}" />
</Label.GestureRecognizers>
</Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ContentPage.Resources>
public partial class Page2 : ContentPage
{
public ObservableCollection<model3> models { get; set; }
public RelayCommand1 command { get; set; }
public Page2()
{
InitializeComponent();
models = new ObservableCollection<model3>()
{
new model3(){username="cherry",Email="cherry#outlook.com"},
new model3(){username="barry",Email="barry#outlook.com"}
};
command = new RelayCommand1(obj => method1((string)obj));
this.BindingContext = this;
}
private void method1(string str)
{
Console.WriteLine("the email is {0}",str);
}
}
public class model3
{
public string username { get; set; }
public string Email { get; set; }
}
Here is the Command that inherit ICommand:
public class RelayCommand1 : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public RelayCommand1(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand1(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_execute(parameter);
}
}
When I tap label, it works fine.
You can set DataTemplate as resource, that would work.

How to display Object Details by a reference via a TapGestureRecognizer within a ListView in Xamarin Forms MVVM

I have a ListView displaying multiple cases, and I would like to display its page details when I click on the the Reference from the list. I only get a blank page.
I have tried EventHandler from my XAML and did not work.
<ListView ItemsSource="{Binding GetCases}" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Margin="20,0,20,0">
<Label Text="Case Reference:" FontSize="14" TextColor="Green"/>
<Label FontSize="12" TextColor="Blue" FontAttributes="Bold">
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding Reference}" TextColor="Blue" TextDecorations="Underline"> // I can get the list of References here, but can go to their details
<Span.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_OnTapped" NumberOfTapsRequired="1" />
<TapGestureRecognizer Command="{Binding Path=BindingContext.GoToPageDetails, Source={x:Reference Page}}" /> //This approach takes me to the Page Details, but it is blank
</Span.GestureRecognizers>
</Span>
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
VIEWMODEL
public CasesViewModel(INavigation navigation)
{
IGetDataFromServer cases = new GetDataFromServer();
Navigation = navigation;
GoToPageDetails = new Command(async () => await PageDetails());
GetCases = cases.GetCases(); // This code retrieves my data from server - it Works fine
}
public Command GoToPageDetails { get; set; }
public async Task PageDetails()
{
await Navigation.PushAsync(new CaseDetails());
}
CASE DETAILS XAML
<ListView ItemsSource="{Binding GetCases}" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Margin="20,0,20,0">
<Label Text="PERSONAL DETAILS" FontSize="Large" TextColor="Black" Margin="0,0,0,20" />
<Label Text="Status:" FontSize="14" TextColor="Green"/>
<Label Text="{Binding status}"
FontSize="12" TextColor="Black" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</ DataTemplate>
</ ListView.ItemTemplate>
</ ListView>
CASE DETAILS VIEWMODEL
public CaseDetailsViewModel(INavigation navigation)
{
IGetDataFromServer cases = new GetDataFromServer();
Navigation = navigation;
GetCases = cases.GetCases().FirstOrDefault();
}
public CasesFull GetCases { get; set; }
I can navigate to Case Details page, but it is blank. Maybe I am not passing the reference to the page, or maybe it is something else.
Thanks for your help.
I finally solved the problem.
The issue was in my Case Details View Model, as I had to add the Model in all properties of the Cases Details View model (see below).
<ListView ItemsSource="{Binding GetCases}" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Margin="20,0,20,0">
<Label Text="PERSONAL DETAILS" FontSize="Large" TextColor="Black" Margin="0,0,0,20" />
<Label Text="Status:" FontSize="14" TextColor="Green"/>
<Label Text="{Binding Case.status}"
FontSize="12" TextColor="Black" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</ DataTemplate>
</ ListView.ItemTemplate>
Where Case is my Model.
If anyone wants to display details of an object, this code can be your solution.
Thanks Umar3x for your help.

How to use Checked binding with radio button on item selected of the listview cell with Xamarin Forms?

I am using radio button with listview and on listview item click I want to make radio button checked/selected but unfortunately not able to select the radio button.
<StackLayout VerticalOptions="CenterAndExpand" HeightRequest="200" HorizontalOptions="CenterAndExpand" >
<ListView RowHeight="45" IsVisible="true" ItemsSource="{Binding Items}" BackgroundColor="#5679d1"
SelectedItem="{Binding objItemSelected, Mode=TwoWay}"
HasUnevenRows="true" SeparatorVisibility="Default" SeparatorColor="White">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Label Text="{Binding Questions}" TextColor="Black" Grid.Column="0"
Grid.Row="0" Grid.ColumnSpan="2" HorizontalOptions="Center">
</Label>
<controls:CustomRadioButton HeightRequest="15" HorizontalOptions="End" Checked="{Binding Radiobtn}" IsVisible="true" Grid.Row="0" Grid.Column="3"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
You haven't posted the code for objItemSelected, so you may need to mix it with my answer, but to achieve what you want you should have this:
public object objItemSelected
{
get => null;
set
{
if (value == null)
return;
value.Radiobtn = true;
onPropertyChanged(nameof(objItemSelected));
}
}
According to your description, I guess that you want to have two event, one is ListView Itemselected, another is RadioButton check event in Listview. I do one sample about this, but I add Button in listview, replace RadioButton, you can take a look:
<StackLayout>
<ListView ItemsSource="{Binding models}" RowHeight="40" ItemSelected="ListView_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout HorizontalOptions="StartAndExpand" Orientation="Horizontal">
<Label
x:Name="label1"
Text="{Binding Name}"
TextColor="Black" />
<Button x:Name="btn1" Text="{Binding Description}" Clicked="OnButtonClick" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
private void ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
testmodel model = (testmodel)e.SelectedItem;
//Console.WriteLine(model.Name);
DisplayAlert("Alert", model.Name, "OK");
}
private void OnButtonClick(object sender, EventArgs e)
{
Button btn = (Button)sender;
StackLayout listviewiten = (StackLayout)btn.Parent;
Label label = (Label)listviewiten.Children[0];
DisplayAlert("Alert", label.Text, "OK");
//Console.WriteLine(label.Text);
}

Xamarin.Forms: How to access the collection used in ListView.ItemTemplate within ListView.GroupHeaderTemplate?

I need to access the OnOff property in a Switch within the ListView.GroupHeaderTemplate this property is in the collection used by ListView.ItemTemplate, I have tried in many ways without success, has anyone ever had this problem?
>
<ListView
ItemsSource="{Binding ItemsGrouped}"
GroupShortNameBinding="{Binding Key}"
IsGroupingEnabled="true"
GroupDisplayBinding="{Binding Key}"
x:Name="ListViewAllDevices">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell.View>
<StackLayout>
<Label Text="{Binding Title}"/>
<Label Text="{Binding Description}"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout>
<Label Text="{Binding Key}" />
<Switch IsToggled="{Binding OnOff, Source={x:Reference Name=ListViewAllDevices}}"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
I think you may to change the viewModel .Each groupHeaderTemplate can bind one value. My code as below:
Model
public class Person
{
public string FullName
{
get;
set;
}
public string Address
{
get;
set;
}
}
public class Group : ObservableCollection<Person>
{
public Group(bool key)
{
Key = key;
}
public bool Key
{
get;
private set;
}
}
ItemSource
listView.ItemsSource = new[] {
new Group (true) {
new Person { FullName = "Ass" ,Address = "cole house" }
},
new Group (false) {
new Person { FullName = "Caprice Nave" }
},
new Group (false) {
new Person { FullName = "James Smith", Address = "404 Nowhere Street"},
new Person { FullName = "John Doe", Address = "404 Nowhere Ave" }
}
};
XMAL
<ListView x:Name="listView" IsGroupingEnabled="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout>
<Label Text="{Binding FullName}"/>
<Label Text="{Binding Address}"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout>
<Switch IsToggled="{Binding Key}"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
</ListView>
PS: Once you setListView.GroupHeaderTemplate ,ListView.GroupDisplayBinding will set to null automatically, so you don't need to set ListView.GroupDisplayBinding , but don't forget IsGroupingEnabled="true"

Xamarin Forms with UWP Refresh causes value to disappear

I have a Xamarin Forms application using Android and UWP. Everything works fine under Android but under UWP I have a problem when I want to modify some values displayed on the screen.
Here is my (simplified) ViewModel (using Fody.PropertyChanged) :
public class SalesViewModel : BaseAppViewModel
{
public ObservableCollection<SaleModel> Sales { get; set; }
= new ObservableCollection<SaleModel>();
[DoNotNotify]
public ICommand AddQuantityCommand => new Command<SaleModel>(item =>
{
item.Quantity += 1;
});
}
The BaseAppViewModel implement the INotifyPropertyChanged interface for Fody.PropertyChanged
The (simplified) SaleModel class:
public class SaleModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public double Quantity { get; set; }
}
And the (part of the) XAML which display the list of SaleModel's
<ListView x:Name="ListView" ItemsSource="{Binding Sales, Mode=TwoWay}" SelectedItem="{Binding SelectedSale, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="arrow.png">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.AddQuantityCommand, Source={x:Reference Name=SalesPage}}" CommandParameter="{Binding .}" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Column="1" Text="{Binding Quantity, Mode=OneWay}"
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
When clicking on the Image, the quantity is incremented but the value disappear from the screen under UWP.
I have tested your code and reproduced your issue. And I written the following ViewCell replace yours. Please try to modify your ViewCell.
<ViewCell>
<StackLayout BackgroundColor="#eee"
Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Image Source="time.jpg" HeightRequest="50" WidthRequest="50" >
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding AddQuantityCommand} " CommandParameter="{Binding .}"/>
</Image.GestureRecognizers>
</Image>
<Label Text="{Binding Quantity}"
TextColor="#f35e20" />
<Label Text="{Binding Quantity}"
HorizontalOptions="EndAndExpand"
TextColor="#503026" />
</StackLayout>
</StackLayout>
</ViewCell>
I have upload code sample to github. Please refer to.