Weirdly my display of screen is pushed down for only the MainPage thereafter display fits the screen as it should. I've tried deleting the page and re-adding it but that didn't work either. Does anyone know what could be causing this and how to fix it?
Here's what it looks like: The black space at the top should not be there
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="LoyaltyWorx.Views.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:LoyaltyWorx.Views.Converters"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
>
<ContentPage.Resources>
<ResourceDictionary>
<local:InvertBooleanConverter x:Key="InvertBooleanConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Image Source="bk3.jpg" Aspect="AspectFill"/>
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal" VerticalOptions="Start">
<!-- top controls -->
</StackLayout>
<StackLayout VerticalOptions="CenterAndExpand">
<!-- middle controls -->
<BoxView HeightRequest="430"></BoxView>
<Button Text="Continue with Facebook" x:Name="LoginBtn" BackgroundColor="#4867aa" TextColor="White" FontFamily="Klavika" HorizontalOptions="CenterAndExpand" Clicked="LoginBtn_Clicked" />
<Button Text="Continue with Google " Command="{Binding GoogleLoginCommand}" BackgroundColor="#d34836" TextColor="White" FontFamily="Klavika" HorizontalOptions="CenterAndExpand"/>
</StackLayout>
<StackLayout Orientation="Horizontal" VerticalOptions="End" HorizontalOptions="Center">
<!-- bottom controls -->
<Frame OutlineColor="White" HorizontalOptions="StartAndExpand">
<StackLayout Orientation="Horizontal" VerticalOptions="End" HorizontalOptions="Center">
<!-- bottom controls -->
<StackLayout Grid.Row="1" Orientation="Horizontal" Spacing="0">
<Label
Text="Terms and conditions"
FontSize="13"
TextColor="#71757a"
FontAttributes="Bold"
x:Name="LblTerms"/>
<Label
Text=" and"
FontSize="13"
TextColor="#71757a"
/>
<Label
Text=" privacy policy"
FontSize="13"
TextColor="#71757a"
FontAttributes="Bold"
x:Name="LblPrivacy"/>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
</StackLayout>
</Grid>
</ContentPage>
App.cs
public partial class App : PrismApplication
{
public App(IPlatformInitializer initializer = null) : base(initializer) { }
protected override void OnInitialized()
{
InitializeComponent();
SetMainPage();
NavigationService.NavigateAsync("NavigationPage/MainPage?title=Hello%20from%20Xamarin.Forms");
}
protected override void RegisterTypes()
{
Container.RegisterTypeForNavigation<NavigationPage>();
Container.RegisterTypeForNavigation<MainPage>();
}
private void SetMainPage()
{
if (!string.IsNullOrEmpty(Helpers.Settings.Usertoken))
{
Application.Current.MainPage = (new Profile());
}
else
{
MainPage = new NavigationPage(new MainPage())
{ BarBackgroundColor = Color.FromHex("#393b3d") };
}
}
public async static Task NavigateToSMS()
{
await Application.Current.MainPage.Navigation.PushAsync(new SMS());
}
public static void NavigateToProfile()
{
Application.Current.MainPage = (new InvalidLogin());
}
public static void NavigateToVerified()
{
Application.Current.MainPage = (new Profile());
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
You have your MainPage wrapped in a NavigationPage that by default shows the NavigationBar. You can turn it off in your cs code or in your MainPage.xaml
cs
var mainPage = new MainPage();
MainPage = new NavigationPage(mainPage);
NavigationPage.SetHasNavigationBar(mainPage, false);
xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="LoyaltyWorx.Views.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:LoyaltyWorx.Views.Converters"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
NavigationPage.HasNavigationBar="False">
Related
I created a custom control to be used in a listview. It almost works fine except for the custom property viewProgress that returns a boolean value based on the status of my order. Although the status gets his value correctly the boolean never gets reread and so the binding never receives a true value. I tried using breakpoints to detect if OnPropertyChanged is being run but it seems to never get there. The Item property seems to never get set, even though the data is bound. What am I doing wrong?
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"
xmlns:local="clr-namespace:HandTerminal"
x:Class="HandTerminal.OrderItem">
<ContentView.Content>
<StackLayout>
<Frame
Margin="10,6,10,6"
Padding="10"
CornerRadius="10">
<StackLayout>
<StackLayout
Padding="0"
HorizontalOptions="Fill"
Orientation="Horizontal">
<Label
FontAttributes="Bold"
FontSize="Medium"
Text="Ordernumber"
TextColor="{DynamicResource TitleTextColor}" />
<Label
FontSize="Medium"
HorizontalOptions="FillAndExpand"
HorizontalTextAlignment="End"
Text="{Binding Item.Ordernumber}"
TextColor="{DynamicResource SubtleTextColor}" />
</StackLayout>
<StackLayout
IsVisible="{Binding viewProgress}"
Orientation="Horizontal"
HorizontalOptions="FillAndExpand">
<Label
HorizontalOptions="Start"
Text="Picked"
TextColor="{DynamicResource HighlightTextColor}" />
<ProgressBar
HorizontalOptions="FillAndExpand"
Progress="{Binding Item.PickedProgress}" />
<StackLayout
HorizontalOptions="End"
Orientation="Horizontal">
<Label
Text="{Binding Item.TotalPicked}"
TextColor="{DynamicResource HighlightTextColor}" />
<Label
Text="/"
TextColor="{DynamicResource HighlightTextColor}" />
<Label
Text="{Binding Item.TotalAmount}"
TextColor="{DynamicResource HighlightTextColor}" />
</StackLayout>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
</ContentView.Content>
</ContentView>
Codebehind:
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace HandTerminal
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class OrderItem : ContentView
{
public OrderItem()
{
InitializeComponent();
Content.BindingContext = this;
}
public static BindableProperty ItemProperty = BindableProperty.Create(
propertyName: "Item",
returnType: typeof(Order),
declaringType: typeof(OrderItem),
defaultValue: new Order(),
defaultBindingMode: BindingMode.OneWay);
public Order Item
{
get
{
return (Order)GetValue(ItemProperty);
}
set
{
SetValue(ItemProperty, value);
OnPropertyChanged("Item");
OnPropertyChanged("viewProgress");
}
}
public static BindableProperty viewProgressProperty = BindableProperty.Create(
propertyName: "viewProgress",
returnType: typeof(bool),
declaringType: typeof(OrderItem),
defaultValue: false,
defaultBindingMode: BindingMode.OneWay);
public bool viewProgress
{
get
{
if (Item.Status == OrderStatus.Picking)
{
return true;
}
else
{
return false;
}
}
}
}
}
The ContentPage that uses the custom control:
<?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="HandTerminal.Orders"
xmlns:controls="clr-namespace:HandTerminal"
xmlns:d="clr-namespace:HandTerminal;assembly=HandTerminal">
<ContentPage.Content>
<StackLayout
Orientation="Vertical"
VerticalOptions="CenterAndExpand">
<ListView
HasUnevenRows="True"
ItemsSource="{Binding Orders}"
VerticalOptions="StartAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<controls:OrderItem Item="{Binding .}" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
I tried your code and my suggestions are:
Create a viewProgressConverter
public class viewProgressConverter : IValueConverter{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
OrderStatus myOrder =(OrderStatus) value ;
if (myOrder == OrderStatus.Picking)
return true;
else return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
} }
You will have to add it to your AppResources in the App.Xaml
2.Modify your OrderItem View, Removing all the "Item." binding directly to your Order
<StackLayout
HorizontalOptions="FillAndExpand"
IsVisible="{Binding Status, Converter={StaticResource progressConverter}}"
Orientation="Horizontal">
You can delete the Content.BindingContext = this; and comment/delete all the bindeable properties
I need some help with the basics of Xamarin.Forms in Visual Studio 2017, please.
I have written a class to hold certain properties that I can bind to on my content page. I have read a number of examples but each time I still can not get it right!
When I compile the page comes up with the label
<Label
Text="TestBinding"
Grid.Row="0"
Grid.Column="0"
HorizontalOptions="Start"
WidthRequest="100"
VerticalOptions="Center"/>
correctly, but the
<Label
Text="{Binding TestBinding}"
Grid.Row="0"
Grid.Column="1"
HorizontalOptions="Start"
WidthRequest="100"
VerticalOptions="Center"/>
comes up empty instead of the text Test binding so clearly I have got something wrong
Please can someone suggest what I am missing
I have stripped back the code to something simple here
So I believe my view class is
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Xamarin.Forms;
namespace FitRestults_Dev1
{
public class AddStudentView : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string _testtext="Test binding";
public string TestBinding
{
get=> _testtext;
set
{
if (string.Equals(_testtext, value))
return;
_testtext = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TestBinding)));
}
}
public ObservableCollection<GradeCollection> GradeCollection { get; set; }
public AddStudentView()
{ }
}
}
And my content page is
<?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="FitRestults_Dev1.AddStudent"
xmlns:local="clr-namespace:FitRestults_Dev1.AddStudentView;assembly=FitRestults_Dev1"
BindingContext="x:local "
>
<ContentPage.Content>
<StackLayout Padding="10" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Grid>
<Label Text="TestBinding " Grid.Row="0" Grid.Column="0" HorizontalOptions="Start" WidthRequest="100" VerticalOptions="Center"/>
<Label Text="{Binding TestBinding} " Grid.Row="0" Grid.Column="1" HorizontalOptions="Start" WidthRequest="100" VerticalOptions="Center"/>
</Grid>
<Button Text="Save" HorizontalOptions="FillAndExpand" BackgroundColor="Blue" TextColor="White" Clicked="Save_Clicked" />
<Button Text="Cancel" HorizontalOptions="FillAndExpand" BackgroundColor="Blue" TextColor="White" Clicked="Cancel_Clicked" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
And finally behind page code is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace FitRestults_Dev1
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AddStudent : ContentPage
{
public AddStudentView Source = new AddStudentView();
public AddStudent ()
{
InitializeComponent ();
BindingContext = Source;
}
async void Save_Clicked(object sender, System.EventArgs e)
{
var personItem = (Student)BindingContext;
await App.Database.SaveStudentAsync(personItem);
await Navigation.PopAsync();
}
async void Cancel_Clicked(object sender, System.EventArgs e)
{
await Navigation.PopAsync();
}
}
}
You can try the following code and let me know if you have any issues with this code. Thank you.
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"
x:Class="FitRestults_Dev1.AddStudent"
xmlns:local="clr
namespace:FitRestults_Dev1.AddStudentView;assembly=FitRestults_Dev1"
BindingContext="x:local ">
<ContentPage.Content>
<StackLayout Padding="10" HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Grid>
<Label Text="TestBinding " Grid.Row="0" Grid.Column="0"
HorizontalOptions="Start" WidthRequest="100" VerticalOptions="Center"/>
<Label Text="{Binding TestBinding} " Grid.Row="0" Grid.Column="1"
HorizontalOptions="Start" WidthRequest="100" VerticalOptions="Center"/>
</Grid>
<Button Text="Save" HorizontalOptions="FillAndExpand" BackgroundColor="Blue"
TextColor="White" Clicked="SaveCommand" />
<Button Text="Cancel" HorizontalOptions="FillAndExpand"
BackgroundColor="Blue" TextColor="White" Clicked="CancelCommand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
Xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AddStudent : ContentPage
{
public AddStudentView Source = new AddStudentView(this.Navigation);
public AddStudent ()
{
InitializeComponent ();
BindingContext = Source;
}
}
ViewModel :
public class AddStudentView : INotifyPropertyChanged
{
private ICommand _navigation;
public AddStudentView(INavigation navigation)
{
_navigation = naviation;
SaveCommand = new Command(SaveCommandHandler);
CancelCommand = new Command(CancelCommandHandler)
}
public string TestBinding
{
get {return _testBinding;}
set
{
_testBinding = value;
OnPropertyChanged();
}
}
public Command SaveCommand {get;set;}
public Command CancelCommand {get;set;}
public void SaveCommandHandler()
{
var value = TestBinding
_navigation.PopAsync();
}
public void CancelCommandHandler()
{
_navigation.PopAsync();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I have a base grid
<Grid Grid.Row="1" Grid.Column="1" x:Name="GridName">
<StackLayout Orientation="Vertical">
<art:GridOptionsView ItemsSource="{Binding Items}" >
<art:GridOptionsView.ItemTemplate>
<DataTemplate>
<uikit:DashboardItemTemplate />
</DataTemplate>
</art:GridOptionsView.ItemTemplate>
</art:GridOptionsView>
</StackLayout>
</Grid>
which uses the following DashboardItemTemplate
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
BackgroundColor="White">
<ContentView.Content>
<Grid Padding="0">
<StackLayout VerticalOptions="Center" HorizontalOptions="Center" Orientation="Vertical" Spacing="10">
<Grid>
<Label Text="" Style="{StaticResource FontIcon}" HorizontalTextAlignment="Center" Opacity="1" FontSize="130" TextColor="{Binding BackgroundColor}" VerticalOptions="Center" HorizontalOptions="Center" IsVisible="{Binding Source={x:Reference Root}, Path=ShowiconColoredCircleBackground}" />
<Label Text="{Binding Icon}" Style="{StaticResource FontIcon}" Opacity="1" TextColor="White" VerticalOptions="Center" HorizontalOptions="Center" />
</Grid>
<Label Text="{Binding Name}" TextColor="{Binding Source={x:Reference Root}, Path=TextColor}" FontSize="14" HorizontalTextAlignment="Center">
</Label>
</StackLayout>
</Grid>
</ContentView.Content>
<ContentView.GestureRecognizers>
<TapGestureRecognizer Tapped="OnWidgetTapped" />
</ContentView.GestureRecognizers>
</ContentView>
How can i capture the "OnWidgetTapped" event on my base xaml class?
I do this usually with a custom bindable property ParentBindingContext in my template:
public class MyTemplate : ContentPage
{
public static BindableProperty ParentBindingContextProperty = BindableProperty.Create(nameof(ParentBindingContext),
typeof(object), typeof(BasePageTemplate));
public object ParentBindingContext
{
get { return GetValue(ParentBindingContextProperty); }
set { SetValue(ParentBindingContextProperty, value); }
}
}
And then in your page (which contains the template) just set the ParentBindingContext:
<DataTemplate>
<template:MyTemplate ParentBindingContext="{Binding BindingContext, Source={x:Reference Name=MyPageName}}" />
</DataTemplate>
With that you can access the full BindingContext of your page in your template. The following example of a command shows how the template can bind to a command MyCommand, which is in the BindingContext of the page:
Command="{Binding ParentBindingContext.MyCommand, Source={x:Reference Name=MyTemplatePageName}}"
But this presupposes that your page has a BindingContext behind (like a ViewModel). This ViewModel then contains the "global" commands for the whole page. These commands (or just methods) can then be accessed by the template, because they know about the BindingContext of the page.
I changed an answer from flow description to the code. The idea is to create ItemTemplate programatically and pass to its constructor the page with list (or grid). Define a function ItemTemplateTapped and call it from template.
EventOnGridPage
<?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="ButtonRendererDemo.EventOnGridPage">
<ListView x:Name="listView" >
</ListView>
</ContentPage>
EventOnGridPage code behind
public partial class EventOnGridPage : ContentPage
{
public EventOnGridPage()
{
InitializeComponent();
listView.ItemsSource = new List<Contact>
{
new Contact { Name = "Kirti",Status = "True"},
new Contact { Name = "Nilesh",Status = "False"}
};
listView.ItemTemplate = new DataTemplate(loadTemplate);
}
private object loadTemplate()
{
return new ViewCell() { View = new EventOnGridTemplate(this) };
}
public void ItemTemplateTapped(string name)
{
DisplayAlert("ItemTemplateTapped", name, "OK");
}
}
EventOnGridTemplate xaml
<?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="ButtonRendererDemo.EventOnGridTemplate"
BackgroundColor="Green">
<Label Text="{Binding Name}" x:Name="myLabel"></Label>
</ContentView>
EventOnGridTemplate code behind
public partial class EventOnGridTemplate
{
EventOnGridPage parent;
public EventOnGridTemplate(EventOnGridPage parent)
{
this.parent = parent;
InitializeComponent();
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += TapGestureRecognizer_Tapped;
myLabel.GestureRecognizers.Add(tapGestureRecognizer);
}
private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
parent.ItemTemplateTapped(myLabel.Text);
}
}
If you already defined the tap gesture binding in the XAML code, you don't need to add the TapGestureRecognizer, simply sign your method to an event listener method:
Your XAML:
<ContentView.GestureRecognizers>
<TapGestureRecognizer Tapped="OnWidgetTapped" />
</ContentView.GestureRecognizers>
On C# code behind:
public void OnWidgetTapped(object sender, EventArgs args)
{
// do stuff here
}
You just need to implement your OnWidgetTapped method:
void OnWidgetTapped(object sender, System.EventArgs e)
{
// Do stuff here
}
Another solution. If you implemented OnWidgetTapped as was suggested you can use sender.Parent.Parent... till you get to the object you want - grid or page. Cast it to for example EventOnGridPage and then call the function of that object.
In Xamarin Forms, I want to implement a horizontal listview (like shown in the image below). Via Rotation this is possible, but the I cannot change the row width. Is there also a possibility the let the second layout start under the first one?
Thanks in advance!
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Recipe.Pages.SearchPage"
Title="Search">
<ContentPage.Content>
<StackLayout Spacing="5" x:Name="layout" Orientation="Vertical" >
<StackLayout x:Name="layoutButtons" HorizontalOptions="FillAndExpand" Orientation="Horizontal" Spacing="5" BackgroundColor="Red">
<Button x:Name="btn1" BackgroundColor="White" Image="#drawable/scan" />
<Button x:Name="btn2" BackgroundColor="White" Image="#drawable/menu" />
<Button x:Name="btn3" BackgroundColor="White" Image="#drawable/search" />
</StackLayout>
<StackLayout x:Name="layoutList" >
<ListView x:Name="listView" Rotation="270" RowHeight="75" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee" Orientation="Vertical" >
<StackLayout Orientation="Horizontal" >
<Button BackgroundColor="White" Rotation="90" Image="{Binding Recipe}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
EDIT
I also tried with a grid in the listview. Having the same issue.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Recipe.Pages.SearchPage"
Title="Search">
<ContentPage.Content>
<StackLayout Spacing="5" x:Name="layout" Orientation="Vertical" >
<StackLayout x:Name="layoutButtons" HorizontalOptions="FillAndExpand" Orientation="Horizontal" Spacing="5" BackgroundColor="Red">
<Button x:Name="btn1" BackgroundColor="White" Image="#drawable/scan" />
<Button x:Name="btn2" BackgroundColor="White" Image="#drawable/menu" />
<Button x:Name="btn3" BackgroundColor="White" Image="#drawable/search" />
</StackLayout>
<StackLayout x:Name="layoutList" >
<ListView x:Name="listView" Rotation="270" RowHeight="75" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" BackgroundColor="White" Rotation="90" Image="{Binding Recipe}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
I have also facing the same issue. I used below xaml code to manage the height and width of ListView.
<?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="VCRoom.HorizontalScroll">
<ContentPage.Content >
<RelativeLayout>
<ListView x:Name="TestListView"
RowHeight="80"
Rotation="270"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.5, Constant=-40}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=-0.5, Constant=40}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=Constant, Constant=80}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}"
>
</ListView>
</RelativeLayout>
</ContentPage.Content>
</ContentPage>
Change RowHeight and Constant in XConstraint and YConstraint to manage Width and height of horizontal ListView accordingly.
Just for reference Below is custom cell I used to populate ListView items. I displayed vertical labels in each list item.
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="VCRoom.TestCell">
<ViewCell.View>
<StackLayout Orientation="Horizontal" HorizontalOptions="End" VerticalOptions ="Center">
<Label Rotation="90" Text="{Binding Day}" TextColor="#000000" HorizontalOptions="StartAndExpand" VerticalOptions="Start"/>
<Label Rotation="90" Text="{Binding mDate}" TextColor="#000000" HorizontalOptions="StartAndExpand" VerticalOptions="Start"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
Hope this will help future users.
The best solution that i found to resolve this problem is making a CustomScrollView with properties from Listview, like is showed in the tutorial from the Fabio Cozzolino.
Pay attention that he has a updated version in the comments.
He created a custom scrollview:
public class TLScrollView : ScrollView
{ public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(CustomScrollView), default(IEnumerable),
BindingMode.Default, null, new BindableProperty.BindingPropertyChangedDelegate(HandleBindingPropertyChangedDelegate));
private static object HandleBindingPropertyChangedDelegate(BindableObject bindable, object value)
{
throw new NotImplementedException();
}
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly BindableProperty ItemTemplateProperty =
BindableProperty.Create("ItemTemplate", typeof(DataTemplate), typeof(CustomScrollView), default(DataTemplate));
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
public event EventHandler<ItemTappedEventArgs> ItemSelected;
public static readonly BindableProperty SelectedCommandProperty =
BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(CustomScrollView), null);
public ICommand SelectedCommand
{
get { return (ICommand)GetValue(SelectedCommandProperty); }
set { SetValue(SelectedCommandProperty, value); }
}
public static readonly BindableProperty SelectedCommandParameterProperty =
BindableProperty.Create("SelectedCommandParameter", typeof(object), typeof(CustomScrollView), null);
public object SelectedCommandParameter
{
get { return GetValue(SelectedCommandParameterProperty); }
set { SetValue(SelectedCommandParameterProperty, value); }
}
static void HandleBindingPropertyChangedDelegate(BindableObject bindable, object oldValue, object newValue)
{
var isOldObservable = oldValue?.GetType().GetTypeInfo().ImplementedInterfaces.Any(i => i == typeof(INotifyCollectionChanged));
var isNewObservable = newValue?.GetType().GetTypeInfo().ImplementedInterfaces.Any(i => i == typeof(INotifyCollectionChanged));
var tl = (CustomScrollView)bindable;
if (isOldObservable.GetValueOrDefault(false))
{
((INotifyCollectionChanged)oldValue).CollectionChanged -= tl.HandleCollectionChanged;
}
if (isNewObservable.GetValueOrDefault(false))
{
((INotifyCollectionChanged)newValue).CollectionChanged += tl.HandleCollectionChanged;
}
if (oldValue != newValue)
{
tl.Render();
}
}
private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Render();
}
}
Created a method to render the scrollview:
public void Render ()
{ if (ItemTemplate == null || ItemsSource == null)
{
Content = null;
return;
}
var layout = new StackLayout();
layout.Orientation = Orientation == ScrollOrientation.Vertical ? StackOrientation.Vertical : StackOrientation.Horizontal;
foreach (var item in ItemsSource)
{
var command = SelectedCommand ?? new Command((obj) =>
{
var args = new ItemTappedEventArgs(ItemsSource, item);
ItemSelected?.Invoke(this, args);
});
var commandParameter = SelectedCommandParameter ?? item;
var viewCell = ItemTemplate.CreateContent() as ViewCell;
viewCell.View.BindingContext = item;
viewCell.View.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = command,
CommandParameter = commandParameter,
NumberOfTapsRequired = 1
});
layout.Children.Add(viewCell.View);
}
Content = layout; }
Then, a customRenderer to each platform (Here iOS):
[assembly: ExportRenderer(typeof(TLScrollView), typeof(TLScrollViewRenderer))]
namespace TitiusLabs.Forms.iOS.Controls
{
class CustomScrollViewRenderer : ScrollViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
var element = e.NewElement as CustomScrollView;
element?.Render();
}
} }
You can use the FlowListView plugin to archive horizontal listview easily on xamarin forms.
NuGet - DLToolkit.Forms.Controls.FlowListView
Good Day everyone. I'm currently doing a simple application in Xamarin.Forms that allows me to CRUD record of an Employee. The created records are displayed on a ListView. Here's my screenshot.
What I want to do is whenever I click an Item on the ListView, is it will display a modal with a more detailed information of an Employee e.g (Birthday, Address, Gender, Work Experience). How can I do that? Is that even possible? Can you show me how?
This is my code that displays the ListView.
<?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="XamarinFormsDemo.EmployeeRecordsPage"
xmlns:ViewModels="clr-namespace:XamarinFormsDemo.ViewModels;assembly=XamarinFormsDemo"
xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin.Abstractions"
BackgroundImage="bg3.jpg"
Title="List of Employees">
<ContentPage.BindingContext>
<ViewModels:MainViewModel/>
</ContentPage.BindingContext>
<StackLayout Orientation="Vertical">
<ListView ItemsSource="{Binding EmployeesList, Mode=TwoWay}"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10" RowSpacing="10" ColumnSpacing="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<controls:CircleImage Source="icon.png"
HeightRequest="66"
HorizontalOptions="CenterAndExpand"
Aspect="AspectFill"
WidthRequest="66"
Grid.RowSpan="2"
/>
<Label Grid.Column="1"
Text="{Binding Name}"
TextColor="#24e97d"
FontSize="24"/>
<Label Grid.Column="1"
Grid.Row="1"
Text="{Binding Department}"
TextColor="White"
FontSize="18"
Opacity="0.6"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout Orientation="Vertical"
Padding="30,10,30,10"
HeightRequest="20"
BackgroundColor="#24e97d"
VerticalOptions="Center"
Opacity="0.5">
<Label Text="© Copyright 2015 smesoft.com.ph All Rights Reserved "
HorizontalTextAlignment="Center"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</StackLayout>
</ContentPage>
NOTE: Records that are displayed are CREATED in ASP.NET Web Application and just displayed on a ListView in UWP. If you need to see more codes, just please let me know.
Thanks a lot Guys.
To bind a command to item selected property see the example bellow otherwise ItemSelected will bind to a model property only
For full example see https://github.com/TheRealAdamKemp/Xamarin.Forms-Tests/blob/master/RssTest/View/Pages/MainPage.xaml.cs
Now you can bind an Icommand which could have something like
private Command login;
public ICommand Login
{
get
{
login = login ?? new Command(DoLogin);
return login;
}
}
private async void DoLogin()
{
await Navigation.PopModalAsync(new MySampXamlPage());
//await DisplayAlert("Hai", "thats r8", "ok");
}
and view :
[Navigation.RegisterViewModel(typeof(RssTest.ViewModel.Pages.MainPageViewModel))]
public partial class MainPage : ContentPage
{
public const string ItemSelectedCommandPropertyName = "ItemSelectedCommand";
public static BindableProperty ItemSelectedCommandProperty = BindableProperty.Create(
propertyName: "ItemSelectedCommand",
returnType: typeof(ICommand),
declaringType: typeof(MainPage),
defaultValue: null);
public ICommand ItemSelectedCommand
{
get { return (ICommand)GetValue(ItemSelectedCommandProperty); }
set { SetValue(ItemSelectedCommandProperty, value); }
}
public MainPage ()
{
InitializeComponent();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
RemoveBinding(ItemSelectedCommandProperty);
SetBinding(ItemSelectedCommandProperty, new Binding(ItemSelectedCommandPropertyName));
}
protected override void OnAppearing()
{
base.OnAppearing();
_listView.SelectedItem = null;
}
private void HandleItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
{
return;
}
var command = ItemSelectedCommand;
if (command != null && command.CanExecute(e.SelectedItem))
{
command.Execute(e.SelectedItem);
}
}
}
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:ValueConverters="clr-namespace:RssTest.ValueConverters;assembly=RssTest"
x:Class="RssTest.View.Pages.MainPage"
Title="{Binding Title}">
<ContentPage.Resources>
<ResourceDictionary>
<ValueConverters:BooleanNegationConverter x:Key="not" />
</ResourceDictionary>
</ContentPage.Resources>
<Grid VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<ListView x:Name="_listView"
IsVisible="{Binding IsLoading, Converter={StaticResource not}" ItemsSource="{Binding Items}"
ItemSelected="HandleItemSelected"
VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ActivityIndicator IsVisible="{Binding IsLoading}" IsRunning="{Binding IsLoading}"
VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" />
</Grid>
</ContentPage>