How to make Grid Row dynamic in CollectionView control of .Net MAUI? - xamarin

I'm trying to achieve dynamic row height in CollectionView control, so that when ever I have more text for a particular property it will extend the height of the frame automatically.
I have tried with ListView as well using HasUnEvenRow property "true" but with that also it's not working.
Here is my code:
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Grid RowDefinitions="*,60" BackgroundColor="{StaticResource PageBackgroundColor}" Padding="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<CollectionView Grid.Row="0" HorizontalOptions="Fill" VerticalOptions="Fill"
ItemsSource="{Binding Inspections}"
VerticalScrollBarVisibility="Always"
ItemsLayout="VerticalList" ItemSizingStrategy="MeasureAllItems">
<CollectionView.ItemTemplate>
<DataTemplate>
<Frame Padding="15" HasShadow="False">
<Grid HorizontalOptions="Fill"
VerticalOptions="Fill"
BackgroundColor="White"
RowSpacing="25"
RowDefinitions="Auto,Auto,Auto"
ColumnDefinitions="*,Auto">
<StackLayout
Orientation="Horizontal"
Grid.Row="0"
Grid.Column="0">
<Label Text="{Binding Path=BusinessName}"
Style="{StaticResource LabelTitleStyle}" />
<Grid Padding="15,0,0,0">
<baseChip:Chip
HorizontalOptions="Fill" VerticalOptions="Fill"
Style="{StaticResource ChipContainer}"
HasShadow="False"
BackgroundColor="{Binding Path=ChipBackgroundColor}">
</baseChip:Chip>
<Label
Text="{Binding Path=ChipText}"
Style="{StaticResource ChipLabel}"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
TextColor="{Binding Path=ChipTextColor}"/>
</Grid>
</StackLayout>
<Image
Grid.Row="0"
Grid.Column="1"
HorizontalOptions="End"
VerticalOptions="Center"
Aspect="AspectFit">
<Image.Source>
<FontImageSource Glyph="{x:Static helper:MaterialFontHelper.FilePdfBox}"
Color="{StaticResource DarkGray}"
Size="20"
FontFamily="MaterialDesignIcons"/>
</Image.Source>
</Image>
<Grid Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
RowDefinitions="Auto, Auto"
ColumnDefinitions="*, *">
<Label
Grid.Row="0"
Grid.Column="0"
Text="Inspection Type"
Style="{StaticResource LabelKeyStyle}" />
<Label
Grid.Row="1"
Grid.Column="0"
Text="ksd kahdkahd kahd kahd aojsoiud aasjlj sdlkja dlkja da asdadas alsajdlaksjdlajd alsjdalkjd alksjd sa"
Style="{StaticResource LabelValueStyle}" />
<Label
Grid.Row="0"
Grid.Column="1"
Text="Primary Inspector"
Style="{StaticResource LabelKeyStyle}" />
<Label
Grid.Row="1"
Grid.Column="1"
Style="{StaticResource LabelValueStyle}" >
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding Path=InspectorFirstName}"/>
<Span Text=" "/>
<Span Text="{Binding Path=InspectorLastName}"/>
</FormattedString>
</Label.FormattedText>
</Label>
</Grid>
<Grid Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
RowDefinitions="*, *"
ColumnDefinitions="*, *">
<Label
Grid.Row="0"
Grid.Column="0"
Text="Scheduled Date"
Style="{StaticResource LabelKeyStyle}" />
<Label
Grid.Row="1"
Grid.Column="0"
Text="{Binding Path=ScheduledStartDate, Converter={StaticResource dateFormatter},ConverterParameter='long'}"
Style="{StaticResource LabelValueStyle}" />
<Label
Grid.Row="0"
Grid.Column="1"
Text="Completed Date"
Style="{StaticResource LabelKeyStyle}" />
<Label
Grid.Row="1"
Grid.Column="1"
Text="{Binding Path=CompletionDate, Converter={StaticResource dateFormatter},ConverterParameter='long'}"
Style="{StaticResource LabelValueStyle}" />
</Grid>
</Grid>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<StackLayout
Grid.Row="1"
VerticalOptions="End"
HorizontalOptions="FillAndExpand"
BackgroundColor="{StaticResource White}">
<controlTemplate:BeginInspectionContentView></controlTemplate:BeginInspectionContentView>
</StackLayout>
</Grid>
</StackLayout>
Output & expected output image attached here:
How to achieve dynamic height for this UI? Any help or suggestions are welcome.

There are three solutions to this problem:
You can change CollectionView to FlexLayout with BindableLayout.ItemsSource and BindableLayout.ItemTemplate. Then you don't need to set Height for item or FlexLayout because all are dynamic.
You can set a value to collectionView.HeightRequest using MVVM. When item increase, the height will increase as well. For more details about this solution, you may refer to the link.
You can use CollectionView.Behaviors to calculate the Height of every item to increase the height of ContentView. For more details about this solution, you may refer to the link.

You have Grid. With StackLayout. With Grid. With Small Grids inside it.
I will put aside for now, that this is extremely bad for rendering. (It is serious problem however...)
None of the expected output justify this organization.
If you need for element to occupy 2 columns, you can use columns span 2.
Before anything else, please combine all 4 grids in a single grid.
After you are done with that, limit your VisualElements height, or, even better, limit the content you are putting in them. (Because cut content looks bad. You should be using something like "show more" link, that opens popup or whatever).
If you have any questions, please ask.
Edit: Let me clarify:
You have the same Grid code. Most important part - columns are * , * , and rows are auto height. And every 2 rows, you create another GRID, that is copy of the first GRID.
This is extremely counterproductive.
Also, just because you can do something, and it is "working in xamarin", it doesn't mean that you should do it.
First, put everything in the same grid, instead of nesting it and copying grids, then you can start working on CLIP/Height limit/etc.
(Recommending you to test it on IOS, because once you get it running fine there, it is much easier to fine-tune it for other platforms, than the other way around.)

Related

How to make the BindableLayout to be scrollable

I have one list and i don't want to use listview inside it as how can i make it scrollable, data is binding but i am not able to scroll it.
<Grid Grid.Row="0" IsVisible="{Binding SearchListLayout}" Margin="0" Padding="0" BackgroundColor="White">
<ScrollView>
<StackLayout BindableLayout.ItemsSource="{Binding ProductsList}" x:Name="SearchLayoutItemList" HeightRequest="255">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid RowDefinitions="37,Auto">
<Image Grid.Row="0" Source="searchingicon.png" Style="{DynamicResource icons}"/>
<Label Grid.Row="0" Text="{Binding name}" FontSize="14" TextColor="Black" Margin="50,0,0,0" HorizontalOptions="StartAndExpand" VerticalOptions="CenterAndExpand"/>
<Image Grid.Row="0" Source="reload.png" Style="{DynamicResource icons}" HorizontalOptions="EndAndExpand" Margin="0,0,15,0"/>
<BoxView Grid.Row="1" Style="{DynamicResource DarkSeparator}" />
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
</Grid>
Although the BindableLayout technically can display your list of items via the StackLayout, and the StackLayout height is being restraint to your height request; the encompassing ScrollViewer has nothing to scroll since it fully contains your StackLayout.
To achieve what you probably want (a fixed 255 pixel StackLayout that scrolls your items) the ScrollViewer should be inside the StackLayout as the rendered ItemsPanel for you Items. Again, you could achieve this with custom BindableLayouts, but this is exactly what Xamarin Forms ListView does by default.
You probably simply want to change your BindableLayout implementation to a ListView:
<Grid Grid.Row="0" IsVisible="{Binding SearchListLayout}" Margin="0" Padding="0" BackgroundColor="White">
<ListView ItemsSource="{Binding ProductsList}" x:Name="SearchLayoutItemList" HeightRequest="255">
<ListView.ItemTemplate>
<DataTemplate>
<Grid RowDefinitions="37,Auto">
<Image Grid.Row="0" Source="searchingicon.png" Style="{DynamicResource icons}"/>
<Label Grid.Row="0" Text="{Binding name}" FontSize="14" TextColor="Black" Margin="50,0,0,0" HorizontalOptions="StartAndExpand" VerticalOptions="CenterAndExpand"/>
<Image Grid.Row="0" Source="reload.png" Style="{DynamicResource icons}" HorizontalOptions="EndAndExpand" Margin="0,0,15,0"/>
<BoxView Grid.Row="1" Style="{DynamicResource DarkSeparator}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
The scrollview could not scroll as you set the HeightRequest="255" for the stacklayout in the scrollview. That because the display content's height is equal with the Scrollview, left content was covered.
Then I remove the HeightRequest
in StackLayout, the ScrollView could scroll. But the scrollview will fill the whole page which I thought is not what you want. So you could add parent layout Stacklayout outside the scrollview which set the size of scrollview equal to 255 and let it scroll at the same time. I just made an example :
<StackLayout>
<ScrollView HeightRequest="255">
<StackLayout BindableLayout.ItemsSource="{Binding ItemCollection}" x:Name="SearchLayoutItemList" >
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid RowDefinitions="37,Auto">
<Image Grid.Row="0" Source=""searchingicon.png"" />
<Label Grid.Row="0" Text="{Binding name}" FontSize="14" TextColor="Black" Margin="50,0,0,0" HorizontalOptions="StartAndExpand" VerticalOptions="CenterAndExpand"/>
<Image Grid.Row="0" Source="reload.png" HorizontalOptions="EndAndExpand" Margin="0,0,15,0"/>
<BoxView Grid.Row="1" BackgroundColor="Yellow"/>
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
</StackLayout>
For more info, you could refer to Xamarin.Forms ScrollView.
Hope it works for you.

How to use a ListView in Xamarin Forms and keep it from growing to big

I need to display a list with about 30 to 40 items that the user has to choose from, and I don't wont to use a combobox, so a Listview seems the way to go.
However, once I put a listview on the page, the listview grows so much in height that it goes off the screen, how can I prevent that ?
I need something like this
<gttCompound:PageBase xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:gttCompound="clr-namespace:gttCompound.Pages"
x:Class="gttCompound.Pages.PageDamageSelectFromList">
<gttCompound:PageBase.ChildStackLayoutContent>
<StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand" Margin="5, 5">
<StackLayout VerticalOptions="Start" Orientation="Horizontal" HorizontalOptions="Center">
<Label Text="SELECT THE DAMAGE LOCATION" FontAttributes="Bold" FontSize="{StaticResource FontSizeLabelSmall}" TextColor="{StaticResource TextColor}" ></Label>
</StackLayout>
<StackLayout x:Name="entirePage" BackgroundColor="Yellow">
<ListView x:Name="listView" ItemsSource="{Binding Items}" Margin="0" BackgroundColor="Red">
<!-- ListView Stuff -->
</ListView>
</StackLayout>
<StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal" VerticalOptions="EndAndExpand">
<Button x:Name="ButtonDamageBack" WidthRequest="150" FontAttributes="Bold" HorizontalOptions="Start" TextTransform="Uppercase" Text="{Binding Back}" BackgroundColor="{StaticResource ElementBackgroundColor}" TextColor="{StaticResource ElementTextColor}" FontSize="{StaticResource FontSizeButtonLittle}" />
<Button x:Name="ButtonDamageNext" WidthRequest="150" FontAttributes="Bold" HorizontalOptions="EndAndExpand" TextTransform="Uppercase" IsEnabled="False" Text="{Binding Next}" BackgroundColor="{StaticResource ElementDisabledBackgroundColor}" TextColor="{StaticResource ElementTextColor}" FontSize="{StaticResource FontSizeButtonLittle}" />
</StackLayout>
</StackLayout>
</gttCompound:PageBase.ChildStackLayoutContent>
I gave some elements a noticable background color so I can see how much space they take
The listview takes way to much space.
Might it be because the page is an inherited page ?
The base page looks like this
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="gttCompound.Pages.PageBase"
xmlns:helpers="clr-namespace:gttCompound.Pages.Helpers">
<ContentPage.Resources>
<ResourceDictionary>
<helpers:StringNewLineConverter x:Key="StringNewLineConverter"/>
<helpers:StringToTitleCaseConverter x:Key="StringToTitleCaseConverter"/>
<helpers:StringSubstringConverter x:Key="StringSubstringConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<!-- All the stuff about the AbsoluteLayout is to get a WaitCursor that can show in the center of the screen, see this url
https://stackoverflow.com/questions/48295792/xamarin-forms-how-to-fix-activity-indicator-in-centre-of-screen-in-scrollview
-->
<AbsoluteLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<ScrollView AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<StackLayout>
<StackLayout x:Name="TopStackLayout" VerticalOptions="Start" BackgroundColor="{StaticResource HeaderColor}" Orientation="Horizontal">
<Frame VerticalOptions="Center" Padding="0" BackgroundColor="{StaticResource HeaderColor}" BorderColor="Transparent" WidthRequest="40">
<Button x:Name="ButtonBack" VerticalOptions="Start" Text="" Image="Back.png" BackgroundColor="{StaticResource HeaderColor}" TextColor="{StaticResource TextColor}" FontSize="8" HeightRequest="14" />
</Frame>
<Frame VerticalOptions="CenterAndExpand" Padding="0" BackgroundColor="{StaticResource HeaderColor}" BorderColor="Transparent">
<Label Text="{Binding AppName}" HorizontalOptions="Start" HorizontalTextAlignment="Center" TextColor="White" FontSize="{StaticResource FontSizeLabelBig}" Padding="0" x:Name="Page_Title" />
</Frame>
</StackLayout>
<StackLayout x:Name="ChildStackLayout" VerticalOptions="FillAndExpand" Orientation="Vertical" Margin="0,-6">
</StackLayout>
<StackLayout x:Name="BottomStackLayout" VerticalOptions="End" Orientation="Horizontal" BackgroundColor="{StaticResource HeaderColor}">
<Label x:Name="LabelUser" Text="" TextColor="White" FontSize="{StaticResource FontSizeLabelTiny}" BackgroundColor="{StaticResource HeaderColor}" Margin="0,0,0,-6" HorizontalTextAlignment="Start" IsVisible= "True" />
<Label x:Name="LabelVersion" Text="" HorizontalOptions="CenterAndExpand" TextColor="White" FontSize="{StaticResource FontSizeLabelTiny}" BackgroundColor="{StaticResource HeaderColor}" Margin="0,0,0,-6" HorizontalTextAlignment="Center" IsVisible= "True" />
<Label Text="{Binding CopyRight}" HorizontalOptions="EndAndExpand" BackgroundColor="{StaticResource HeaderColor}" HorizontalTextAlignment="End" TextColor="White" FontSize="{StaticResource FontSizeLabelTiny}" />
</StackLayout>
</StackLayout>
</ScrollView>
<AbsoluteLayout x:Name="LayoutWaitCursor" BackgroundColor="#22000000" AbsoluteLayout.LayoutBounds="0.5,0.5,1,1" AbsoluteLayout.LayoutFlags="All" IsVisible="false">
<ActivityIndicator IsVisible="true" IsRunning="True" Color="{StaticResource TextColor}" AbsoluteLayout.LayoutBounds="0.5,0.5,0.1,0.1" AbsoluteLayout.LayoutFlags="All" />
</AbsoluteLayout>
</AbsoluteLayout>
</ContentPage>
Here is how the form looks like at runtime
And without the listview it looks like this
I changed just this
<StackLayout x:Name="entirePage" BackgroundColor="Yellow">
<!--
<ListView x:Name="listView" ItemsSource="{Binding Items}" Margin="0" BackgroundColor="Red">
</ListView>
-->
</StackLayout>
What I want is that the listview is visible and scrollable, but the 2 buttons should always stay visible. The listview must only occupy the space between the label on top of the page and the 2 buttons on the bottom of the page.
How can I do that ?
1) REMOVE ScrollView.
2) <StackLayout x:Name="ChildStackLayout" VerticalOptions="FillAndExpand" .... Try different VerticalOptions. Try Center. Also try CenterAndExpand..
3) If still wrong, change the outer StackLayout to Grid, and use RowDefinitions="Auto,*,Auto", with the 3 sections marked Grid.Row="0" / "1" / "2".
ChildStackLayout is "1" (numbered from 0), so gets the * in RowDefinitions.

Why only the second Frame shows in a StackLayout

I have a Stacklayout that contains another Stacklayout and an Image. In order to have rounded corners for both children of the top Stacklayout, I added Frame for each child. Now, only the second child (Image) appear no matter how I change the visibility of the two children.
<StackLayout HeightRequest="135" WidthRequest="100" Margin="5,5" Grid.Row="0" Spacing="0" HorizontalOptions="Start" VerticalOptions="Start">
<Frame IsVisible="false" CornerRadius="5" IsClippedToBounds="True" Padding="0" HasShadow="False" x:Name="InitialsFrame">
<StackLayout IsVisible="false" HeightRequest="100" WidthRequest="100" BackgroundColor="{Binding Color}">
<Label FontSize="60" Text="{Binding Initials}" TextColor="White" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" MaxLines="1" x:Name="InitialsLabel">
</Label>
</StackLayout>
</Frame>
<Frame IsVisible="true" CornerRadius="5" IsClippedToBounds="True" Padding="0" x:Name="ImageFrame">
<Image IsVisible="true" Source="{Binding Image}" HeightRequest="100" WidthRequest="100" x:Name="IconImage" />
</Frame>
</StackLayout>
Without the two Frames, I could choose which child to appear by setting IsVisible to True. But now, setting IsVisible does not work any more. Is there another way to conditionally choose which child to appear?

Xamarin.Forms: can grid cell include several labels?

One of the grid cells looks like this:
<Label Text="{Binding Address1}" FontSize="12" TextColor="Black" Grid.Row="1" Grid.Column="0"/>
This displays Address1 which is correct.
But instead of just showing Address1, I would like to display Address1, City, St, each with a different FontSize.
Can this be done without altering the number of rows and columns in the grid?
One way is to place a StackLayout at the Grid row|column and then separately format each element within it:
<Grid....
~~~
<StackLayout Grid.Row="1" Grid.Column="0">
<Label Text="{Binding Address1}" FontSize="12" TextColor="Black" />
<StackLayout Orientation="Horizontal" >
<Label Text="{Binding City}" FontSize="10" TextColor="Black" />
<Label Text="{Binding St}" FontSize="10" TextColor="Black" />
</StackLayout>
<StackLayout>
~~~
</Grid>
Sure, you would use:
<StackLayout Grid.Row="1" Grid.Column="0">
<Label Text="l1"/>
<Label Text="l2"/>
<Label Text="l3"/>
</StackLayout>
You can use other layouts such as StackLayout inside of your Grid as others suggested but you can also put multiple Views inside a Grid cell by setting the same Grid.Row and Grid.Column for them and by setting HorizontalOptions and VerticalOptions of views inside the Grid you can choose each view position.
For Example:
<Grid....
~~~
<Label Grid.Row="0" Grid.Column="1" HorizontalOptions="Start" VerticalOptions="Start" Text="{Binding Address1}" FontSize="12" TextColor="Black" />
<Label Grid.Row="0" Grid.Column="1" HorizontalOptions="Start" VerticalOptions="End" Text="{Binding City}" FontSize="10" TextColor="Black" />
<Label Grid.Row="0" Grid.Column="1" HorizontalOptions="End" VerticalOptions="End" Text="{Binding St}" FontSize="10" TextColor="Black" />
~~~
</Grid>

TextWrapped Label breaks Layout Option FillAndExpand in StackLayout

I'm having a cell view with nested StackLayouts, there's one label that will be wrapped if the text is long, which is the desired behaviour. However, the wrap breaks the LayoutOptions set to (basically) all parent views resulting in a gray gap on the right hand side.
<StackLayout Orientation="Horizontal" BackgroundColor="Gray" Margin="0,30,0,0">
<BoxView
HorizontalOptions="Start"
BackgroundColor="#EEBB00"
WidthRequest="100"
/>
<StackLayout
BackgroundColor="#CC4400"
HorizontalOptions="FillAndExpand"
>
<BoxView
BackgroundColor="Green"
HeightRequest="10"
HorizontalOptions="FillAndExpand"
/>
<Label
FontSize="16"
HorizontalOptions="FillAndExpand"
Text="Name that is toolongandwillbewrapped"
/>
<StackLayout
Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
BackgroundColor="Blue"
>
<Label
FontSize="13"
Text="Left"
TextColor="White"
HorizontalOptions="StartAndExpand"
VerticalTextAlignment="End"
/>
<Label
FontSize="13"
Text="Right"
TextColor="White"
HorizontalOptions="EndAndExpand"
VerticalTextAlignment="End"
/>
</StackLayout>
</StackLayout>
</StackLayout>
The resulting views are:
So I can tell why this is happening, but well, of course I don't like it. The expected behaviour is for the right-hand-side stacklayout to expand all the way to the right. I've tried various ways to circumvent this and would not be here if I had succeeded. Does anybody have an idea?
Unfortunately, it's a bug in Xamarin.Forms (probably, iOS-only).
Bugzilla #28650
Bugzilla #31128
Bugzilla #33841
The workaround in that case is using Grid instead of StackLayout : http://forums.xamarin.com/discussion/comment/152969/#Comment_152969

Resources