I'm developing a mobile application and I want to put one Grid in the SrollView, under it a ListView with the height of its elements, under the ListView another ListView with same height.
I put two Listviews in StackLayout. It should look something like that
This is content that should scroll in ScrollView
But with this implementation(code below), the first ListView Occupies the entire remaining height, and the second Listview is far from it
there is listview height at the full remaining size
And my second Listview after scrolling is far away, here
It also occupies the entire height of the scrollview
Here is the code:
<ScrollView>
<Grid RowSpacing="2">
<Grid.RowDefinitions>
<RowDefinition Height="130"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid x:Name="RecommendedCaloriesGrid" Grid.Row="0" RowSpacing="2" ColumnSpacing="1"
BackgroundColor="Violet" Margin="3">
// here is code of my Grid 1
</Grid>
</Grid>
<StackLayout Grid.Row="1"> // here I want to make a listview under Each other
<ListView x:Name="ItemsListView" BackgroundColor="red"
ItemsSource="{Binding Items}"
HasUnevenRows="true"
RefreshCommand="{Binding LoadItemsCommand}"
IsPullToRefreshEnabled="true"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
CachingStrategy="RecycleElement"
ItemSelected="OnItemSelected">
<d:ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>First Item</x:String>
<x:String>Second Item</x:String>
</x:Array>
</d:ListView.ItemsSource>
<ListView.Header>
<StackLayout Margin="5" Spacing="2">
<StackLayout Orientation="Horizontal">
<Label Text="Завтрак" HorizontalOptions="StartAndExpand"
FontSize="Large" FontAttributes="Bold"/>
<Label Text="744 ккал" HorizontalOptions="EndAndExpand"
FontSize="Large" FontAttributes="Bold"/>
</StackLayout>
<Label Text="Рекомендуется 30% от суточного потребления (n ккал)." FontSize="11"/>
</StackLayout>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10">
<Label Text="{Binding Text}"
d:Text="{Binding .}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Label Text="{Binding Description}"
d:Text="Item descripton"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView x:Name="LunchListView" // second ListView under first
ItemsSource="{Binding Items}"
HasUnevenRows="true"
RefreshCommand="{Binding LoadItemsCommand}"
IsPullToRefreshEnabled="true"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
CachingStrategy="RecycleElement"
ItemSelected="OnItemSelected">
<d:ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>First Item</x:String>
<x:String>Second Item</x:String>
<x:String>Third Item</x:String>
<x:String>Forth Item</x:String>
</x:Array>
</d:ListView.ItemsSource>
// SAME logic here
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</Grid>
</ScrollView>
How I can fix it?
Please help me to find a solution.
I read many articles like below, but did not find the answer. I want to do this without calculating the height in code-behind:
Xamarin.Forms ListView size to content?
Xamarin.Forms - ListView change height at runtime
https://forums.xamarin.com/discussion/comment/66248
Xamarin.Forms: ListView inside StackLayout: How to set height?
Why did you use two listviews to do this, you can just use different DataTemplate to achieve this function.
You can refer to the following code:
1.Consuming a DataTemplateSelector in XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-
namespace:Selector;assembly=Selector" x:Class="Selector.HomePage">
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="validPersonTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="invalidPersonTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<local:PersonDataTemplateSelector x:Key="personDataTemplateSelector"
ValidTemplate="{StaticResource validPersonTemplate}"
InvalidTemplate="{StaticResource invalidPersonTemplate}" />
</ResourceDictionary>
</ContentPage.Resources>
...
</ContentPage>
2.use like this:
<ListView x:Name="listView" ItemTemplate="{StaticResource personDataTemplateSelector}"
/>
For more details, you can check:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/data-templates/selector
Besides, you can also try ListView Grouping, for more details:
https://learn.microsoft.com/en-ie/xamarin/xamarin-forms/user-interface/listview/
https://learn.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/userinterface-listview-grouping/
the first ListView Occupies the entire remaining height
For me it looks like its the issue with footer which is taking extra space inside listview. Can you just put the Empty listview footer and see if it works:
<ListView.Footer>
<Label />
</ListView.Header>
Related
I have this xaml structure to display categories in CollectionView.
<CollectionView ItemsSource="{Binding Categories}" Grid.ColumnSpan="2">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Horizontal" HorizontalItemSpacing="2"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="{x:Type m:Category}">
<Grid Padding="5">
<Frame CornerRadius="10" IsClippedToBounds="True" BorderColor="LightGray">
<Label Text="{Binding Name}"/>
</Frame>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I get this result.[1]: https://i.stack.imgur.com/GoHlu.png. But I want to show by 2 categories like on this picture [1]: https://i.stack.imgur.com/S3nZK.png. How can I autosize them by width, so there was not parts of other categories?
Hoping you can advise as I've tried all methods to bind a picker in a Listview to my item source values using both code-behind and MVVM. The picker binding works outside of the ListView, but not inside - is this out of the box or just not possible?
Please see my list below!
code
<ListView
x:Name="TypesList"
HeightRequest="53"
BackgroundColor="White"
IsGroupingEnabled="True"
IsPullToRefreshEnabled="false"
ItemsSource="{Binding Items}"
IsRefreshing="{Binding IsBusy}"
RefreshCommand="{Binding LoadTypesCommand}"
SeparatorVisibility="None"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Height="63">
<StackLayout Orientation="Horizontal" VerticalOptions="Center">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="150"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="70"/>
</Grid.ColumnDefinitions>
<!-- -->
<Label Grid.Column="0"
Grid.Row="0"
VerticalOptions="Center"
FontAttributes="None"
Text="{Binding .Name, Mode=TwoWay} "
TextColor="Black"
VerticalTextAlignment="Center"
Margin="0,15,0,110"
BackgroundColor="White"
Padding="20,10,0,10"
FontFamily="Hiragino Sans"
FontSize="14"
HeightRequest="53"
x:Name="userLabel"
/>
<Entry Grid.Column="1"
Grid.Row="0"
Text="{Binding .Amount, Mode=TwoWay}"
TextColor="Black"
VerticalOptions="EndAndExpand"
Margin="0,15,20,110"
BackgroundColor="White"
FontFamily="Hiragino Sans"
FontSize="14"
HeightRequest="40"
WidthRequest="55"
x:Name="userEntry"
/>
<Picker Grid.Column="2"
Grid.Row="0"
x:Name="mPicker"
ItemsSource="{Binding UserOptions}"
/>
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
code
Code behind
code
mPicker.ItemsSource = ViewModel.UserOptions;
code
The model allocates UserOptions and this works for a picker outside the listview so I don't believe there is anything wrong with the model or this code needs to be posted.
Any help appreciated!
List view has its own binding context. So you need to get binding context of view model and then bind to picker like this
Set a name of your view like this
<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"
x:Name="viewName">
<Picker Grid.Column="2"
Grid.Row="0"
x:Name="mPicker"
ItemsSource="{Binding BindingContext.UserOptions, Source={x:Reference viewName}}"
/>
I have a listview. This list view has 5 rows with two buttons namely A & B. When I tap on button A on a row, I want to change the image on A as well as B on the same row and vice-versa. I am able to individually tap and change the image on the same button but don't know how to change the image on the other button. Here is my listview:
<ListView x:Name="GroupedView" SeparatorColor="Transparent" GroupDisplayBinding="{Binding Title}" IsGroupingEnabled="true" HasUnevenRows="true" >
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Padding="5" BackgroundColor="#E2F5F9">
<Label Text="{Binding Title}" TextColor="{StaticResource NavyBlue}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Spacing="2" Padding="5">
<StackLayout VerticalOptions="FillAndExpand">
<Label Text="{Binding QuestionName}" />
</StackLayout>
<StackLayout IsVisible="{Binding ShowYesNo}" Spacing="15" Orientation="Horizontal" HorizontalOptions="End">
<Button ClassId="Yes" Clicked="ChoiceSelected" CommandParameter="{Binding question_id}" Image="{Binding YesChoiceImg}" />
<Button ClassId="No" Clicked="ChoiceSelected" CommandParameter="{Binding question_id}" Image="{Binding NoChoiceImg}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I am then using the sender to identify the class ID and change the image of the button.
Should I be using a command? Should I be doing something else? Please help. Thanks
If you want to use the CommandParameter you should be using a Command. At the moment you're mixing 2 different ways to handle the click.
One thing to note though is that if you use a command you usually want to bind it to a Command that is defined on your ViewModel but since inside the DataTemplate your BindingContext is the ListView item instead of the ViewModel so you have to reference around that. Something like this should work:
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Spacing="2" Padding="5">
<StackLayout VerticalOptions="FillAndExpand">
<Label Text="{Binding QuestionName}" />
</StackLayout>
<StackLayout IsVisible="{Binding ShowYesNo}" Spacing="15" Orientation="Horizontal" HorizontalOptions="End">
<Button ClassId="Yes" Command="{Binding Path=BindingContext.ButtonCommand, Source={x:Reference MyQuestionPage}}" CommandParameter="{Binding .} Image="{Binding YesChoiceImg}" />
<Button ClassId="No" Clicked="ChoiceSelected" CommandParameter="{Binding question_id}" Image="{Binding NoChoiceImg}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
Note here that you have to give your ContentPage an x:Name (so you can reference it and call the BindingContext on it). And the "{Binding .}" binds to the current list item. So no need to search for it on id you can just plug it into the command directly!
I have this .XAML page and Scroll doesn't work
Its working fine when I have remove AbsoluteLayout and take stacklayout.
<ScrollView>
<AbsoluteLayout>
<ListView x:Name="lstView" ItemsSource="{Binding Items}" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1"
ItemSelected="lstView_ItemSelected">
<ListView.Header>
<Label Text="Store Allocation" BackgroundColor="White" TextColor="Black" FontAttributes="Bold" HorizontalOptions="Fill" HorizontalTextAlignment="Center" />
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}" Height="200" Detail="{Binding Detail}" DetailColor="Black" TextColor="Red" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<BoxView AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1" BackgroundColor="LightGray" Opacity="0.7" InputTransparent="False" IsVisible="{Binding Path=IsBusy, Source={x:Reference Page}}" />
<ActivityIndicator IsRunning="{Binding Path=IsBusy, Source={x:Reference Page}}" AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds=".5,.5,-1,-1" />
</AbsoluteLayout>
</ScrollView>
Your XAML basically "says" put a ScrollView on the page, with an AbsoluteLayout filling that ScrollView. Since the inner layout perfectly fits the ScrollView there is no need to scroll. Moreover the ListView and the BoxView are set to take the whole AbsoluteLayout (AbsoluteLayout.LAyoutBounds="0,0,1,1"), no more no less. Why should the ScrollView scroll?
Furthermore, if it worked that way, you'd scroll the ActivityIndicator with everything else, which is supposedly not what you want. I'd assume that you'd like to keep the ActivityIndicator in place, on top of the ListView.
What you could try (I'm not 100% sure, but it should work) is wrapping the ListView only with the ScrollView and put the ScrollView in the AbsoluteLayout this way, the ScrollView will recognize the ListView being too large for the screen and enable scrolling, while everything else stays in place:
<AbsoluteLayout>
<ScrollView AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1">
<ListView x:Name="lstView" ItemsSource="{Binding Items}"
ItemSelected="lstView_ItemSelected">
<ListView.Header>
<Label Text="Store Allocation" BackgroundColor="White" TextColor="Black" FontAttributes="Bold" HorizontalOptions="Fill" HorizontalTextAlignment="Center" />
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}" Height="200" Detail="{Binding Detail}" DetailColor="Black" TextColor="Red" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollView>
<BoxView AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1" BackgroundColor="LightGray" Opacity="0.7" InputTransparent="False" IsVisible="{Binding Path=IsBusy, Source={x:Reference Page}}" />
<ActivityIndicator IsRunning="{Binding Path=IsBusy, Source={x:Reference Page}}" AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds=".5,.5,-1,-1" />
</AbsoluteLayout>
You can also manually set the height of your AbsoluteLayout.
<ScrollView>
<AbsoluteLayout HeightRequest="800">
<!--Page Contents-->
</AbsoluteLayout>
</ScrollView>
I developing app with Visual Studio to Android, and I have file ItemsPage.xaml with this code :
<ContentPage.Content>
<StackLayout>
<ListView x:Name="ItemsListView" ItemsSource="{Binding Items}" VerticalOptions="FillAndExpand" HasUnevenRows="true" RefreshCommand="{Binding LoadItemsCommand}" IsPullToRefreshEnabled="true" IsRefreshing="{Binding IsBusy, Mode=OneWay}" CachingStrategy="RecycleElement" ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout x:Name="General" Orientation="Horizontal" HorizontalOptions="Fill" Padding="5">
<Image Source="{Binding FileName, Converter={StaticResource ImageConverter}}" HeightRequest="150" WidthRequest="150" AbsoluteLayout.LayoutBounds="250.25, 0.25, 50, 50 "/>
<StackLayout Orientation="Vertical">
<Label Text="ST:" /><Label Text = "{Binding ST_string}" FontSize="24" AbsoluteLayout.LayoutBounds="0.25, 0.25, 400, 40"/>
<Label Text="Folio:" /><Label Text = "{Binding Folio_string}" FontSize="24" AbsoluteLayout.LayoutBounds="0.25, 0.25, 400, 40"/>
<Label Text="txt" /><Label Text = "{Binding Sent} " FontSize="24" AbsoluteLayout.LayoutBounds="0.25, 0.25, 400, 40"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
And in my ItemsPage.xaml.cs I can't access to my StackLayout with Name="General", I need paint this with color, but I can't, please help.
In general I can't do General.Background, I don't know access this.
Thanks!
Elements inside a DataTemplate are not accessible from outside the DataTemplate; this includes the code-behind (the xaml.cs file).
DataTemplates are handled in a special way. They're used as a template (hence the name) for each item inside the ListView. This means that at runtime there's going to be an instance of the contents inside the DataTemplate for each item. If you have 20 items in that list, there's going to be 20 StackLayouts with the name General. You can read about DataTemplates in the docs.
If you want to set the background color of the StackLayout, the easiest way is to do that directly on the StackLayout element:
<StackLayout x:Name="General" BackgroundColor="Blue" Orientation="Horizontal"...
Alternatively you can create a ContentView and put that inside the ViewCell. The BindingContext of the ContentView will automatically be set to the current item. ContentViews are a bit like ContentPages, but you can use them inside a page like any other View (like a Button or a BoxView.
Edit
To add a ContentView right-click and add a new file, choose ContentView. Put the XAML inside ViewCell inside the ContentView:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Testing.MyView">
<ContentView.Content>
<StackLayout x:Name="General" Orientation="Horizontal" HorizontalOptions="Fill" Padding="5">
<Image Source="{Binding FileName, Converter={StaticResource ImageConverter}}" HeightRequest="150" WidthRequest="150" AbsoluteLayout.LayoutBounds="250.25, 0.25, 50, 50 " />
<StackLayout Orientation="Vertical">
<Label Text="ST:" />
<Label Text="{Binding ST_string}" FontSize="24" AbsoluteLayout.LayoutBounds="0.25, 0.25, 400, 40" />
<Label Text="Folio:" />
<Label Text="{Binding Folio_string}" FontSize="24" AbsoluteLayout.LayoutBounds="0.25, 0.25, 400, 40" />
<Label Text="txt" />
<Label Text="{Binding Sent} " FontSize="24" AbsoluteLayout.LayoutBounds="0.25, 0.25, 400, 40" />
</StackLayout>
</StackLayout>
</ContentView.Content>
</ContentView>
In the code-behind, you can access all controls:
public partial class MyView : ContentView
{
public MyView()
{
InitializeComponent();
General.BackgroundColor = true ? Color.Blue : Color.Brown;
}
}
Then add the ContentView to the ViewCell:
<ListView x:Name="ItemsListView" ItemsSource="{Binding Items}" VerticalOptions="FillAndExpand" HasUnevenRows="true" RefreshCommand="{Binding LoadItemsCommand}" IsPullToRefreshEnabled="true" IsRefreshing="{Binding IsBusy, Mode=OneWay}" CachingStrategy="RecycleElement" ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<local:MyView/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>