I have a Content Page in which I want to show an invoice, for that I have two listviews.
The first one contains the name of the customer, the date and the total cost.
The thing is to get the total cost I have used Shell navigation with parameters and it works fine just not in the listview.
So here is my ViewModel
[QueryProperty(nameof(Total), "total")]
public class InvoiceViewModel : BindableObject
{
string _total;
public string Total
{
get => _total;
set
{
_total = Uri.UnescapeDataString(value ?? string.Empty);
OnPropertyChanged();
}
}
public InvoiceViewModel()
{
_oListOrders = new ObservableCollection<CrOrder>();
GetListCart();
}
private ApiService _apiService = new ApiService();
public List<Invoice> _oListCart = new List<Invoice>();
public ObservableCollection<CrOrder> _oListOrders;
public List<Invoice> ListCart
{
get => _oListCart;
set
{
_oListCart = value;
OnPropertyChanged();
}
}
private async void GetListCart()
{
// call database here
var customerId = Convert.ToInt32(CurrentPropertiesService.GetCustomer());
var customer = await _apiService.GetCustomerById(customerId, CurrentPropertiesService.GetToken());
_oListCart.Add(new Invoice
{
Name = customer.Data.Name,
Date = DateTime.UtcNow,
Total = Convert.ToDecimal(_total),
ListOrders = await GetListOrders()
});
}
private async Task<ObservableCollection<CrOrder>> GetListOrders()
{
// call database here
var cartId = Convert.ToInt32(CurrentPropertiesService.GetCart());
var orders = await _apiService.GetOrdersByCart(cartId, CurrentPropertiesService.GetToken());
ObservableCollection<CrOrder> collection = new ObservableCollection<CrOrder>(orders.Data);
return collection;
}
}
Here is what I have in my View
<ContentPage.Content>
<StackLayout BackgroundColor="#A7A7A7">
<Label Text="{Binding Total}" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"></Label>
<ListView x:Name="ListViewCart" ItemsSource="{Binding ListCart}" HasUnevenRows="True" IsPullToRefreshEnabled="False" >
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:Invoice">
<ViewCell>
<Frame HasShadow="True" Margin="2" BorderColor="Gray">
<Grid Margin="0" HorizontalOptions="FillAndExpand" VerticalOptions="Center" HeightRequest="150" RowSpacing="0" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="Nombre del Cliente:" VerticalOptions="Start"/>
<Label Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding Name}" VerticalOptions="Start"/>
<Label Grid.Row="1" Grid.Column="0" Text="Fecha Compra:" VerticalOptions="Start"/>
<Label Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding Date}" VerticalOptions="Start"/>
<Label Grid.Row="2" Grid.Column="0" Text="Monto Total:" VerticalOptions="Start"/>
<Label Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding Total, StringFormat='{0:N2}€'}" VerticalOptions="Start"/>
<Label Grid.Row="3" Grid.ColumnSpan="3" Text="Detalle Compra" VerticalOptions="Start"/>
<BoxView Grid.Row="4" Grid.ColumnSpan="3" Color="Gray" HeightRequest="2" HorizontalOptions="Fill" />
<Label Grid.Row="5" Grid.Column="0" Text="Nombre" VerticalOptions="Start" TextColor="#9C2424"/>
<Label Grid.Row="5" Grid.Column="1" Text="Monto" VerticalOptions="Start" TextColor="#9C2424"/>
<Label Grid.Row="5" Grid.Column="2" Text="Cantidad" VerticalOptions="Start" TextColor="#9C2424"/>
<StackLayout Grid.Row="6" Grid.ColumnSpan="3" Margin="0" Padding="0">
<ListView x:Name="ListViewOrders" ItemsSource="{Binding ListOrders}" HasUnevenRows="True" IsPullToRefreshEnabled="False" >
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:CrOrder">
<ViewCell IsEnabled="False">
<Grid RowSpacing="0" ColumnSpacing="0" Margin="0" MinimumHeightRequest="50">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="{Binding Reference}" TextColor="Black" VerticalOptions="Center" FontSize="12" />
<Label Grid.Row="0" Grid.Column="1" Text="{Binding Price, StringFormat='{0:N2}€'}" TextColor="Black" VerticalOptions="End" FontSize="12" />
<Label Grid.Row="0" Grid.Column="2" Text="{Binding Quantity}" TextColor="Black" VerticalOptions="End" FontSize="12"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>...
And on my ContentPage I don't have anything
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class InvoicePage : ContentPage
{
public InvoicePage()
{
InitializeComponent();
//BindingContext = new InvoiceViewModel();
}
}
So on my View I have put a label to check what I thought was happening. So the label shows right the total but when I use the ListView binging it doesn't work I don't know why it is null there.
As you can see the label works fine but where it sais "Monto Total" it shows nothing. Please help I don't know what is going on. Thanks.
EDIT
I tried naming the Total property different and then when I add my Invoice entity to my list I do this
Total = Convert.ToDecimal(TotalCart),
But it isn't working eitherway. I don't know why the first time it returns the value fine but the second it doesn't.
After debbuging I have realized when getting the total property that the first time when GetListCart is being called the value is null and the second time, when the label text is set it returns the correct value. Why is this happening?
Related
I have a CarouselView in which inside the DataTemplate I have a CollectionView, whose ItemsSource property is binded to an Observablecollection, in which elements are added only when the user presses on a button. The problem is that this CollectionView is always empty, I can't see any items
<CarouselView
x:Name="CollectionDiary"
RelativeLayout.YConstraint="{ConstraintExpression
Type=Constant,
Constant=242}"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,
Property=Width,
Factor=1}"
PeekAreaInsets="20"
HeightRequest="330">
<CarouselView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" SnapPointsType="MandatorySingle" SnapPointsAlignment="Center" ItemSpacing="5"/>
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<DataTemplate>
<yummy:PancakeView CornerRadius="22" BackgroundColor="Transparent">
<yummy:PancakeView.Shadow>
<yummy:DropShadow Color="#000000" Offset="2,2" BlurRadius="5" Opacity="0.8" />
</yummy:PancakeView.Shadow>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="15"/>
<RowDefinition Height="45"/>
<RowDefinition Height="268"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.Background>
<LinearGradientBrush StartPoint="1,0" EndPoint="1,1">
<GradientStop Color="Black" Offset="0" />
<GradientStop Color="#4191cc" Offset="1.0" />
</LinearGradientBrush>
</Grid.Background>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding Data}" FontSize="14" TextColor="Gray" VerticalTextAlignment="End" Margin="10,5,10,0"/>
<Label Grid.Row="1" Grid.Column="1" Text="{Binding Orario}" FontSize="14" TextColor="Gray" VerticalTextAlignment="End" Margin="10,0"/>
<Image Grid.Row="0" Grid.RowSpan="3" Grid.Column="0" Margin="15,15,0,0" Source="{Binding Umore}" HeightRequest="60"/>
<Label Grid.Row="2" Grid.Column="1" Text="{Binding TipoUmore}" FontAttributes="Bold" TextColor="{Binding ColoreUmore}" FontSize="22" Margin="10,0" VerticalOptions="Start"/>
<Label Grid.Row="3" Grid.Column="1" TextColor="White" FontSize="16" Text="{Binding Nota}" Margin="10,0" VerticalOptions="Start" HorizontalTextAlignment="Start"/>
<CollectionView
Grid.Row="2"
Grid.Column="0"
Margin="10"
SelectionMode="None"
ItemsSource="{Binding listEmojiDiarioView}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" VerticalItemSpacing="10" HorizontalItemSpacing="10"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Grid.Row="0" Grid.Column="0" Source="{Binding SourceImg}"/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding id}" TextColor="White" FontSize="13"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</yummy:PancakeView>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
c#
ObservableCollection<HumorDiary> listDiario = new ObservableCollection<HumorDiary>();
ObservableCollection<IconDiary> listEmojiDiarioView = new ObservableCollection<IconDiary>();
private async void BTSaveDiary_Clicked(object sender, EventArgs e)
{
HumorDiary hum = new HumorDiary
{
Nota = TestoDiary.Text,
Data = DateTime.Today.Day.ToString() + " " + Mese,
Orario = DateTime.Now.TimeOfDay.ToString().Remove(5,DateTime.Now.TimeOfDay.ToString().Length-5),
Anno = DateTime.Now.Year.ToString(),
Umore = "Smile" + NUmore + ".png",
TipoUmore = tipoUmore,
ColoreUmore = Colore,
IconTot = NIcon,
};
string[] srListIcon = NIcon.Split(new string[] { set.Tag }, StringSplitOptions.RemoveEmptyEntries);
foreach (string sr in srListIcon)
{
string src = sr.Substring(0, 9);
string id = sr.Substring(9, sr.Length-9);
IconDiary ic = new IconDiary
{
SourceImg = src,
id = id,
};
listEmojiDiarioView.Add(ic);
}
listDiario.Insert(0, hum);
CollectionDiary.ItemsSource = listDiario.Take(3);
}
Since the BindingContext inside a CarouselView changes and takes it ItemsSource as a BindingContext, you need to explicitly specify your BindingContext in case of your CollectionView. I guess if you look at the logs you will find some binding error/failure because it was looking for an IEnumerable property with the name of listEmojiDiarioView inside listDiario which obviously is not there.
One way you can overcome this is by using a reference of your page as binding source:
<ContentPage x:Name="pageref" ...
<CollectionView ...
ItemsSource="{Binding Source={x:Reference pageref}, Path=BindingContext.listEmojiDiarioView}">
listEmojiDiarioView must be a property not a field
If it is not working check weather you have implemented the INotifyPropertyChanged on your ObservableCollection used in binding or no.
Omitted code remains unchanged.
Related documentation
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/data-binding-basics
I am currently trying to build two separate collection views on the same page in Xamarin. I keep getting the error that content is set more than once and also that I've set the content binding more than once. How do I add different bindings to two separate collection views on the same page?
ConsumerOrders.xaml page:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage 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" xmlns:viewmodels="clr-namespace:Shared.ViewModel"
mc:Ignorable="d"
x:Class="Shared.consumerOrders">
<ContentPage.BindingContext>
<viewmodels:AddedServicesViewModel />
</ContentPage.BindingContext>
<d:ContentPage.BindingContext>
<viewmodels:PastOrderViewModel />
</d:ContentPage.BindingContext>
<ScrollView>
<CollectionView ItemsSource="{Binding ViewAddedServices}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="4"/>
<!--0-->
<RowDefinition Height="30"/>
<!--1-->
<RowDefinition Height="20"/>
<!--2-->
<RowDefinition Height=".25"/>
<!--3-->
<RowDefinition Height="4"/>
<!--4-->
<RowDefinition Height="Auto"/>
<!--5-->
<RowDefinition Height="Auto"/>
<!--6-->
<RowDefinition Height=".25"/>
<!--7-->
<RowDefinition Height="Auto"/>
<!--8-->
<RowDefinition Height="Auto"/>
<!--9-->
<RowDefinition Height=".25"/>
<!--10-->
<RowDefinition Height="Auto"/>
<!--11-->
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="4"/>
</Grid.ColumnDefinitions>
<Label Text="Services added" FontAttributes="Bold" TextColor="#F65506" Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="2" VerticalTextAlignment="End" HorizontalTextAlignment="Start" FontSize="18"/>
<Label Grid.Column="1" Grid.Row="7" BackgroundColor="#707070" Grid.ColumnSpan="3"/>
<!--This is a line-->
<BoxView BackgroundColor="#F0F0F0" Grid.Row="9" Grid.Column="1" Grid.ColumnSpan="3" CornerRadius="22"/>
<Label Grid.Column="1" Grid.Row="9" Padding="10" TextColor="Black" FontSize="18" Text="{Binding BusinessName}" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand" Grid.ColumnSpan="2"/>
<Label Grid.Column="3" Grid.Row="9" Padding="0,0,20,0" TextColor="#F65506" FontAttributes="Bold" FontSize="18" Text="View" VerticalOptions="CenterAndExpand" HorizontalOptions="EndAndExpand" Grid.ColumnSpan="2"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<CollectionView ItemsSource="{Binding ViewQuoteStatus}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="4"/>
<!--0-->
<RowDefinition Height="30"/>
<!--1-->
<RowDefinition Height="20"/>
<!--2-->
<RowDefinition Height=".25"/>
<!--3-->
<RowDefinition Height="4"/>
<!--4-->
<RowDefinition Height="Auto"/>
<!--5-->
<RowDefinition Height="Auto"/>
<!--6-->
<RowDefinition Height=".25"/>
<!--7-->
<RowDefinition Height="Auto"/>
<!--8-->
<RowDefinition Height="Auto"/>
<!--9-->
<RowDefinition Height=".25"/>
<!--10-->
<RowDefinition Height="Auto"/>
<!--11-->
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="4"/>
</Grid.ColumnDefinitions>
<Label Text="Past Orderrs" FontAttributes="Bold" TextColor="#F65506" Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="2" VerticalTextAlignment="End" HorizontalTextAlignment="Start" FontSize="18"/>
<Label Grid.Column="1" Grid.Row="7" BackgroundColor="#707070" Grid.ColumnSpan="3"/>
<!--This is a line-->
<BoxView BackgroundColor="#F0F0F0" Grid.Row="9" Grid.Column="1" Grid.ColumnSpan="3" CornerRadius="22"/>
<Label Grid.Column="1" Grid.Row="9" Padding="10" TextColor="Black" FontSize="18" Text="{Binding BusinessName}" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand" Grid.ColumnSpan="2"/>
<Label Grid.Column="3" Grid.Row="9" Padding="0,0,20,0" TextColor="#F65506" FontAttributes="Bold" FontSize="18" Text="View" VerticalOptions="CenterAndExpand" HorizontalOptions="EndAndExpand" Grid.ColumnSpan="2"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ScrollView>
</ContentPage>
AddedServicesViewModel.cs :
using Shared.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
namespace Shared.ViewModel
{
class AddedServicesViewModel
{
readonly IList<AddedServiceStatus> source;
public ObservableCollection<AddedServiceStatus> ViewAddedServices { get; private set; }
public AddedServicesViewModel()
{
source = new List<AddedServiceStatus>();
CreateAddedServicesCollection();
}
void CreateAddedServicesCollection()
{
source.Add(new AddedServiceStatus
{
BusinessName = "Duck's Duct Cleaning"
});
source.Add(new AddedServiceStatus
{
BusinessName = "Rodney's Home Repair"
});
ViewAddedServices = new ObservableCollection<AddedServiceStatus>(source);
}
}
}
PastOrderViewModel :
using Shared.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
namespace Shared.ViewModel
{
class PastOrderViewModel
{
readonly IList<PastOrderStatus> source;
public ObservableCollection<PastOrderStatus> ViewPastOrders { get; private set; }
public PastOrderViewModel()
{
source = new List<PastOrderStatus>();
CreatePastOrderCollection();
}
void CreatePastOrderCollection()
{
source.Add(new PastOrderStatus
{
BusinessName = "Karen's Magnificent Dog Grooming"
});
source.Add(new PastOrderStatus
{
BusinessName = "Harry's In Home Haircuts"
});
source.Add(new PastOrderStatus
{
BusinessName = "Shelly's Floral Arrangements"
});
ViewPastOrders = new ObservableCollection<PastOrderStatus>(source);
}
}
}
You could also bind a ViewModel to each CollectionView separately.
like:
<CollectionView ItemsSource="{Binding ViewAddedServices}">
<CollectionView.BindingContext>
<viewmodels:AddedServicesViewModel/>
</CollectionView.BindingContext>
...
</CollectionView>
<CollectionView ItemsSource="{Binding ViewPastOrders}">
<CollectionView.BindingContext>
<viewmodels:PastOrderViewModel/>
</CollectionView.BindingContext>
...
</CollectionView>
You can't have two ViewModels binding to a SingleView. (as far a I know)
I see that the DataTemplate in both Collections are the same..... there are many ways to refactor....
You could create two CustomView one with the AddedServicesViewModel and the other with PastOrderViewModel
You can merge the two ViewModels into one, and create a CustomView that it's the collection.
Another thing that I see that It could not work is that you can't have a more than one View Nested in a ScrollView
<ScrollView>
<StackLayout> /* Or any other Layout, Grid, Absolute, Flex etc... */
</StackLayout>
</ScrollView>
Another thing is that a CollectionView with orientation vertical in a ScrollView maybe it won't behave as you expect, since the CollectionView with orientation vertical it has Scroll
Two CollectionViews with orientation vertical in the same View it should have a Height, I would do something like this
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<CollectionView Grid.Row="0" ItemsSource="{Binding ViewQuoteStatus}"> ... </CollectionView>
<CollectionView Grid.Row="1" ItemsSource="{Binding ViewAddedServices}"> ... </CollectionView>
</Grid>
or if you create a custom view (custom control)
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<MyCustomCollectionView Grid.Row="0" ItemsSource="{Binding ViewQuoteStatus}"> ... </MyCustomCollectionView>
<MyCustomCollectionView Grid.Row="1" ItemsSource="{Binding ViewAddedServices}"> ... </MyCustomCollectionView>
</Grid>
In Xamarin forms with MVVM ; I'm using observable collection for listing my items in the listview. It worked fine. In my listview i have a Label and i need to change the Label value when the user click on that selected list item. It's also working fine. But the problem is, Selected list item Label value changed only after i scroll the listview.
I need to change the selected list item's Label value On time.
Here is my code:
Xaml
<ListView x:Name="Listitem" Grid.Row="2" Grid.ColumnSpan="2" ItemsSource="{Binding States,Mode=TwoWay}" SelectedItem="{Binding YourSelectedItem,Mode=TwoWay}" VerticalOptions="FillAndExpand" HasUnevenRows="true" CachingStrategy="RecycleElement" BackgroundColor="White" >
<ListView.Header>
<Grid BackgroundColor="{StaticResource Accent}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Text="Country Code" HorizontalOptions="Center" VerticalOptions="Center" TextColor="{StaticResource Primary}" />
<Label Grid.Column="1" Text="Name" HorizontalOptions="Center" TextColor="{StaticResource Primary}" />
<Label Grid.Column="2" Text="Capital" HorizontalOptions="Center" TextColor="{StaticResource Primary}" />
</Grid>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid VerticalOptions="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Text="{Binding abbr}" Margin="5" HorizontalOptions="Center" VerticalOptions="Center" FontSize="18" TextColor="{StaticResource Primary}" />
<Label Grid.Column="1" Text="{Binding name}" Margin="5" HorizontalTextAlignment="Start" VerticalOptions="Center" FontSize="18" LineBreakMode="WordWrap" TextColor="{StaticResource Primary}"/>
<Label Grid.Column="2" Text="{Binding capital}" Margin="5" HorizontalTextAlignment="Start" VerticalOptions="Center" FontSize="18" LineBreakMode="WordWrap" TextColor="{StaticResource Primary}"/>
<controls:CheckBox Grid.Column="3" Margin="0, 0, 0, 0" CheckedChanged="Handle_CheckedChanged" BindingContext="{Binding .}" BackgroundColor="Transparent" WidthRequest="40" HeightRequest="30" IsVisible="True" />
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And this is my View model for selected list item;
public TodoItem YourSelectedItem
{
get
{
return _yourSelectedItem;
}
set
{
_yourSelectedItem = value;
_yourSelectedItem.abbr = "Tapped";
OnPropertyChanged("YourSelectedItem");
}
}
Item source property;
private ObservableCollection<TodoItem> _States;
public ObservableCollection<TodoItem> States
{
get { return _States; }
set { _States = value; OnPropertyChanged("States"); }
}
The class TodoItem needs to implement the interface INotifyPropertyChanged and the property abbr needs to be implemented as something like blow:
public string abbr {
get
{
return _abbr;
}
set
{
if (_abbr != value) {
_abbr = value;
OnPropertyChanged("abbr");
}
}
}
I am currently working on a Xamarin CrossPlatform project and have implemented a Listview bound to an ObservableCollection. Everything works out fine until I remove an Item from the ListView. The images in the follow up items within the ListView disappear randomly - not all of them and a different amount of them every time. I guess it has something to do with the MemoryStream, but what do I have to change? Here´s the relevant part of my Model that is bound to the ListView:
public string ImageBase64
{
get
{
return imagebase64;
}
set
{
if (imagebase64 != value)
{
imagebase64 = value;
OnPropertyChanged(nameof(ImageBase64));
OnPropertyChanged(nameof(ImageSource));
}
}
}
public ImageSource ImageSource
{
get
{
if (!string.IsNullOrEmpty(imagebase64))
{
return ImageSource.FromStream(() => new MemoryStream(Convert.FromBase64String(imagebase64)));
}
else
{
return null;
}
}
}
Here´s the relevant XAML:
<ListView x:Name="listView" Margin="20" ItemsSource="{Binding}" ItemSelected="OnListItemSelected" HasUnevenRows="True" SeparatorColor="{StaticResource primaryGreen}" SeparatorVisibility="Default">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Margin="0,5,0,5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="45" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Grid.RowSpan="3" Margin="-2,-2,-2,-2" Source="{Binding ImageSource}" HorizontalOptions="Start" VerticalOptions="Center" Aspect="AspectFill"/> <!-- This is the displayed Image -->
<Label Margin="10,0,0,0" Grid.Column="1" Grid.Row="0" FontAttributes="Bold" FontSize="18" TextColor="{StaticResource primaryGreen}" Text="{Binding VorNachname}" VerticalTextAlignment="Start" HorizontalTextAlignment="Start"/>
<Label Margin="10,0,0,0" Grid.Column="1" Grid.Row="1" Text="{Binding MediumSelected.Wert, StringFormat='via {0}'}" HorizontalOptions="FillAndExpand" VerticalTextAlignment="Start" HorizontalTextAlignment="Start"/>
<StackLayout Margin="10,0,0,0" Grid.Column="1" Grid.Row="2" Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label Text="{Binding Alter,StringFormat='Alter: {0}'}" VerticalTextAlignment="Start" HorizontalTextAlignment="Start" HorizontalOptions="Start"/>
</StackLayout>
<StackLayout Margin="0,0,0,-5" Grid.Column="2" Grid.RowSpan="3" Orientation="Vertical" HorizontalOptions="End" VerticalOptions="End">
<Button WidthRequest="40" HeightRequest="40" BackgroundColor="White" BorderWidth="0" BorderColor="White" Image="socialmedia_18.png" Clicked="OnChangeClicked" CommandParameter ="{Binding}" VerticalOptions="EndAndExpand" />
<Button Margin="0,-15,0,0" WidthRequest="40" HeightRequest="40" BackgroundColor="White" BorderColor="White" Image="cancel_18.png" Clicked="OnDeleteClicked" CommandParameter ="{Binding}" VerticalOptions="End" />
</StackLayout>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
...and the Code behind:
async void OnDeleteClicked(object sender, EventArgs e)
{
Helper.TrackEvent("PeopleList_OnDeleteClicked");
//Get selected Person
Person person = (Person)((Button)sender).CommandParameter;
//Remove from Model
DBHelper.DBModel.People.Remove(person);
//Update database
App.Database.UpdateWithChildren(DBHelper.DBModel);
}
EDIT:
Resizing the images does not help, same problem. I tried it by binding a testvariable ImageSourceThumb to the ListViewItemImage:
public ImageSource ImageSourceThumb
{
get
{
if (!string.IsNullOrEmpty(imagebase64))
{
return ImageSource.FromStream(() => new MemoryStream(ImageResizer.ResizeImage(Convert.FromBase64String(imagebase64), 64, 64)));
}
else
{
return null;
}
}
}
I had a similar problem. When I loaded or updated my listview not all the images showed up.
I fixed my problem resizing the images. Huge images gived me a outofmemory exception. Resizing those images to a smaller resolution fixed these problems.
I want to assign the values of the findFamily object to the different TextBox(s) i tried the following code but it's not working would you please suggest me a better way. Thanks in advance.
private void Search_Click(object sender, RoutedEventArgs e)
{
if (SearchFamilyMemberId.Text.Trim() != "")
{
SITDataDataContext con = new SITDataDataContext();
List<Family> findFamily = (from s in con.Families where s.FamilyMemberId.Equals(SearchFamilyMemberId.Text.Trim()) select s).ToList();
if (findFamily.Any())
{
FamilyMemberId.Text = findFamily[0];
FirstName.Text = findFamily[1];
LastName.Text = findFamily[2];
if (findFamily[3]=="Male")
{
Male.IsChecked = true;
}
else
{
Female.IsChecked = true;
}
Phone.Text = findFamily[4];
Address.Text = findFamily[5];
}
else
{
MessageBox.Show("Family Id not found!");
}
}
else
{
MessageBox.Show("Invalid Id!");
}
}
here is my xamal code
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="1" Grid.Column="0" Content="Family Member ID:"/>
<Label Grid.Row="2" Grid.Column="0" Content="First Name:"/>
<Label Grid.Row="3" Grid.Column="0" Content="Last Name:"/>
<Label Grid.Row="4" Grid.Column="0" Content="Gender:"/>
<Label Grid.Row="5" Grid.Column="0" Content="Phone:"/>
<Label Grid.Row="6" Grid.Column="0" Content="Address:"/>
<CheckBox Name="ColonyResident" Content="Colony Resident" Grid.Row="0" Grid.Column="0" Margin="5" Checked="ColonyResident_Checked" Unchecked="ColonyResident_Unchecked"/>
<TextBox Name="SearchFamilyMemberId" IsEnabled="False" SelectionChanged="FamilyMemberId_SelectionChanged" Grid.Row="0" Grid.Column="1" Margin="3"/>
<TextBox Name="FamilyMemberId" IsEnabled="False" Grid.Row="1" Grid.Column="1" Margin="3" Grid.ColumnSpan="2"/>
<TextBox Name="FirstName" Grid.Row="2" Grid.Column="1" Margin="3" Grid.ColumnSpan="2"/>
<TextBox Name="LastName" Grid.Row="3" Grid.Column="1" Margin="3" Grid.ColumnSpan="2"/>
<RadioButton Name="Male" Grid.Row="4" Grid.Column="1" Margin="3" Content="Male" />
<RadioButton Name="Female" Grid.Row="4" Grid.Column="2" Margin="3" Content="Female" />
<TextBox Name="Phone" Grid.Row="5" Grid.Column="1" Margin="3" Grid.ColumnSpan="2"/>
<TextBox Name="Address" Grid.Row="6" Grid.Column="1" Margin="3" Grid.ColumnSpan="2" TextWrapping="Wrap"/>
<Button Name="Search" IsEnabled="False" Grid.Row="0" Grid.Column="2" Margin="3" MinWidth="100" MinHeight="25" HorizontalAlignment="Center" Content="Search" Click="Search_Click"/>
<Button IsDefault="True" Grid.Row="7" Grid.Column="1" Margin="3" MinWidth="100" MinHeight="25" HorizontalAlignment="Center" Content="Add" Click="Add_Click"/>
<Button Grid.Row="7" Grid.Column="2" Margin="3" MinWidth="100" MinHeight="25" HorizontalAlignment="Center" Content="Clear" Click="Clear_Click"/>
</Grid>
Why don't you use data binding?
For each of the text boxes that you have, bind your TextBox.Text to its corresponding property in the view model, something like this:
<TextBox Text={Binding FirstName} />
Then, assign your FirstName, LastName...etc. properties to values and raise INotifyPropertyChanged.PropertyChanged for each of the properties (your view model should implement INotifyPropertyChanged) and your view (i.e. UI) should get updated.
I don't agree with any of the answers posted here. The question doesn't seem to be correct.
If you have a list of Family members. Then how can you show it as a single item. How do you know which item you want to display.
Hence my suggestion is to use a listbox and using data binding, create a view to display the current selected Family member's data in that view.
use foreach loop through list as:
foreach(var a in findFamily)
{
txtbox.text=a[0].tostring();
txtbox2.text=a[1].tostring();
}
or use:
txtbox.text = findFamily.Select(a => a[0].ToString()).FirstOrDefault().ToString();