I have a problem with my project, I'm using MasterDetailPage with a simple ListView and using a local namespace to call another page inside of him with a ListView too, and have THIS result, the problem is, that white space between the toolbar and the listview, but if I try to navigate for this very page without using the MasterDetailPage, the listview works fine without this white space, and you check HERE
App.cs navigates to MenuPage.Xaml
MainPage = new NavigationPage(new MenuPage());
MenuPage.XAML
`<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Gone.MenuPage"
xmlns:local="clr-namespace:Gone;assembly=Gone">
<MasterDetailPage.Master>
<ContentPage Title="Menu">
<ListView BackgroundColor="Transparent"
SeparatorVisibility="Default"
HasUnevenRows="True"
x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="2" Orientation="Horizontal">
<Image Aspect="Fill" WidthRequest="60" HeightRequest="60" Source="{Binding image}"/>
<StackLayout Padding="5,18,0,0" Orientation="Vertical">
<Label TextColor="Black" Text="{Binding title}"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<local:MainPage/>
</MasterDetailPage.Detail>
</MasterDetailPage>`
MainPage.Xaml
<ListView BackgroundColor="Transparent"
SeparatorVisibility="Default"
HasUnevenRows="True"
x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Image Aspect="AspectFill" WidthRequest="130" HeightRequest="130" Source="{Binding image}"/>
<StackLayout Padding="20" Orientation="Vertical">
<Label LineBreakMode="WordWrap" FontSize="17" TextColor="#4CAF50" Text="{Binding title}"/>
<Label FontAttributes="Bold" TextColor="#2962FF" Text="{Binding price}"/>
<Label TextColor="#455A64" Text="{Binding date}"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
A temporary solution is
Creating a CustomMasterDetailRenderer in your Android Project:
[assembly: ExportRenderer(typeof(MasterDetailPage), typeof(CustomMasterDetailRenderer))]
namespace Your.Name.Space
{
public class CustomMasterDetailRenderer : MasterDetailPageRenderer
{
public override void AddView(Android.Views.View child)
{
child.GetType().GetRuntimeProperty("TopPadding").SetValue(child, 0);
var padding = child.GetType().GetRuntimeProperty("TopPadding").GetValue(child);
base.AddView(child);
}
}
}
Maybe is needed set Padding 0 in your view.
Thanks to Sylvia Martinez:
https://forums.xamarin.com/discussion/comment/244966/#Comment_244966
This happens if you use MasterDetailPage with NavigationPage.
Don't declare MasterDetailPage as new NavigationPage(new MasterDetailPage()).
Instead declare MasterDetailPage as var masterDetailPage = new MasterDetailPage().
After that use masterDetailPage.Detail = new NavigationPage(new ContentPage());
So if you have navigation both through masterDetail and navigation, you will come up with several NavigationPages. And you won't be able to use just Navigation.PushAsync(somePage). Instead of it you will have to use the current NavigationPage instance like: ((NavigationPage)(this.Detail)).PushAsync(new ContentPage());
Related
I am having issues binding the values of a string[] to the DataTemplate of a BindableLayout. I have recreated the issue in the AboutPage of the Shell Flyout Template.
AboutPage.xaml
<ContentPage.BindingContext>
<vm:AboutViewModel />
</ContentPage.BindingContext>
<StackLayout VerticalOptions="Center"
Padding="20"
BindableLayout.ItemsSource="{Binding Data}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label FontSize="Large"
Text="{Binding .}"
BackgroundColor="PowderBlue"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
AboutViewModel.cs
namespace App2.ViewModels
{
public class AboutViewModel : BaseViewModel
{
private string[] _data;
public string[] Data
{
get
{
return _data;
}
set
{
if (_data != value)
{
_data = value;
OnPropertyChanged();
}
}
}
public AboutViewModel()
{
Title = "About";
Data = new string[] { "One", "Two", "Three" };
}
}
}
When the page first opens, the the correct number of labels are there but without any text.
If I edit the Text="{Binding .}" the binding works after Xaml Hot Reload.
Why on earth are the strings not being displayed in the first place when they're clearly not empty or null?
I have solved this problem in an unexpected way. Simply by moving the DataTemplate into its own file, this problem goes away. Can someone please explain to me why this works? My new code produces two StackLayouts side by side, bound to the same data but only the Stackview on the right, with its DataTemplate defined elsewhere as ListItemView.xaml shows the data when the app is run. The StackView on the left has empty Labels at first, then after I delete the full-stop (.) from Text="{Binding .}" and replace it, Xaml Hot Reload runs and the strings are displayed.
ListItemView.xaml
<DataTemplate xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App2.Views.ListItemView">
<Label FontSize="Large"
Text="{Binding ., Mode=OneWay}"
BackgroundColor="PowderBlue"/>
</DataTemplate>
AboutPage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App2.Views.AboutPage"
xmlns:vm="clr-namespace:App2.ViewModels"
xmlns:views="clr-namespace:App2.Views"
Title="{Binding Title}"
x:DataType="vm:AboutViewModel">
<ContentPage.BindingContext>
<vm:AboutViewModel />
</ContentPage.BindingContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<StackLayout VerticalOptions="Center"
Padding="20"
BindableLayout.ItemsSource="{Binding Data}"
Grid.Column="0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label FontSize="Large"
Text="{Binding ., Mode=OneWay}"
BackgroundColor="PowderBlue"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<StackLayout VerticalOptions="Center"
Padding="20"
BindableLayout.ItemsSource="{Binding Data}"
Grid.Column="1">
<BindableLayout.ItemTemplate>
<views:ListItemView />
</BindableLayout.ItemTemplate>
</StackLayout>
</Grid>
</ContentPage>
I solved this in a similar way. I did create a separate DataTemplate, but not in its own file. The addition I made was to add an x:DataType attribute.
<DataTemplate x:Key="myLabel" x:DataType="x:String">
<StackLayout>
<Label Text="{Binding .}" />
</StackLayout>
</DataTemplate>
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>
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>