How to achieve a google material design entry / input in Xamarin.Forms (so no renderers, etc), even without the animation of the bottom label ?
Below code is a Xamarin.Forms google material design like entry approach. Total xaml + a little coding :)
Step1: Create a class in PCL project
public class CustomEntry : Entry
{
}
Step2: Create a control template in App.xaml
<ControlTemplate x:Key="MyControlTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<controls:CustomEntry x:Name="myEntry" Text="{TemplateBinding Text, Mode=TwoWay}" HorizontalOptions="FillAndExpand" HorizontalTextAlignment="Start" IsPassword="{TemplateBinding IsPassword}" MinimumHeightRequest="25"/>
<BoxView Grid.Row="1" BackgroundColor="#D2D2D2" HeightRequest="1" HorizontalOptions="FillAndExpand" VerticalOptions="Start">
<BoxView.Triggers>
<DataTrigger TargetType="BoxView" Binding="{Binding Source={x:Reference myEntry}, Path=IsFocused}" Value="true">
<Setter Property="BackgroundColor" Value="Black" />
<Setter Property="HeightRequest" Value="2"/>
</DataTrigger>
</BoxView.Triggers>
</BoxView>
</Grid>
</ControlTemplate>
Step 3: Create a super material design entry class
public class MyMaterialDesignEntry : ContentView, INotifyPropertyChanged
{
public static readonly BindableProperty TextProperty =
BindableProperty.Create("Text", typeof(string), typeof(ContentPage), "");
public static readonly BindableProperty IsPasswordProperty =
BindableProperty.Create("IsPassword", typeof(bool), typeof(ContentPage), false);
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, (string)value); }
}
public bool IsPassword => (bool)GetValue(IsPasswordProperty);
public MyMaterialDesignEntry()
{
ControlTemplate = (ControlTemplate)Application.Current.Resources.FirstOrDefault(x => x.Key == "MyControlTemplate").Value;
}
}
Step 4: Use your super material design entry in xaml
<StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand">
<Label Text="Login"/>
<controls:MyMaterialDesignEntry Text="{Binding Login, Mode=TwoWay}"/>
</StackLayout>
Don't forget to add appropriate namespaces to your page xaml. It will tell you anyway.
Related
I am getting this runtime error saying that the CellView needs a View. I have not found anything on this so far, here on StackOverflow or on google, so I am in the total dark about what needs to be fixed.
I need to set up a list view with 2 sections. the first one is for the bikes that are in the database and the other section is for the ones that we detected but are not saved in the DB yet.
Both sections use the same UI (cell) and so I need to be able to have a sliding button (ContextAction MenuItem) in the first section and for the second section this action needs to be disabled/removed.
If it's not possible then I would need to have the action for the second section "Add" instead of "Forget".
This is why I created a subclass.
this is my code.
(edit: corections)
---- .xaml file ----
<?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="EGrid18.Components.BikeSelectionCell"
x:Name="ThisCell">
<ViewCell.View>
<StackLayout>
<Grid ColumnSpacing="10"
BindingContext="{x:Reference ThisCell}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="32"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding BikeName}"
StyleClass="bikecellname"
Grid.Row="0"
Grid.Column="0"
VerticalOptions="Center"
HorizontalOptions="StartAndExpand"/>
<Image Source="{Binding Image}"
HeightRequest="16"
WidthRequest="16"
VerticalOptions="Center"
Aspect="AspectFit"
Grid.Column="1"
Grid.Row="0"/>
<Label Text="{Binding Distence, StringFormat='{0:F2} M'}"
Grid.Row="0"
Grid.Column="2"
VerticalOptions="Center"/>
</Grid>
</StackLayout>
</ViewCell.View>
</ViewCell>
---- .cs file ----
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace EGrid18.Components
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class BikeSelectionCell : ViewCell
{
public static BindableProperty BikeNameProperty =
BindableProperty.Create(nameof(BikeName), typeof(string), typeof(BikeSelectionCell), string.Empty);
public string BikeName
{
get => (string)GetValue(BikeNameProperty);
set => SetValue(BikeNameProperty, value);
}
public static BindableProperty ImageProperty =
BindableProperty.Create(nameof(Image), typeof(string), typeof(BikeSelectionCell), string.Empty);
public string Image
{
get => (string)GetValue(ImageProperty);
set => SetValue(ImageProperty, value);
}
public static BindableProperty DistenceProperty =
BindableProperty.Create(nameof(Distence), typeof(double), typeof(BikeSelectionCell), 0.0);
public double Distence
{
get => (double)GetValue(DistenceProperty);
set => SetValue(DistenceProperty, value);
}
public static readonly BindableProperty ForgetCommandProperty =
BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(BikeSelectionCell), null);
public ICommand ForgetCommand
{
get { return (ICommand)GetValue(ForgetCommandProperty); }
set { SetValue(ForgetCommandProperty, value); }
}
public Command OnForget => new Command(() => Execute(ForgetCommand));
// Helper method for invoking commands safely
public static void Execute(ICommand command)
{
if (command == null) return;
if (command.CanExecute(null))
{
command.Execute(null);
}
}
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if(propertyName == nameof(Image))
{
this.ContextActions.Clear();
if (Image != "unknown")
{
this.ContextActions.Add(new MenuItem()
{
Text = "Forget",
Command = ForgetCommand,
CommandParameter = this
});
}
}
}
}
}
--- the .xaml file that consumes the CellView subclass ---
<?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:vm="clr-namespace:EGrid18.ViewModels"
xmlns:iOS="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
xmlns:components="clr-namespace:EGrid18.Components"
iOS:Page.UseSafeArea="True"
x:Class="EGrid18.Views.BikeSelectionPage"
Title="Bike Selection List">
<ContentPage.Resources>
<ResourceDictionary>
<vm:BikeListViewModel x:Key="vm"/>
<StyleSheet Source="/CSS/Styles.css"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.ToolbarItems>
<ToolbarItem x:Name="ScanButton" Text="Scan"
Command="{Binding Source={StaticResource vm}, Path=OnScanCommand}"
CommandParameter="{Binding Source={StaticResource vm}, Path=IsScanning}" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout Margin="8,8,8,8">
<Label Text="Bike Selection Page"
StyleClass="titlelabel"/>
<ListView x:Name="ListView"
BindingContext="{StaticResource vm}"
StyleClass="listview"
ItemsSource="{Binding BikeList}"
IsGroupingEnabled="True"
SelectedItem="{Binding SelectedBike}"
Margin="8,8,8,8">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Heading}"
VerticalOptions="Center"
Margin="8,8,8,8"/>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<components:BikeSelectionCell
BikeName="{Binding Name}"
Image="{Binding Image}"
Distence="{Binding Distence}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
A ViewCell is not a View - it isn't part of View heirarchy. It is a "wrapper" that is needed by ListView, around each item.
Personally, I never create subclasses of ViewCell, though that can be done.
IMHO, Its more straightforward to make a custom View, then wrap that in <ViewCell> to use with ListView.
As a View, you can inherit from any view class. If you don't know what else to use, inherit from ContentView. (Or from StackLayout, if need to add multiple children views.) In your case, your View is a StackLayout.
public partial class BikeSelectionView : StackLayout
... // All the lines of code you have in BikeSelectionCell go here.
xaml:
<StackLayout ... x:Name="ThisCell">
<Grid ColumnSpacing="10" ...>
... All the remaining lines of code from your xaml ...
</StackLayout>
Usage inside ListView's ItemTemplate:
<DataTemplate>
<ViewCell>
<components:BikeSelectionView
BikeName="{Binding Name}"
Image="{Binding Image}"
Distence="{Binding Distence}"/>
</ViewCell>
</DataTemplate>
One advantage of this approach is if you switch from ListView to CollectionView (which does not use ViewCells), you can still use the custom class:
<CollectionView.ItemTemplate>
<DataTemplate>
<components:BikeSelectionView ... />
</DataTemplate>
</CollectionView.ItemTemplate>
The error was coming from a missing constructor that needed to initialize the Component.
public BikeSelectionCell()
{
InitializeComponent();
}
In the end I used the suggestion ToolmakerSteve. I also used a custom DataTemplateSelector to set specifics DataTemplate for the 2 different sections
I am setting this as the answer for any one looking for this problem as the problem was really the missing call to InitializeComponent();
I'm study Xamarin, I have Xamarin Forms using Collection View. I want to create master menu on home page in android. I can't auto change show view item in Collection View.
enter image description here
Bind the ItemTemplate to a DynamicResource and change the Resource on a button click or where you want the change to happen.
Define the templates in resource of the page.
<ContentPage.Resources>
<DataTemplate x:Key="menuTemplate1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*" />
<ColumnDefinition Width="0.7*" />
</Grid.ColumnDefinitions>
<Image Source="https://i.stack.imgur.com/di65V.jpg?s=328&g=1" />
<StackLayout Grid.Column="2">
<Label Text="Hi there" />
<Label Text="Hi there" />
</StackLayout>
</Grid>
</DataTemplate>
<DataTemplate x:Key="menuTemplate2">
<Image Source="https://i.stack.imgur.com/di65V.jpg?s=328&g=1" />
</DataTemplate>
</ContentPage.Resources>
Initialize DynamicResource in Page.Xaml.cs
public MainPage()
{
InitializeComponent();
Resources["menuTemplate"] = Resources["menuTemplate1"];
}
Bind the DynamicResource toItemTemplate`
<CollectionView ItemTemplate="{DynamicResource menuTemplate}" ItemsSource="{Binding ItemCollection}" />
Change the DynamicResource on button click or where you want.
void Button_Clicked(System.Object sender, System.EventArgs e)
{
if(Resources["menuTemplate"] == Resources["menuTemplate1"])
{
Resources["menuTemplate"] = Resources["menuTemplate2"];
}
else
{
Resources["menuTemplate"] = Resources["menuTemplate1"];
}
}
Please do check and comment for any query.
I cant find a good example about use of FFImageLoading in a UWP custom renderer for xamarin forms, good example sites use to focus in android and ios only. My main issue is how to use this Image Class in the UWP resource, CachedImage should be used in PCL project if i understand correctly. So how i should continue here? The advance use of ImageService does not detail this. I probably dont understand something. thanks in advance.
This is my View Cell in PCL:
<ViewCell>
<Grid RowSpacing="0" Padding="5,1,10,1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="30"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="32"></RowDefinition>
<RowDefinition Height="32"></RowDefinition>
</Grid.RowDefinitions>
<ffimageloading:CachedImage Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Source="{Binding MyViewModel.Image}" Aspect="AspectFit" VerticalOptions="Center" LoadingPlaceholder = "resource://MyProject.Resources.loading.png" />
<Label Grid.Column="1" Grid.Row="0" Text="{Binding MyViewModel.Name}" FontSize="16" TextColor="Red" FontAttributes="Bold" VerticalOptions="End"></Label>
<Label Grid.Column="1" Grid.Row="1" Text="{Binding MyViewModel.Serie}" FontSize="11" TextColor="Gray" FontAttributes="Italic" VerticalOptions="Start"></Label>
<ffimageloading:CachedImage x:Name="check" Grid.Column="2" Grid.Row="0" Grid.RowSpan="2" Source="{Binding MyViewModel.Own, Converter={StaticResource BoolToOwnImageSourceConverter}}}" Aspect="AspectFit" VerticalOptions="Center">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="OnCheckTapped"
Command="{Binding ChangeOwnCommand}"
CommandParameter="{Binding .}"/>
</Image.GestureRecognizers>
</ffimageloading:CachedImage>
</Grid>
<ViewCell.ContextActions>
<MenuItem Clicked="OnOwned" CommandParameter="{Binding .}" Text="Got it!" />
<MenuItem Clicked="OnNotOwned" CommandParameter="{Binding .}" Text="Not Yet" IsDestructive="True" />
</ViewCell.ContextActions>
Image source come from a image url stored in my view model
My main issue is how to use this Image Class in the UWP resource
If you want to custom image renderer. You could expand an attribute for xamarin image.
public class CustomImage : Image
{
public static readonly BindableProperty UriProperty = BindableProperty.Create(
propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(CustomImage),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
}
And you could invoke LoadUrl to set image for native control in the custom image render.
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
var customImage = (CustomImage)Element;
if (Control == null)
{
SetNativeControl(new Windows.UI.Xaml.Controls.Image());
}
if (e.OldElement != null)
{
}
if (e.NewElement != null)
{
if (!string.IsNullOrEmpty(customImage.Uri))
{
ImageService.Instance.LoadUrl(customImage.Uri).FadeAnimation(true).Into(Control);
}
else
{
// do some stuff
}
}
}
I'm using a MasterDetailPage in exrin
this is my ViewContainer
public class MainViewContainer : Exrin.Framework.ViewContainer, IMasterDetailContainer
{
private readonly MasterDetailPage r_MasterPage;
public MainViewContainer(MenuStack i_MenuStack, MainStack i_MainStack)
: base(eContainer.Main.ToString())
{
r_MasterPage = new MasterDetailPage();
MasterDetailProxy masterProxy = new MasterDetailProxy(r_MasterPage);
NativeView = masterProxy.View;
Proxy = masterProxy;
DetailStack = i_MainStack;
MasterStack = i_MenuStack;
RegionMapping.Add(eRegions.Menu, ContainerType.Master);
RegionMapping.Add(eRegions.Main, ContainerType.Detail);
}
public IHolder MasterStack { get; set; }
public IHolder DetailStack { get; set; }
public IMasterDetailProxy Proxy { get; set; }
public bool IsPresented
{
get
{
return r_MasterPage.IsPresented;
}
set
{
r_MasterPage.IsPresented = value;
}
}
public void SetStack(ContainerType i_ContainerType, object i_Page)
{
switch (i_ContainerType)
{
case ContainerType.Detail:
r_MasterPage.Detail = i_Page as Page;
break;
case ContainerType.Master:
r_MasterPage.Master = i_Page as Page;
break;
}
}
}
and this is my IMasterDetailProxy
public class MasterDetailProxy : IMasterDetailProxy
{
private readonly MasterDetailPage r_MasterPage;
public MasterDetailProxy(MasterDetailPage i_MasterPage)
{
View = i_MasterPage;
r_MasterPage = i_MasterPage;
}
public object DetailNativeView
{
get
{
return r_MasterPage.Detail;
}
set
{
r_MasterPage.Detail = value as Page;
}
}
public object MasterNativeView
{
get
{
return r_MasterPage.Master;
}
set
{
Page page = value as Page;
if(string.IsNullOrEmpty(page.Title))
{
page.Title = "Please set your MasterPage Title";
}
r_MasterPage.Master = page;
}
}
public object View { get; set; }
}
I'm using it show a menu on the master and the pages on the Detail part.
my menu view is
<base:PageProxy xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:base="clr-namespace:Exrin.Base;assembly=Exrin.Base"
xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin.Abstractions"
xmlns:control="clr-namespace:BeAttend.Control;assembly=BeAttend"
x:Class="BeAttend.View.MenuView" Title="Menu">
<base:PageProxy.Icon>
<OnPlatform x:TypeArguments="FileImageSource">
<On Platform="iOS" >Icon-Small.png</On>
</OnPlatform>
</base:PageProxy.Icon>
<ContentPage.Content>
<Grid BackgroundColor="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="200" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid>
<Image Source="menubg.jpg" Aspect="AspectFill" />
<StackLayout Padding="0,20,0,0" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" >
<controls:CircleImage BorderColor="White" BorderThickness="2" Source="{Binding VisualState.User.Picture}" Aspect="AspectFit" WidthRequest="100" HeightRequest="100" />
<Label Text="{Binding VisualState.User.Name}" TextColor="White" FontSize="Large" />
</StackLayout>
</Grid>
<StackLayout Margin="20,20,20,0" Grid.Row="1" Spacing="15">
<control:NavigationItem Text="Dashboard" Icon="fa-archive" Command="{Binding NavigationCommand}" CommandParameter="Dashboard" />
<ContentView HeightRequest="1" BackgroundColor="Gray" />
<control:NavigationItem Text="Beacons" Icon="fa-archive" Command="{Binding NavigationCommand}" CommandParameter="Beacons" />
<ContentView HeightRequest="1" BackgroundColor="Gray" />
<control:NavigationItem Text="Create event" Icon="fa-archive" Command="{Binding NavigationCommand}" CommandParameter="CreateEvent" />
<ContentView HeightRequest="1" BackgroundColor="Gray" />
<control:NavigationItem Text="My events" Icon="fa-archive" Command="{Binding NavigationCommand}" CommandParameter="MyEvents" />
<ContentView HeightRequest="1" BackgroundColor="Gray" />
<control:NavigationItem Text="Registered events" Icon="fa-archive" Command="{Binding NavigationCommand}" CommandParameter="RegisteredEvents" />
<ContentView HeightRequest="1" BackgroundColor="Gray" />
<control:NavigationItem Text="Attendance QR" Icon="fa-archive" Command="{Binding NavigationCommand}" CommandParameter="AttendanceQr" />
<ContentView HeightRequest="1" BackgroundColor="Gray" />
<control:NavigationItem Text="Join Event" Icon="fa-archive" Command="{Binding NavigationCommand}" CommandParameter="JoinEvent" />
<ContentView HeightRequest="1" BackgroundColor="Gray" />
<control:NavigationItem Text="Logout" Icon="fa-arrow-circle-left" Command="{Binding LogoutCommand}" />
</StackLayout>
</Grid>
</ContentPage.Content>
</base:PageProxy>
I have a couple of problems:
1. on Android I have the hamburger menu button automatically but on iOS I don't have any icon, I tried to set an icon for the menu view for iOS using
<base:PageProxy.Icon>
<OnPlatform x:TypeArguments="FileImageSource">
<On Platform="iOS" >Icon-Small.png</On>
</OnPlatform>
</base:PageProxy.Icon>
on the menu view but it doesn't work.
2. On iOS the page title is "Please set your MasterPage Title" (The proxy sets it if the page title is empty) but you can see on the menu view that I set the title for the page, this happens only on iOS.
https://drive.google.com/file/d/0B3YFjr58f7_OMC04Y0FreVRvVlE/view?usp=sharing
when pressing a link on the menu I want the master page to disappear it currently stays on and hides part of the Detail page until I press on the Detail page.
On the Detail page I have a back button, so if I want to navigate to another page I have to first press back and then I can see the the menu icon to show the mater page and select another link. How can I replace the back button to always show the hamburger menu button?
this is my stack
public class MainStack : BaseStack
{
public MainStack(IViewService i_ViewService)
: base(new NavigationProxy(new NavigationPage()), i_ViewService, eStack.Main, nameof(Views.eMain.Dashboard))
{
ShowNavigationBar = true;
}
protected override void Map()
{
NavigationMap<DashboardView, DashboardViewModel>(nameof(Views.eMain.Dashboard));
NavigationMap<BeaconsView, BeaconsViewModel>(nameof(Views.eMain.Beacons));
NavigationMap<BeaconAddView, BeaconAddViewModel>(nameof(Views.eMain.AddBeacon));
NavigationMap<BeaconEditView, BeaconEditViewModel>(nameof(Views.eMain.EditBeacon));
NavigationMap<EventCreateView, EventCreateViewModel>(nameof(Views.eMain.CreateEvent));
NavigationMap<EventsCreatedView, EventsCreatedViewModel>(nameof(Views.eMain.MyEvents));
NavigationMap<EventsRegisteredView, EventsRegisteredViewModel>(nameof(Views.eMain.RegisteredEvents));
NavigationMap<EventEditView, EventEditViewModel>(nameof(Views.eMain.EditEvent));
NavigationMap<EventView, EventViewModel>(nameof(Views.eMain.ViewEvent));
NavigationMap<AttendanceQrView, AttendanceQrViewModel>(nameof(Views.eMain.AttendanceQr));
NavigationMap<JoinEventView, JoinEventViewModel>(nameof(Views.eMain.JoinEvent));
}
}
If you want to remove the Master page when you click a link, you will find that in your IMasterDetailContainer, there is a property called IsPresented. Set this to true or false, to manually show or hide the page.
If you set the Title of your ContentPages, this will replace any default title being set.
Ensure the Icon is in your Resources folder. Also if it's still not shown in iOS, set the icon to the Detail, Navigation or ContentPage. I can't remember which one you are meant to set it to. But if you try that, you can find out which one works.
Git: https://github.com/jimmyt1988/Test
I'm running on desktop windows 10 pc on UWP Local device "emulator"
I have a deep integer property in my view model that gets incremented by a button command.
When i do, the number disapears from the screen, and then if i resize my application, it will render correctly again.
What's happening?
It seems to work on the Android emulator.
Code
public DelegateCommand<FoodGroupModel> SubtractFromAmountEatenCommand { get; private set; }
...
SubtractFromAmountEatenCommand = new DelegateCommand<FoodGroupModel>((foodGroup) => SubtractFromAmountEaten(foodGroup));
...
public void SubtractFromAmountEaten(FoodGroupModel foodGroup)
{
if(foodGroup.AmountEaten != 0)
{
foodGroup.AmountEaten--;
}
}
...
public class FoodGroupModel : BindableBase
{
private int _amountEaten;
public int AmountEaten
{
get { return _amountEaten; }
set { SetProperty(ref _amountEaten, value); }
}
}
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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="...Views.MealPage">
<StackLayout>
<Label Text="{Binding Meal.Number}"/>
<ListView x:Name="FoodGroupsListView" ItemsSource="{Binding Meal.FoodGroups}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" TextColor="#bababa" Text="Group"></Label>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding Title}" />
<Label Grid.Row="0" Grid.Column="2" TextColor="#bababa" Text="Qty"></Label>
<Label Grid.Row="0" Grid.Column="3" Text="{Binding AmountEaten}" />
<Button Grid.Row="0" Grid.Column="4"
Command="{Binding Source={x:Reference FoodGroupsListView}, Path=BindingContext.UndoAmountEatenByOneCommand}"
CommandParameter="{Binding}"
Text="✖"></Button>
<Button Grid.Row="0" Grid.Column="5"
Command="{Binding Source={x:Reference FoodGroupsListView}, Path=BindingContext.SubtractFromAmountEatenCommand}"
CommandParameter="{Binding}"
Text="✔"></Button>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
When i do, the number disapears from the screen, and then if i resize my application, it will render correctly again.
You might run into an issue: The changed notification of property binding won't work well(May be related to rerender) inside Xamarin ListView, Please report it in here: Bugzilla
In Windows runtime platform(Win/WP 8.1 & UWP), we have to use a workaround to temporarily avoid this:
private void RefreashFoodGroupModel()
{
if (Device.OS == TargetPlatform.Windows || Device.OS == TargetPlatform.WinPhone)
{
//var index = Meal.FoodGroups.IndexOf(foodGroup);
//Meal.FoodGroups.RemoveAt(index);
//Meal.FoodGroups.Insert(index, foodGroup);
var t = Meal.FoodGroups;
Meal.FoodGroups = new System.Collections.ObjectModel.ObservableCollection<FoodGroupModel>();
foreach (var item in t)
{
Meal.FoodGroups.Add(item);
}
}
}
Call the above method to refresh data after data change:
public void SubtractFromAmountEaten(FoodGroupModel foodGroup)
{
if(foodGroup.AmountEaten != 0)
{
foodGroup.AmountEaten--;
RefreashFoodGroupModel();
}
}
public void UndoAmountEatenByOne(FoodGroupModel foodGroup)
{
if (foodGroup.AmountEaten != foodGroup.Quantity)
{
foodGroup.AmountEaten++;
RefreashFoodGroupModel();
}
}
This workaround will cause the refresh of ListView items.