Hey so I've set up a CarouselView with a video in each cell
<CarouselView
x:Name="TheCarousel">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout
HorizontalOptions="Center">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="6*"/>
</Grid.RowDefinitions>
<Label FontSize="Title" HorizontalOptions="Center" HorizontalTextAlignment="Center" Text="{Binding Name}" VerticalOptions="Center" />
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="8*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackLayout Grid.Column="1">
<video:VideoPlayer Source="{Binding Uri}" HeightRequest="480"/>
</StackLayout>
</Grid>
</Grid>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
It is working, the videos play, however when i scroll to a different video, the previous one plays by itself. For example, if i pause the first video, then scroll over to the second video, the first video will start playing. I'm not sure why this is happening.
Any help would be appreciated.
Don't know which videoplayer you use, but I use Octane.Xamarin.Forms.VideoPlayer, don't have this problem.
<CarouselView x:Name="TheCarousel" ItemsSource="{Binding videos}">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout HorizontalOptions="Center">
<Label
FontSize="Title"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
Text="{Binding title}"
VerticalOptions="Center" />
<o:VideoPlayer
AutoPlay="True"
DisplayControls="True"
FillMode="ResizeAspectFill"
Source="{Binding path}" />
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
public partial class Page5 : ContentPage
{
public ObservableCollection<videomodel> videos { get; set; }
public Page5()
{
InitializeComponent();
videos = new ObservableCollection<videomodel>()
{
new videomodel(){path="https://sec.ch9.ms/ch9/a7e9/abda3d53-bed3-4f20-9f53-70047a35a7e9/Xamarin101WhatIsXamarin_high.mp4",title="title 2"},
new videomodel(){path="https://ia800201.us.archive.org/12/items/BigBuckBunny_328/BigBuckBunny_512kb.mp4",title="title 1"},
new videomodel(){path="https://sec.ch9.ms/ch9/3901/c6e0e4e6-bb93-4033-a484-040a874f3901/Xamarin101XamarinFormsMVVMXAML_high.mp4",title="title 3"}
};
this.BindingContext = this;
}
}
public class videomodel
{
public string path { get; set; }
public string title { get; set; }
}
}
Related
Firstscreen with all the notes.
After I deleted the first note!
I have recently started programming with .NET MAUI. The elements are correctly removed in the C# list. However, after deleting the remaining elements are only partially displayed. That means that only e.g. the 4th element is displayed. For the other elements only an empty bar is displayed.
My code so far:
XAML:
<VerticalStackLayout>
<ScrollView>
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image
Grid.Column="0"
Source="logo.png"
WidthRequest="150"
HorizontalOptions="Start"
VerticalOptions="Start"/>
<Label
TextColor="Black"
Grid.Column="1"
Text="TODO"
FontSize="35"
HorizontalOptions="Start"
VerticalOptions="Start"
Margin="23"/>
</Grid>
<Grid BackgroundColor="#24D4A3">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView
Grid.ColumnSpan="2"
Grid.RowSpan="2"
RowHeight="100"
x:Name="listview">
<ListView.ItemTemplate>
<DataTemplate >
<ViewCell >
<Grid BackgroundColor="#24D4A3">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Button BackgroundColor="#DEABF5"
Text="{Binding Title}"
Clicked="onNoteSelected"
BorderWidth="2"
TextColor="Black"
FontSize="28"
Margin="20"
CornerRadius="100"
WidthRequest="350"
HeightRequest="70"
HorizontalOptions="Center"
VerticalOptions="Start"/>
<Button
BindingContext="{Binding Id}"
Clicked="ToDoSolved"
BorderWidth="2"
BorderColor="Black"
BackgroundColor="White"
WidthRequest="45"
HeightRequest="45"
CornerRadius="35"
Margin="0,0,260,0"
/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ImageButton
Clicked="Settings"
Source="settings.png"
Grid.Row="0"
Grid.Column="2"
BorderColor="#2b3c3c"
BorderWidth="0"
BackgroundColor="#34A4EB"
CornerRadius="35"
HorizontalOptions="End"
WidthRequest="70"
HeightRequest="70"
Margin="0,10, 10, 0"
VerticalOptions="Start"/>
<ImageButton
Clicked="CreateNote"
Source="add.png"
Grid.Row="1"
Grid.Column="2"
BorderColor="#2b3c3c"
BorderWidth="0"
BackgroundColor="#34A4EB"
CornerRadius="35"
HorizontalOptions="End"
WidthRequest="70"
HeightRequest="70"
Margin="0,0,10,10"
Padding="2,0,0,0"/>
</Grid>
</StackLayout>
</ScrollView>
</VerticalStackLayout>
C#:
public partial class MainPage : ContentPage
{
private ObservableCollection<Note> notes = new ObservableCollection<Note>();
public ObservableCollection<Note> Notes
{
get { return notes; }
set { notes = value; }
}
public MainPage()
{
InitializeComponent();
notes.Add(new Note(1, "My Note1", "I'm ugly"));
notes.Add(new Note(2, "My Note2", "I'm short"));
notes.Add(new Note(3, "My Note3", "I'm smart"));
notes.Add(new Note(4, "My Note4", "I'm smart"));
//notes.Add(new Note(6, "My Note6", "I'm smart"));
//notes.Add(new Note(7, "My Note7", "I'm smart"));
//notes.Add(new Note(8, "My Note8", "I'm smart"));
//notes.Add(new Note(9, "My Note9", "I'm smart"));
this.BindingContext= Notes;
listview.ItemsSource= Notes;
}
private async void CreateNote(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("//CreateNote");
}
private async void Settings(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("//Settings");
}
private void ToDoSolved(object sender, EventArgs e)
{
Button button= (Button) sender ;
var id = (int)button.BindingContext;
var item = Notes.SingleOrDefault(x => x.Id == id);
if (item != null)
{
Notes.Remove(item);
Console.WriteLine(id);
}
}
async void onNoteSelected(object sender, EventArgs e)
{
Button button= (Button) sender ;
var id = (int)button.BindingContext;
//await Shell.Current.GoToAsync("NotePage" + id);
}
}
I would be grateful for any help :)
To delete the item, since you are using ListView, you can delete the via
Button click. However, you need to delete the item from bottom to top in order.
Code-behind:
public partial class MainPage : ContentPage
{
public ObservableCollection<Note> Notes { get; private set; } = new ObservableCollection<Note>();
public MainPage()
{
InitializeComponent();
AddNotes();
BindingContext = this;
}
private void AddNotes()
{
Notes.Add(new Note("0", "My Note1"));
Notes.Add(new Note("1", "My Note2"));
Notes.Add(new Note("2", "My Note3"));
Notes.Add(new Note("3", "My Note4"));
}
private void Button_Clicked(object sender, EventArgs e)
{
var note = (Button)sender;
Note listnote = (from itm in Notes
where itm.Id == note.CommandParameter.ToString()
select itm).FirstOrDefault<Note>();
Notes.Remove(listnote);
}
}
Xaml:
<VerticalStackLayout>
<ScrollView>
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image
Grid.Column="0"
Source="logo.png"
WidthRequest="150"
HorizontalOptions="Start"
VerticalOptions="Start"
/>
<Label
TextColor="Black"
Grid.Column="1"
Text="TODO"
FontSize="35"
HorizontalOptions="Start"
VerticalOptions="Start"
Margin="23"
/>
</Grid>
<Grid BackgroundColor="#24D4A3">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView
Grid.ColumnSpan="2"
Grid.RowSpan="2"
RowHeight="100"
x:Name="listview"
ItemsSource="{Binding Notes}" >
<ListView.ItemTemplate>
<DataTemplate >
<ViewCell>
<Grid BackgroundColor="#24D4A3" >
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Button BackgroundColor="#DEABF5"
Text="{Binding Title}"
BorderWidth="2"
TextColor="Black"
FontSize="28"
Margin="20"
CornerRadius="100"
WidthRequest="350"
HeightRequest="70"
HorizontalOptions="Center"
VerticalOptions="Start"/>
<Button
Text="Delete"
Clicked="Button_Clicked"
CommandParameter="{Binding Id}"
BorderWidth="2"
BorderColor="Black"
BackgroundColor="White"
WidthRequest="45"
HeightRequest="45"
CornerRadius="35"
Margin="0,0,260,0"
/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</StackLayout>
</ScrollView>
</VerticalStackLayout>
Note:
public class Note
{
public string Id { get; set; }
public string Title { get; set; }
public Note(string id, string title)
{
Id = id;
Title = title;
}
}
I am trying to display an object in a grid using data binding. For some reason Only one Row of the grid is being displayed per entry. I know the data binding works, because if I comment out the first row of each grid it then displays the second row. Below is a sample of the relevant code, as well as a screenshot displaying the issue.
MainPage.xaml
<?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:local="clr-namespace:Game_Tracker.ViewModels;assembly=Game Tracker"
x:Class="Game_Tracker.MainPage">
<ContentPage.BindingContext>
<local:OpponentItemVm/>
</ContentPage.BindingContext>
<StackLayout>
<ListView x:Name="OpponentList" ItemsSource="{Binding OpponentItems }">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame BorderColor="Black"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Padding="0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="Name: "/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding OpponentFullName}"/>
<Label Grid.Row="1" Grid.Column="0" Text="Email: "/>
<Label Grid.Row="1" Grid.Column="1" Text="{Binding OpponentEmail}"/>
<Label Grid.Row="2" Grid.Column="0" Text="Phone: "/>
<Label Grid.Row="2" Grid.Column="1" Text="{Binding OpponentPhone}"/>
<Label Grid.Row="3" Grid.Column="0" Text="Address: "/>
<Label Grid.Row="3" Grid.Column="1" Text="{Binding OpponentAddress}"/>
<Label Grid.Row="4" Grid.Column="0" Text="Id: "/>
<Label Grid.Row="4" Grid.Column="1" Text="{Binding OpponentId}"/>
</Grid>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace Game_Tracker
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
}
Opponent.cs
using System;
namespace Game_Tracker.Models
{
public class Opponent
{
public int OpponentId { get; set; }
public string OpponentFName { get; set; }
public string OpponentLName { get; set; }
public string OpponentAddress { get; set; }
public string OpponentPhone { get; set; }
public string OpponentEmail { get; set; }
public string OpponentFullName => $"{OpponentFName} {OpponentLName}";
public Opponent(int opponentId, string opponentFName, string opponentLName,
string opponentAddress, string opponentPhone, string opponentEmail)
{
this.OpponentId = opponentId;
this.OpponentFName = opponentFName;
this.OpponentLName = opponentLName;
this.OpponentAddress = opponentAddress;
this.OpponentPhone = opponentPhone;
this.OpponentEmail = opponentEmail;
}
}
}
OpponentItemVM.cs
using System.Collections.ObjectModel;
using Game_Tracker.Models;
namespace Game_Tracker.ViewModels
{
public class OpponentItemVm
{
public ObservableCollection<Opponent> OpponentItems { get; set; }
public OpponentItemVm()
{
OpponentItems = new ObservableCollection<Opponent>();
OpponentItems.Add(new Opponent(1, "Jim", "Jimson",
"123 Fake Street", "(123)123-4567", "Jim#Fake.com" ));
OpponentItems.Add(new Opponent(2, "Ken", "Kensington",
"123 False Street", "(123)123-4567", "Ken#Fake.com" ));
}
}
}
To be honest, I agree with Jason.However, the best practice is that you just add HasUnevenRows to True and let unset the RowHeight property which will automatically set the row height to fit content like below:
<ListView x:Name="OpponentList" ItemsSource="{Binding OpponentItems }" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame BorderColor="Black"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Padding="0"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="Name: "/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding OpponentFullName}"/>
<Label Grid.Row="1" Grid.Column="0" Text="Email: "/>
<Label Grid.Row="1" Grid.Column="1" Text="{Binding OpponentEmail}"/>
<Label Grid.Row="2" Grid.Column="0" Text="Phone: "/>
<Label Grid.Row="2" Grid.Column="1" Text="{Binding OpponentPhone}"/>
<Label Grid.Row="3" Grid.Column="0" Text="Address: "/>
<Label Grid.Row="3" Grid.Column="1" Text="{Binding OpponentAddress}"/>
<Label Grid.Row="4" Grid.Column="0" Text="Id: "/>
<Label Grid.Row="4" Grid.Column="1" Text="{Binding OpponentId}"/>
</Grid>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Official reference docs:
https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.listview.hasunevenrows?view=xamarin-forms
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/customizing-list-appearance#row-height
I have a collection view whose source is an IObservable(Object1) inside of each Object1 is a List(Object2).
I would like to show each Object2 that is related to its Object1.
I have tried to place a ListView inside of a collectionView
I am getting the error System.InvalidOperationException LoadTemplate should not be null
<CollectionView Grid.Row="2" ItemsSource="{Binding Object1Collection}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.65*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label TextColor="Black" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding Response}"></Label>
<Label TextColor="Black" Grid.Row="1" Grid.Column="0" Text="Restriction: "></Label>
<ListView Grid.Row="1" Grid.Column="1" ItemsSource="{Binding Object2List }">
<ListView.ItemTemplate>
<DataTemplate>
<!--
<StackLayout Orientation="Horizontal">
<Label TextColor="Black" Text="{Binding Statistic}"></Label>
<Label TextColor="Black" Text=" : "></Label>
<Label TextColor="Black" Text="{Binding Amount}"></Label>
</StackLayout>
-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
You could use CollectionView Grouping. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/grouping
Xaml:
<CollectionView ItemsSource="{Binding Object1Collection}" IsGrouped="True">
<CollectionView.GroupHeaderTemplate>
<DataTemplate >
<Label Text="{Binding Response}"/>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate>
<ScrollView>
<Grid Padding="10">
<StackLayout BackgroundColor="Blue">
<Label Text="{Binding Statistic}"/>
<Label TextColor="Black" Text=" : "></Label>
<Label Text="{Binding Amount}"/>
</StackLayout>
</Grid>
</ScrollView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Model:
public class Object1Model : List<Object2Model>
{
public string Response { get; set; }
public Object1Model(string response, List<Object2Model> Object2List) : base(Object2List)
{
Response = response;
}
}
public class Object2Model
{
public string Statistic { get; set; }
public string Amount { get; set; }
}
Code behind:
public ObservableCollection<Object1Model> Object1Collection { get; set; }
public Page23()
{
InitializeComponent();
Object1Collection = new ObservableCollection<Object1Model>();
Object1Collection.Add(new Object1Model("Object1A", new List<Object2Model>
{
new Object2Model(){ Statistic="Object2Statistic1A", Amount="Object2Amount1A"},
new Object2Model(){ Statistic="Object2Statistic1A", Amount="Object2Amount1A"},
}));
Object1Collection.Add(new Object1Model("Object1B", new List<Object2Model>
{
new Object2Model(){ Statistic="Object2Statistic1B", Amount="Object2Amount1B"},
new Object2Model(){ Statistic="Object2Statistic1B", Amount="Object2Amount1B"},
}));
Object1Collection.Add(new Object1Model("Object1C", new List<Object2Model>
{
new Object2Model(){ Statistic="Object2Statistic1C", Amount="Object2Amount1C"},
new Object2Model(){ Statistic="Object2Statistic1C", Amount="Object2Amount1C"},
}));
this.BindingContext = this;
}
Add ViewCell under DataTemplate of ListView.
<ListView Grid.Row="1" Grid.Column="1" ItemsSource="{Binding Object2List }">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label TextColor="Black" Text="{Binding Statistic}"></Label>
<Label TextColor="Black" Text=" : "></Label>
<Label TextColor="Black" Text="{Binding Amount}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Fix those two exceptions:
No viewcell error:
'Specified cast is not valid.'
Comment out the StackLayout error:
'LoadTemplate should not be null'
In a CollectionView I have 4 rows, 2 of which are set to "Auto".
In one I have a Label in Binding, in the other I have another CollectionView with objects in Binding. In the Row where I have the Label, the height is automatically set correctly, while where I have the CollectionView it becomes an "infinite" height, in the sense that even if empty, it takes up the whole screen.
<DataTemplate>
<yummy:PancakeView CornerRadius="5" BackgroundColor="Transparent">
<Grid BackgroundColor="Gainsboro" RowSpacing="0.2">
<Grid.RowDefinitions>
<RowDefinition Height="21"/>
<RowDefinition Height="16"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3"/>
<ColumnDefinition Width="65"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<BoxView Grid.Column="0" Grid.RowSpan="4" BackgroundColor="{Binding ColoreUmore}"/>
<Label Grid.Row="0" Grid.Column="2" Text="{Binding GiornoTrascritto}" FontSize="14" TextColr="Gray" Margin="0,5,0,0"/>
<Label Grid.Row="1" Grid.Column="2" Text="{Binding Orario}" FontSize="14" TextColr="Gray"/>
<Image Grid.Row="0" Grid.RowSpan="3" Grid.Column="1" Margin="8" Source="{Binding Umore}" VerticalOptions="Start" HeightRequest="45"/>
<Label Grid.Row="3" Grid.Column="2" TextColor="Black" FontSize="16" Text="{Binding Nota}" Margin="0,0,10,0" VerticalOptions="Start" HorizontalTextAlignment="Start" VerticalTextAlignment="Start"/>
<CollectionView
Grid.Row="2"
Margin="0,0,10,0"
Grid.Column="2"
SelectionMode="None"
ItemsSource="{Binding IconDiaries}"
VerticalOptions="Start">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" VerticalItemSpacing="5" HorizontalItemSpacing="5"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid RowSpacing="0.5">
<Grid.RowDefinitions>
<RowDefinition Height="17"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="18"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<BoxView BackgroundColor="Gray" Grid.ColumnSpan="2" Grid.Row="0" CornerRadius="5" Opacity="0.6" />
<Image Grid.Row="0" Grid.Column="0" Source="{Binding isSource}" Margin="3"/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding id}" TextColor="Black" FontSize="12" VerticalTextAlignment="Center" Margin="0,0,3,0"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</yummy:PancakeView>
</DataTemplate>
while where I have the CollectionView it becomes an "infinite" height, in the sense that even if empty, it takes up the whole screen.
From your code and description, you have one collectionview in datatemplate, now you want to adjust collectionview height according to its content, am I right?
If yes, I suggest you can binding collectionview HeightRequest like the following code:
<StackLayout >
<CollectionView
x:Name="assessmentsCollectionView"
BackgroundColor="Blue"
HeightRequest="{Binding rowHeigth}"
ItemsSource="{Binding letters}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="5" Spacing="10">
<Frame
Padding="0"
CornerRadius="5"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal">
<Frame
Padding="5"
CornerRadius="0"
WidthRequest="50">
<Label
FontSize="24"
HorizontalTextAlignment="Center"
Text="{Binding TypeLetter}"
TextColor="#37474f"
VerticalTextAlignment="Center" />
</Frame>
<StackLayout Padding="10">
<Label
FontSize="24"
Text="{Binding Name}"
TextColor="Black" />
<StackLayout Orientation="Horizontal">
<Image
HeightRequest="12"
Source="c1.png"
WidthRequest="12" />
<Label
FontSize="12"
Text="{Binding Date}"
TextColor="Gray" />
</StackLayout>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Button
x:Name="btn1"
Command="{Binding AddCommand}"
Text="btn1" />
</StackLayout>
public partial class Page4 : ContentPage
{
public Page4()
{
InitializeComponent();
this.BindingContext = new letterviewmodel(); ;
}
}
public class letterviewmodel: INotifyPropertyChanged
{
public ObservableCollection<lettermodel> letters { get; set; }
private int _rowHeigth;
public int rowHeigth
{
get { return _rowHeigth; }
set
{
_rowHeigth = value;
RaisePropertyChanged("rowHeigth");
}
}
public ICommand AddCommand { protected set; get; }
public letterviewmodel()
{
letters = new ObservableCollection<lettermodel>()
{
new lettermodel(){TypeLetter="A",Name="letter 1",Date="2021-01-01"},
new lettermodel(){TypeLetter="B",Name="letter 2",Date="2021-01-01"},
new lettermodel(){TypeLetter="C",Name="letter 3",Date="2021-01-01"}
};
rowHeigth = letters.Count * 100 ;
AddCommand = new Command<lettermodel>(async (key) => {
letters.Add(new lettermodel() { TypeLetter = "D", Name = "test letter ", Date = "2021-01-01" });
rowHeigth = letters.Count * 100 ;
});
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class lettermodel
{
public string TypeLetter { get; set; }
public string Name { get; set; }
public string Date { get; set; }
}
The screenshot:
If I understand correctly, you want the CollectionView to take an automatic height and adapt to the row, right?
In order to make this happen you will need to:
Set the property
ItemSizingStrategy="MeasureFirstItem" in the CollectionView, so the CollectionView has the proper height you're looking for.
Set the Row Height to *, so the CollectionView height sets automatically for the remaining size of the page.
Set VerticalOptions to FillAndExpand in Collection View so the CollectionView can adapt to the size of the Row.
Finally, put the label with Row 3 below the CollectionView to avoid any issues with the Layout order.
Let me know if this does any help!
I have created a ListView with items based on data saved in database. Its computer list with few properties as name, ipAdress, port and selected. If selected = true computer is marked as default and I need to change his appearance in ListView.
I need to create a binding to property which isnt part of the table.
I have simple list of computers (XAML)
<ListView x:Name="CompListView" HasUnevenRows="true" Grid.Row="1" SeparatorColor="Black" ItemsSource="{Binding ComputerList}"
SelectedItem="{Binding SelectedComputerItem, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding ComputerName}" Grid.Row="1" Font="20" TextColor="{Binding Selected_Color}" />
<Label Text="{Binding IPAddress}" Grid.Row="0" Font="20" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="{Binding Selected_Color}"/>
<Label Text="{Binding Port}" Grid.Row="1" Font="13" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="{Binding Selected_Color}"/>
<Image Source="computerpng.png" Grid.Row="0" Grid.Column="0" WidthRequest = "24" HeightRequest = "24" HorizontalOptions = "Start"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Base computer View connected to database.
public class BaseComputerView : INotifyPropertyChanged
{
public Computer _computer;
public INavigation _navigation;
public IComputer _computerRepository;
public string ComputerName
{
get => _computer.ComputerName;
set
{
_computer.ComputerName = value;
NotifyPropertyChanged("Computer_Name");
}
}
public string IPAddress
{
get => _computer.IPAddress;
set
{
_computer.IPAddress = value;
NotifyPropertyChanged("IPAddress");
}
}
public string Port
{
get => _computer.Port;
set
{
_computer.Port = value;
NotifyPropertyChanged("Port");
}
}
public bool Selected
{
get => _computer.Selected;
set
{
_computer.Selected = value;
NotifyPropertyChanged("Selected");
}
}
Based on _Selected I added property "Selected_Color" within the same class. Goal is to change back color of controls if the item is selected.
public string Selected_Color
{
get
{
string Text_Color = string.Empty;
try
{
if (Selected == true)
{
Text_Color = "#33cc33";
}
else
{
Text_Color = "#000000";
}
}
catch (Exception ex)
{
return "#000000";
}
return Text_Color;
}
}
This code however looks up for property "Selected_Color" in Computer table, which is wrong.
use the Ignore attribute to tell SQLite to ignore your new property
[Ignore]
public string Selected_Color
alternately, you could use a ValueConverter to set the color based on the Selected property
Thanks for your answer,
I figured it out by adding Selected_Color as Computer Table property.
[Table("Computer")]
public class Computer
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string ComputerName { get; set; }
public string IPAddress { get; set; }
public string Port { get; set; }
public bool Selected { get; set; }
[Ignore]
public string Selected_Color
{
get
{
string Text_Color = string.Empty;
try
{
if (Selected == true)
{
//Green color
Text_Color = "#33cc33";
}
else
{
Text_Color = "#000000";
}
}
catch (Exception ex)
{
return "#000000";
}
return Text_Color;
}
}
}
App_ComputerList_Image
Works fine until I open one of the computers for edit and come back to computer list. What is weird is fact that I get Java exception not for the first time I do that but only for the second time. So I am able to open one of the items and came back to computer list. If I repeat that then I get this Java exception.
just wanted to add answer for everyone who would fight with similar problem, that I found a better way to do this. You can define data templates based on your property and then use it to draw your Listview like this. Difference in this case is textcolor of the labels.
<ResourceDictionary>
<DataTemplate x:Key="SelectedComputer">
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding ComputerName}" Grid.Row="1" Font="20" TextColor="Green" />
<Label Text="{Binding IPAddress}" Grid.Row="0" Font="20" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="Green"/>
<Label Text="{Binding Port}" Grid.Row="1" Font="13" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="Green"/>
<Image Source="computerpng.png" Grid.Row="0" Grid.Column="0" WidthRequest = "24" HeightRequest = "24" HorizontalOptions = "Start"/>
</Grid>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="Computer">
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding ComputerName}" Grid.Row="1" Font="20" TextColor="Black" />
<Label Text="{Binding IPAddress}" Grid.Row="0" Font="20" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="Black"/>
<Label Text="{Binding Port}" Grid.Row="1" Font="13" Grid.Column="1" HorizontalOptions="EndAndExpand" HorizontalTextAlignment="End" TextColor="Black"/>
<Image Source="computerpng.png" Grid.Row="0" Grid.Column="0" WidthRequest = "24" HeightRequest = "24" HorizontalOptions = "Start"/>
</Grid>
</ViewCell>
</DataTemplate>
<local:ComputerTemplateSelector x:Key="ComputerTemplateSelector" SelectedComputer="{StaticResource SelectedComputer}" Computer="{StaticResource Computer}" />
</ResourceDictionary>
Template selector:
public class ComputerTemplateSelector : DataTemplateSelector
{
public DataTemplate SelectedComputer { get; set; }
public DataTemplate Computer { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return ((SQLite_Database.Computer)item).Selected == true ? SelectedComputer : Computer;
}
}