I have a weird exception where the Compiler tells me that the Specified cast is not valid even though what im doing is very Simple.
I have a ListView binded to a ObservableCollection. And inside my Listview is a ViewCell with a Grid. Xamarin.Forms Version 2.3.2.127
<ListView ItemsSource="{Binding GiftCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="{Binding GiftName}"/>
<Label Grid.Row="1" Grid.Column="0" Text="{Binding GiftDescription}"/>
<Image Grid.Row="0" Grid.RowSpan="2" Grid.Column="1" Source="{Binding GiftImage}"/>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Model:
public class GiftModel {
public string GiftName { get; set; }
public string GiftDescription { get; set; }
public ImageSource GiftImage { get; set; }
}
ViewModel:
public class NextRoundViewModel : BaseViewModel {
public NextRoundViewModel(ApplicationModel applicationModel) {
ApplicationModel = applicationModel;
Initialize();
}
public ApplicationModel ApplicationModel { get; set; }
public ObservableCollection<GiftModel> GiftCollection { get; set; }
public string CurrentRound => "Runde 2";
private void Initialize() {
GiftCollection = new ObservableCollection<GiftModel> {
new GiftModel {
GiftName = "100 Punkte",
GiftDescription = "Test",
GiftImage = ImageSource.FromFile("Star.png"),
},
new GiftModel {
GiftName = "200 Punkte",
GiftDescription = "Test",
GiftImage = ImageSource.FromFile("Star.png"),
},
new GiftModel {
GiftName = "300 Punkte",
GiftDescription = "Test",
GiftImage = ImageSource.FromFile("Star.png"),
},
};
}
}
So ive tried everything but if i use for example a TextCell the Exception is gone.
System.InvalidCastException: Specified cast is not valid. It is just weird because i dont know where to look for the Bug.
I had this problem too, the issue was with the xaml. I had a <StackLayout> inside of my <DataTemplate>, you can remove your <Grid> and that should solve the problem.
Did you know that you could replace the <Grid> with an <ImageCell>:
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell
Text="{Binding GiftName}"
Detail="{Binding GiftDescription}"
ImageSource="{Binding GiftImage}">
</ImageCell>
</DataTemplate>
</ListView.ItemTemplate>
You can place inside with .
Something like this
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
Remove the <ViewCell> from the DataTemplate. This should resolve the error. <Grid> will work in <CollectionView>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
:
:
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
The following code gives the same exception, may help someone:
using ListView or CollectionView but in the ItemTemplate I use BindableLayout.ItemTemplate instead CollectionView.ItemTemplate
<CollectionView Grid.Row="0" ItemsSource="{Binding SummaryInfos}">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" />
</CollectionView.ItemsLayout>
<!-- this code gives the same exception -->
<!-- must use CollectionView instead BindableLayout -->
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding SomeText}"/>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</CollectionView>
Related
I just can't get my head around it. My brain melts trying to understand how to bind to a parent's context.
So here I have a (relatively) simple object:
public class BinDefinition
{
public string labelAdresse { get; set; }
public InventoryItem inventoryItem { get; set; }
public List<BinContent> binContents { get; set; }
public List<InventoryProduct> productsinBinContent { get; set; }
public bool showDeleteButton { get; set; }
public bool showTransferButton { get; set; }
public ObservableCollection<ListItem> Items { get; set; }
}
then I have my view model that has two of these bindefinitions.
public class viewModel
{
public binDefinition primaryBin { get; set; }
public binDefinition secondaryBin { get; set; }
}
And finally, the relevant xaml part:
<ListView x:Name="ItemsListView" Grid.Row="1"
ItemsSource="{Binding Items}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
RefreshCommand="{Binding LoadItemsCommand}"
IsPullToRefreshEnabled="true"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
CachingStrategy="RecycleElement"
ItemTapped="ItemsListView_ItemTapped"
Grid.RowSpan="2"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="LightBlue">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="60"></ColumnDefinition>
<ColumnDefinition Width="60"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Text="{Binding Name}" LineBreakMode="WordWrap" FontAttributes="Bold" FontSize="16" HorizontalOptions="FillAndExpand" />
<Label Grid.Row="1" Text="{Binding EANReference}" LineBreakMode="WordWrap" TextColor="Gray" FontSize="16" HorizontalOptions="FillAndExpand" />
<Label Grid.Row="2" Text="{Binding QuantityDisplay}" LineBreakMode="WordWrap" TextColor="DarkBlue" FontSize="16" HorizontalOptions="FillAndExpand" />
<Button Grid.RowSpan="3" Grid.Column="1" Text="Info" Clicked="btnInfos_Clicked" CommandParameter="{Binding EAN}"/>
<Button Grid.RowSpan="3" Grid.Column="2" Text="Del" Clicked="btnDel_Clicked" CommandParameter="{Binding Id}" IsVisible="{Binding BindingContext.primaryBin.showDeleteButton, Source={x:Reference Inv2PageMainContent}}"/>
<Button Grid.RowSpan="3" Grid.Column="2" Text="Tra" Clicked="btnTransfer_Clicked" CommandParameter="{Binding Id}" IsVisible="{Binding BindingContext.primaryBin.showTransferButton, Source={x:Reference Inv2PageMainContent}}"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I am trying to bind the two final button so that the show up or hide depending on the state of the boolean available in BinDefinition. But at that point, the datacontext of said button is a ListItem (from the Items in the viewModel).
I just don't know how to call back the direct parent to use its property.
edit: apologies, it seems I failed to provide sufficient informations.
the inv2MainpageContent is the name of the page. x:Name = inv2MainPageContent.
The BindingContext of the page is an instance of the viewModel. That viewModel contain two binDefinitions. And in that bin Definition are multiple properties. The three that are important to me are the bool ShowDelete/ShowTransfer and the Collection Items.
The List view in my view has dug into the primaryBin and uses "primaryBin.Items" as its ItemSource. The thing is, I would like to bind the visibility of these objects to the the primaryBin.ShowDelete/ShowTransfer.
i'm trying to bind a command to a button inside a listView, but without success. I follow all other answers posted here, like this one:
Xamarin Forms Button Command binding inside a ListView
The actual result is that nothing happens. A thing that i notice is that visual studio, when i type after x:Reference suggests me just GridWebcam, like if it doesn't see other reference elements. What can i do?
Here my code:
<ContentPage
...
x:Name="WebcamList">
<ContentPage.Resources>
...
<ContentPage.Content>
<ListView ItemsSource="{Binding ListOfWebcam}"
SeparatorVisibility="None"
CachingStrategy="RecycleElement"
RowHeight="250"
VerticalOptions="FillAndExpand"
x:Name="ListWebcam">
<ListView.Header>
<StackLayout x:Name="HeaderStackLayout"
Padding="5,25,0,30"
Orientation="Horizontal"
HorizontalOptions="FillAndExpand">
<Label x:Name="LabelHeader"
Text="Webcam:"
FontSize="Large"
FontAttributes="Bold"
TextColor="{x:Static statics:Palette.PrimaryColor}"
VerticalOptions="Center"
HorizontalOptions="Start" Margin="10,0,0,0"/>
</StackLayout>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<controls:ExtendedViewCell IsEnabled="False">
<controls:ExtendedViewCell.View>
<Grid x:Name="GridWebcam">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Frame Grid.Column="1"
Grid.RowSpan="2"
CornerRadius="20"
BackgroundColor="{x:Static statics:Palette.PrimaryColor}"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
HasShadow="True"
Margin="5,10">
<StackLayout>
<Label Text="{Binding t_str_vid,Converter={StaticResource WebcamNameConverter}}"
FontSize="Medium"
TextColor="White"
FontAttributes="Bold"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
</Label>
<Label TextColor="White"
FontSize="Medium"
Text="{Binding direzione,Converter={StaticResource DirectionToStringConverter}}"/>
<StackLayout Orientation="Horizontal">
<ffimageloading:CachedImage LoadingPlaceholder="Rolling.gif"
DownsampleToViewSize="False"
VerticalOptions="FillAndExpand"
HorizontalOptions="StartAndExpand"
Source="{Binding image1}"/>
<iconize:IconButton Text="fas-play-circle"
FontSize="50"
HorizontalOptions="EndAndExpand"
VerticalOptions="EndAndExpand"
TextColor="White"
Command="{Binding BindingContext.OpenVideoWebcamCommand, Source={x:Reference WebcamList}}"
CommandParameter="{Binding .}"
BackgroundColor="Transparent"/>
</StackLayout>
</StackLayout>
</Frame>
</Grid>
</controls:ExtendedViewCell.View>
</controls:ExtendedViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
```
public class WebcamListViewModel : BaseViewModel
{
public ICommand OpenVideoWebcamCommand { set; get; }
private List<Webcam> _ListOfWebcam { get; set; }
public List<Webcam> ListOfWebcam
{
get { return _ListOfWebcam; }
set
{
_ListOfWebcam = value;
OnPropertyChanged();
}
}
private Task DownloadFramesTask;
CancellationTokenSource tokenSourceDownloadFrames = new CancellationTokenSource();
CancellationToken cancellationTokenDownloadFrames;
public WebcamListViewModel(INavigationService navigationService, IApiAutostradeManagerFactory apiAutostradeManagerFactory) : base(navigationService,apiAutostradeManagerFactory)
{
OpenVideoWebcamCommand = new Command<Webcam>(async (webcam) => {
await navigationService.NavigateAsync(Locator.WebcamVideoPopUpPage);
Messenger.Default.Send(new InfoWebcamVideoMessage(webcam.c_mpr, webcam.c_uuid, webcam.t_str_vid));
});
}
Well it could be related to this mysterious controls:ExtendedViewCell of yours :)
Also did you disable the ListView selection: <ListView ... SelectionMode="None" /> ?
As Roubachof said that I don't know if it is related to controls:ExtendedViewCell,please check if you have binding BindingContext, then you can take a look the following code:
<StackLayout>
<ListView x:Name="listview1" ItemsSource="{Binding persons}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Id}" />
<Label Text="{Binding name}" />
<Button
Command="{Binding BindingContext.command, Source={x:Reference listview1}}"
CommandParameter="{Binding Id}"
Text="Delete item" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
public partial class Page1 : ContentPage
{
public ObservableCollection<person> persons { get; set; }
public RelayCommand1 command { get; set; }
public Page1 ()
{
InitializeComponent ();
persons = new ObservableCollection<person>();
for(int i =0;i<20;i++)
{
person p = new person()
{
Id = i,
name = "cherry" + i
};
persons.Add(p);
command = new RelayCommand1(obj => method1((int)obj));
}
this.BindingContext = this;
}
public void method1(int Id)
{
persons.RemoveAt(Id);
//IEnumerable<person> list = persons.Where(x => x.Id == Id);
//foreach (person m in list)
//{
//}
}
}
public class person
{
public int Id { get; set; }
public string name { get; set; }
}
I have created a ViewCell that can be reused throughout my project:
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:C="using:****.Converters"
x:Class="****.Views.Settings.SettingCell">
<Grid BackgroundColor="{StaticResource BlueGray}">
<Grid.Resources>
<C:DebugConverter x:Key="debugConverter"/>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding ImageSource}"/>
<Label Grid.Column="1"
Text="{Binding Path=Title,
Converter={StaticResource debugConverter},
FallbackValue=Title}"
HorizontalOptions="Start"
VerticalOptions="Center"/>
</Grid>
</ViewCell>
Here is ViewModel:
public partial class SettingCell : ViewCell
{
public SettingModel Model
{
get
{
return model;
}
set
{
model = value;
BindingContext = value;
}
}
public SettingModel model;
public static readonly BindableProperty SettingTypeProperty = BindableProperty.Create(nameof(SettingType), typeof(Setting), typeof(SettingModel));
public Setting SettingType
{
get
{
return (Setting)GetValue(SettingTypeProperty);
}
set
{
SetValue(SettingTypeProperty, value);
}
}
public SettingCell()
{
InitializeComponent();
switch (SettingType)
{
case Setting.Name:
Model = new NameSettingModel();
break;
default:
throw new NotImplementedException("Unknown Setting Type");
}
}
}
The Model is a subtype of an abstract class that is selected through a class discriminator. The class is very simple at this point since I'm just getting it wired up, but here is the base class along with on sub-type:
public class NameSettingModel : SettingModel
{
public NameSettingModel()
{
Title = "Name";
IconSource = "";
}
public override void ClickCommand()
{
Debug.WriteLine("Setting Command Run");
}
}
public abstract class SettingModel : BindableBase
{
public string Title
{
get
{
return GetProperty<string>();
}
set
{
SetProperty(value);
}
}
public string IconSource
{
get
{
return GetProperty<string>();
}
set
{
SetProperty(value);
}
}
public abstract void ClickCommand();
}
BindableBase is just a base binding class that implements INotifyPropertyChanged and stores property values in a dictionary so I don't have to make a field for each property.
When I run the project; the fallback value shows up each time. The thing that strikes me as odd is that when I put a break in my debugConverter which is as follows:
public class DebugConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
I see the value "Name" coming through the converter but the UI only ever shows the fallback value. Any ideas? Any reason that the binding would get the correct value but just not refresh to display it? I'm at a loss here. I'm happy to post any more code that could be helpful, just leave me a comment.
Thanks!
=========================== Edit =============================
The plot thickens. I now have a viewcell that is directly in my listview and the template I have inserted is just a Grid.
<?xml version="1.0" encoding="UTF-8"?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:Images="clr-namespace:MyApp.Images;assembly=MyApp"
xmlns:Converters="clr-namespace:MyApp.Views.Converters"
x:Class="MyApp.Views.Templates.SettingTemplate"
BackgroundColor="White" VerticalOptions="Center">
<Grid.Resources>
<Converters:SettingToIconConverter x:Key="SettingToIconConverter"/>
<Converters:InverseBoolConverter x:Key="InverseBoolConverter"/>
</Grid.Resources>
<StackLayout Orientation="Horizontal" VerticalOptions="Center" HorizontalOptions="Center">
<Images:VectorImage ResourceId="{Binding Converter={StaticResource SettingToIconConverter}}"
WidthRequest="30" HeightRequest="30" Margin="2" VerticalOptions="Center"/>
<Label Text="{Binding Name, FallbackValue=Name}" FontAttributes="Bold" FontSize="Medium" Margin="2"
VerticalOptions="Center"/>
<ContentPresenter Content="{Binding BonusContent}" VerticalOptions="Center" Margin="2"/>
</StackLayout>
<Frame BackgroundColor="{StaticResource Slate}" Opacity="0.25" IsVisible="{Binding IsEnabled, UpdateSourceEventName=ValueChanged, Converter={StaticResource InverseBoolConverter}, FallbackValue=false}"/>
Here's the containing listpage that has two templates in it:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75"/>
<RowDefinition Height="1"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Templates:PeripheralDetailsTemplate/>
<Frame BackgroundColor="{StaticResource Slate}" Grid.Row="1"/>
<Frame BackgroundColor="White" Grid.Row="2">
<ListView x:Name="lvPeripheralSettings" ItemsSource="{Binding Settings}"
SelectionMode="None" ItemTapped="Setting_Tapped" RowHeight="40"
ios:ListView.SeparatorStyle="FullWidth">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell IsEnabled="{Binding IsEnabled, UpdateSourceEventName=ValueChanged, Mode=TwoWay, Converter={StaticResource DebugConverter}}">
<Templates:SettingTemplate/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Frame>
</Grid>
Take note of the PeripheralDetailsTemplate:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="75"/>
</Grid.ColumnDefinitions>
<!--Icon-->
<Frame Padding="5">
<Images:VectorImage ResourceId="{Binding HardwareType, Converter={StaticResource hardwareTypeToSVGPathConverter}}"
WidthRequest="150" HeightRequest="150"
HorizontalOptions="Center" VerticalOptions="Center"/>
</Frame>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Frame>
<Label Text="{Binding Name, FallbackValue=Peripheral Name}" FontSize="Medium" FontAttributes="Bold" HorizontalOptions="Start" VerticalOptions="Center"/>
</Frame>
<Frame Grid.Row="1">
<Label Text="{Binding HardwareType, FallbackValue=Peripheral Type}" FontSize="Micro" HorizontalOptions="Start" VerticalOptions="Center"/>
</Frame>
<Frame Grid.Row="2">
<Label Text="{Binding MacAddress, StringFormat='Mac: {0}', FallbackValue=000111222333}" FontSize="Micro" HorizontalOptions="Start" VerticalOptions="Center"/>
</Frame>
<Frame Grid.Row="3">
<Label Text="{Binding FirmwareRevision, StringFormat='Firmware: {0}', FallbackValue=01AB}" FontSize="Micro" HorizontalOptions="Start" VerticalOptions="Center"/>
</Frame>
</Grid>
<Frame Grid.Column="2">
<Label Text="Conn" HorizontalOptions="Center" VerticalOptions="Center" TextColor="{Binding IsConnected, Converter={StaticResource BoolToColorConverter}, FallbackValue={StaticResource LynkdBlue}}"/>
</Frame>
</Grid>
It is bound to EXACTLY THE SAME PROPERTY AS THE ViewCell!!! and it works fine. I'm looking for the difference and haven't found it yet. I just know that I have properly set the bindingcontext because it databinds once and I know I'm properly firing NotifyPropertyChanged because the other template which is bound to the same property updates as I would expect. I have attached a debugconverter and it is never run. I think it's interesting that in both situations I was working with a ViewCell. These are two separate code bases with the same issue. :/
Simple answer; I was binding to a read-only property in my model that was based off of another property. When the other property changed I was not firing OnPropertyChanged for the read-only property.
I have been trying to play around Xamarin Forms for a while and then came across to the Listview Grouping. I am not getting done its showing blank list. Please give me help to find where I am going wrong? Thanks in advance
However, My class domain looks like:
public class LineItemTaxDto
{
public int InvoiceLineItemId { get; set; }
public int InvoiceId { get; set; }
public int TaxId { get; set; }
public decimal TaxRate { get; set; }
public decimal TaxAmount { get; set; }
public string TaxName { get; set; }
}
My View Model property look like
public IEnumerable<KeyValuePair<string, ObservableCollection<LineItemTaxDto>>> ReceiptTaxList { get; set; }
My expecting result look like:
My xaml code below
<ListView x:Name="TaxListView"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
ItemsSource="{Binding Invoice.ReceiptTaxList}"
IsGroupingEnabled="true">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Key}" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid RowSpacing="0" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Label Text="{Binding TaxName}" Grid.Row="0" Grid.Column="0" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" HorizontalTextAlignment="End" Margin="0,5,0,5" />
<Label Grid.Row="0" Grid.Column="1" Text="{Binding TaxAmount, Converter={Helpers:CurrencyAmountConverter}}" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" Margin="0,5,0,5" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
EDIT
I am set value in view will appear method
Invoice.ReceiptTaxList = Invoice.InvoiceLineItems.Select(x => { return new KeyValuePair<string, ObservableCollection<LineItemTaxDto>>(x.TaxName, x.LineItemTaxes); });
The value was set properly
I have solved this tricky code not using grouping but now its work as expected
My ViewModel Code
var TaxList = Invoice.InvoiceLineItems.Where(x => x.TaxId > 1).GroupBy(y=>y.TaxId > 1).Select(x =>
{
return new KeyValuePair<LineItemTaxDto, ObservableCollection<LineItemTaxDto>>(new LineItemTaxDto()
{
InvoiceLineItemId = x.First().Id,
InvoiceId = x.First().InvoiceId,
TaxId = x.First().TaxId,
TaxRate = x.First().TaxRate,
TaxAmount = x.Sum(a=>a.TaxAmount),
TaxName = taxlabel + " (" + x.First().TaxName + ")"
}, x.First().LineItemTaxes);
});
var taxes = new ObservableCollection<LineItemTaxDto>();
foreach (var tax in TaxList.GroupBy(tax => tax.Key.TaxId).Select(grp => grp.First()))
{
taxes.Add(tax.Key);
foreach (var subtax in tax.Value.Where(x => x.TaxId > 0))
{
taxes.Add(subtax);
}
}
Invoice.ReceiptTaxList = taxes;
My Xaml Code
<ListView
x:Name="TaxListView"
ItemsSource="{Binding Invoice.ReceiptTaxList}"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
SeparatorVisibility="None"
HasUnevenRows="false"
RowHeight="35"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid RowSpacing="0" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="{Binding TaxName}" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" HorizontalTextAlignment="End" Margin="0,5,0,5" />
<Label Grid.Row="0" Grid.Column="1" Text="{Binding TaxAmount, Converter={Helpers:CurrencyAmountConverter}}" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" Margin="0,5,0,5" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
You must use a list of list as items source on listview to get it working. I recommend you to create a class with the properties you want to show at header like this:
public class TaxesObservableCollection<T> : ObservableCollection<T> // Think about to implement INotifyPropertyChanged too, I guess it will be usefull
{
public TaxesObservableCollection(IEnumerable<T> collection, string taxGroupName) : base(collection)
{
TaxGroupName = taxGroupName;
}
private bool taxGroupName;
public bool TaxGroupName
{
get { return taxGroupName; }
set { taxGroupName = value; }
}
}
In your view model:
public IEnumerable<TaxesObservableCollection<LineItemTaxDto>> ReceiptTaxList { get; set; }
Your ListView:
(...) // The rest of it as you did
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding TaxGroupName}" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
(...) // The rest of it as you did
And you fill it this way:
Invoice.ReceiptTaxList = Invoice.InvoiceLineItems.Select(x => { return new TaxesObservableCollection<LineItemTaxDto>(x.LineItemTaxes, x.TaxName); }).ToList();
It should works, please let me know if is that what you wanted.
Trying to render a ListView with a grid into it. The grid contains two columns. The first one, with a button. The second one, with a Label.
Model contains two attributes. First one, a List of specific object. Second one, a string.
Finally, the label of the grid inside of listview will be binded to the one random attribute of list of object of the Model.
My best approach is:
<ListView x:Name="intervectionList"
ItemsSource="{Binding .}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="1"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="3*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Text="Play" Grid.Row="0" Grid.Column="0" Clicked="OnLogginClicked"/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding random_attribute}"/>
<BoxView Color="Navy" HeightRequest="1" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
CODE-BEHIND:
public Intervection()
{
InitializeComponent();
var obj= new Model();
this.BindingContext = prueba.List_of_object;
}
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaiseOnPropertyChange([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public ViewModel()
{
_viewmodel = new ViewModel();
}
private ViewModel _viewmodel;
private string _attribute1;
public string Attribute1
{
get { return _attribute1; }
set { _attribute1= value; RaiseOnPropertyChange(); }
}
.............
}
public class Model
{
public List<obj> Intervencion;
public string attribute2;
// Helpers...
}
That is not rendering anything.
I tried successive approaches. Coming from Basic ListView with string, ListView of object,... and so on. The problem is coming from when I insert the grid.
After check Stackoverflow. I found this link Create Grid from Code-Behind, but this is not serving to my purpose because I can´t re-write the view model. (I, even, tried to coded it).
As usual, thanks mates.
I have added the VerticalOptions to the Listview and Grid.
I have created a viewmodel in which I have one property, the list of items.
The viewmodel also implements INotifyPropertyChanged.
You can read about INotifyPropertyChanged here.
The INotifyPropertyChanged interface is used to notify clients,
typically binding clients, that a property value has changed.
XAML :
<ListView ItemsSource="{Binding MyObservableCollection}" VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="5" VerticalOptions="Fill">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="1"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="3*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Text="Play" Grid.Row="0" Grid.Column="0"/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding .}"/>
<BoxView Color="Navy" HeightRequest="1" Grid.Row="1"
Grid.Column="0" Grid.ColumnSpan="2"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ViewModel :
public class ListViewWithGridViewModel : INotifyPropertyChanged
{
private ObservableCollection<string> _myObservableCollection;
public ListViewWithGridViewModel()
{
MyObservableCollection = new ObservableCollection<string>(new List<string> { "abc", "xyz", "pqr", "aaa", "abc", "xyz", "pqr", "aaa", "abc", "xyz", "pqr", "aaa" });
}
public ObservableCollection<string> MyObservableCollection
{
get { return _myObservableCollection; }
set
{
_myObservableCollection = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
XAML.cs :
public partial class ListViewWithGrid : ContentPage
{
public ListViewWithGrid()
{
InitializeComponent();
BindingContext = new ListViewWithGridViewModel();
}
}
Finally I got it. The xaml needed for it is the next one (you can complet all code coming from the code´s question). Posted just in case you all want to use another approach. Proper answer (more elegant) is #Rohit´s answer.
<ContentPage.Resources>
<ResourceDictionary>
<Color x:FactoryMethod="FromHex" x:Key="fondoBlancoPalido">
<x:Arguments>
<x:String>#F2F2F2</x:String>
</x:Arguments>
</Color>
</ResourceDictionary>
</ContentPage.Resources>
<ListView x:Name="listView" ItemsSource="{Binding .}" BackgroundColor="{StaticResource fondoBlancoPalido}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="10"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="2*"></ColumnDefinition>
<ColumnDefinition Width="3*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Clicked="OnStartClicked" Image="play.png" BackgroundColor="Transparent" HorizontalOptions="Center" Grid.RowSpan="2"/>
<Label Grid.Row="0" Grid.Column="1" Text="Hora de Inicio: " XAlign="Center" YAlign="Center" TextColor="Black" FontAttributes="Bold"/>
<Label Grid.Row="0" Grid.Column="2" Text="{ Binding attribute3 }" XAlign="Center" YAlign="Center" TextColor="Black"/>
<Label Grid.Row="1" Grid.Column="1" Text="Encargado de la Tarea: " XAlign="Center" YAlign="Center" TextColor="Black" FontAttributes="Bold"/>
<Label Grid.Row="1" Grid.Column="2" Text="{ Binding attribute4 }" XAlign="Center" YAlign="Center" TextColor="Black"/>
<BoxView Color="Navy" HeightRequest="2" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3"/>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>