I'm attempting to build a 3 column status bar with the Grid control in Xamarin.Forms. I receive 3 values: open, pending and filled. I would like the column width to be bound to those values. However, the column widths remain equal.
Current Look:
Desired Look:
This is achieved by replacing the bindings in the Column Width with 3*, 0*, and 2* respectively.
XAML
<Frame HorizontalOptions="FillAndExpand" CornerRadius="10" HasShadow="False" Padding="0" IsClippedToBounds="True">
<Grid ColumnSpacing="0" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Filled, StringFormat='{0:N}*'}" />
<ColumnDefinition Width="{Binding Pending, StringFormat='{0:N}*'}" />
<ColumnDefinition Width="{Binding Open, StringFormat='{0:N}*'}" />
</Grid.ColumnDefinitions>
<BoxView Grid.Column="0" Color="#5cb85c" />
<Label Grid.Column="0" Text="{Binding Filled}" TextColor="White" HorizontalOptions="Center" VerticalOptions="Center" />
<BoxView Grid.Column="1" Color="#f0ad4e" />
<Label Grid.Column="1" Text="{Binding Pending}" TextColor="White" HorizontalOptions="Center" VerticalOptions="Center" />
<BoxView Grid.Column="2" Color="#d43f3a" />
<Label Grid.Column="2" Text="{Binding Open}" TextColor="White" HorizontalOptions="Center" VerticalOptions="Center" />
</Grid>
</Frame>
UPDATE:
I updated my code with your suggestion. The issue is that the converter is not fired. I do not get an error and the breakpoint in the converter is never reached. I added "Source={x:Reference listView}" as I've seen some SO answers suggest it. However, it doesn't help. I also tried to add a basic double to string converter to the label and it doesn't execute either.
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:conv="clr-namespace:MyApp.Converters" x:Class="MyApp.Views.OrgDash.PositionsPage" Title="Positions">
<ContentPage.Resources>
<ResourceDictionary>
<conv:NumberToGridLengthConverter x:Key="numberToGridLengthConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<AbsoluteLayout x:Name="absLayout" VerticalOptions="FillAndExpand">
<ListView x:Name="listView" HasUnevenRows="true" ItemTapped="OnItemTapped" HeightRequest="{Binding Path=Height, Source={x:Reference absLayout}}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10,10,10,10" Orientation="Vertical">
<StackLayout HorizontalOptions="StartAndExpand" Orientation="Horizontal">
<Label Text="{Binding Name}" VerticalTextAlignment="Center" FontAttributes="Bold" />
</StackLayout>
<Frame HorizontalOptions="FillAndExpand" CornerRadius="10" HasShadow="False" Padding="0" IsClippedToBounds="True">
<Grid ColumnSpacing="0" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Filled, Source={x:Reference listView}, Converter={StaticResource numberToGridLengthConverter}}" />
<ColumnDefinition Width="{Binding Pending, Source={x:Reference listView}, Converter={StaticResource numberToGridLengthConverter}}" />
<ColumnDefinition Width="{Binding Open, Source={x:Reference listView}, Converter={StaticResource numberToGridLengthConverter}}" />
</Grid.ColumnDefinitions>
<BoxView Grid.Column="0" Color="#5cb85c" />
<Label Grid.Column="0" Text="{Binding Filled" TextColor="White" HorizontalOptions="Center" VerticalOptions="Center" />
<BoxView Grid.Column="1" Color="#f0ad4e" />
<Label Grid.Column="1" Text="{Binding Pending}" TextColor="White" HorizontalOptions="Center" VerticalOptions="Center" />
<BoxView Grid.Column="2" Color="#d43f3a" />
<Label Grid.Column="2" Text="{Binding Open}" TextColor="White" HorizontalOptions="Center" VerticalOptions="Center" />
</Grid>
</Frame>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ContentView x:Name="overlay" AbsoluteLayout.LayoutBounds="0, 0, 1, 1" AbsoluteLayout.LayoutFlags="All" IsVisible="True" BackgroundColor="#C0808080" Padding="10, 0">
<ActivityIndicator WidthRequest="110" HeightRequest="70" IsRunning="True" IsVisible="True" Color="Black" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"/>
</ContentView>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
Converter Class:
using System;
using System.Globalization;
using Xamarin.Forms;
namespace MyApp.Converters
{
public class NumberToGridLengthConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var numberValue = (double)value;
return new GridLength(numberValue, GridUnitType.Star);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var gridLength = (GridLength)value;
return gridLength.Value;
}
}
}
I guess that your binding will cause binding error and you will see in Debug window something like this:
[0:] Binding: '3.00*' can not be converted to type 'Xamarin.Forms.GridLength'.
[0:] Binding: '0.00*' can not be converted to type 'Xamarin.Forms.GridLength'.
[0:] Binding: '2.00*' can not be converted to type 'Xamarin.Forms.GridLength'.
I would use a custom converter to convert number value to GridLength:
public class NumberToGridLengthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var numberValue = (double)value;
return new GridLength(numberValue, GridUnitType.Star);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var gridLength = (GridLength)value;
return gridLength.Value;
}
}
Xaml:
<ContentPage.Resources>
<ResourceDictionary>
<conv:NumberToGridLengthConverter x:Key="numberToGridLengthConverter" />
</ResourceDictionary>
</ContentPage.Resources>
...
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Filled, Converter={StaticResource numberToGridLengthConverter}}" />
<ColumnDefinition Width="{Binding Pending, Converter={StaticResource numberToGridLengthConverter}}" />
<ColumnDefinition Width="{Binding Open, Converter={StaticResource numberToGridLengthConverter}}" />
</Grid.ColumnDefinitions>
Related
I am implementing a first-time user onboarding in a Xamarin.Forms application like the one on the image below:
Please, how can I quickly do that?
Thank you in advance.
Do you want to achieve the result like following GIF?
You can use CarouselView and IndicatorView to achieve it.
Here is layout code.I dont adjust the layout like yours, you can adjust it by yourself, If you want to make Next and Skip Button over float the CarouselView, you can use AbsoluteLayout
<StackLayout Margin="10">
<CarouselView x:Name="myCarouselView" ItemsSource="{Binding Monkeys}"
IndicatorView="indicatorView">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame HasShadow="True"
BorderColor="DarkGray"
CornerRadius="5"
Margin="50"
HeightRequest="300"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<StackLayout>
<Label Text="{Binding Name}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Image Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="150"
WidthRequest="150"
HorizontalOptions="Center" />
<Label Text="{Binding Location}"
HorizontalOptions="Center" />
<Label Text="{Binding Details}"
FontAttributes="Italic"
HorizontalOptions="Center"
MaxLines="5"
LineBreakMode="TailTruncation" />
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Skip" Grid.Column="0" BackgroundColor="Transparent" Clicked="Button_Clicked"></Button>
<Button Text="Next" Grid.Column="1" BackgroundColor="Transparent" Clicked="Button_Clicked_1"></Button>
</Grid>
<IndicatorView x:Name="indicatorView"
MaximumVisible="6"
Margin="0,0,0,40"
IndicatorColor="LightGray"
SelectedIndicatorColor="DarkGray"
HorizontalOptions="Center" />
</StackLayout>
Here is layout bakground code.
public partial class BasicIndicatorViewPage : ContentPage
{
int monkeyCount;
public BasicIndicatorViewPage()
{
InitializeComponent();
MonkeysViewModel monkeysViewModel= new MonkeysViewModel();
monkeyCount = monkeysViewModel.Monkeys.Count;
BindingContext = monkeysViewModel;
}
private void Button_Clicked(object sender, System.EventArgs e)
{
Navigation.PushAsync(new Page1());
Navigation.RemovePage(this);
}
private void Button_Clicked_1(object sender, System.EventArgs e)
{
if (myCarouselView.Position < monkeyCount-1)
{
myCarouselView.Position += 1;
}
else
{
Navigation.PushAsync(new Page1());
Navigation.RemovePage(this);
}
}
}
Here is my demo, you can download it.
https://github.com/851265601/XFormsCarouselView-IndicatorViewLoginPage
If you want to put the indicatorView and Button in the same line like this screenshot.
You can use this layout(indicatorView to the Grid).
<StackLayout Margin="10">
<CarouselView x:Name="myCarouselView" ItemsSource="{Binding Monkeys}"
IndicatorView="indicatorView">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame HasShadow="True"
BorderColor="DarkGray"
CornerRadius="5"
Margin="50"
HeightRequest="300"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<StackLayout>
<Label Text="{Binding Name}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Image Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="150"
WidthRequest="150"
HorizontalOptions="Center" />
<Label Text="{Binding Location}"
HorizontalOptions="Center" />
<Label Text="{Binding Details}"
FontAttributes="Italic"
HorizontalOptions="Center"
MaxLines="5"
LineBreakMode="TailTruncation" />
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Skip" Grid.Column="0" BackgroundColor="Transparent" Clicked="Button_Clicked"></Button>
<IndicatorView x:Name="indicatorView"
MaximumVisible="6"
IndicatorColor="LightGray"
SelectedIndicatorColor="DarkGray"
HorizontalOptions="Center" Grid.Column="1" />
<Button Text="Next" Grid.Column="2" BackgroundColor="Transparent" Clicked="Button_Clicked_1"></Button>
</Grid>
</StackLayout>
You could use the offical Xamarin.Forms CarouselView but that's still in preview. You could also potentially look at the Sharpnado's solution with HorizontalListView. Your third option would be to use Alex Rainman's CarouselView.
Hello I’m having an issue with binding a list of string to my Carousel View
First I have a list of an object I get from my server
public class PostObject
{
public string PostOwner { get; set; }
public string Id { get; set; }
public string Post { get; set; }
public string ProfileImage { get; set; }
public List<string> PostImages { get; set; }
}
List<PostObject> posts = new List<PostObject>();
This works as I expected.
Next I have a card view I created and within the card view I want to have a Carousel View.
So I have setup my Xaml like this (omitting the parts that works for clarity)
<?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:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin"
NavigationPage.HasNavigationBar="True"
NavigationPage.HasBackButton="False"
NavigationPage.BackButtonTitle="Back"
Title="amici"
x:Class="amici.Posts">
<NavigationPage.TitleView>
<StackLayout Orientation="Horizontal" VerticalOptions="Center" Spacing="10" >
<Label x:Name="GroupTitle" TextColor="White" FontSize="Medium"/>
</StackLayout>
</NavigationPage.TitleView>
<ContentPage.ToolbarItems>
<ToolbarItem Name="iconexample" Icon="settings.png" Priority="0" Order="Primary" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout>
<ListView x:Name="ItemsListView"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
IsPullToRefreshEnabled="true"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
CachingStrategy="RecycleElement">
<!--ItemSelected="OnItemSelected"-->
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout Padding="10">
<Frame x:Name="myframe" HasShadow="True" >
<Grid HorizontalOptions="FillAndExpand" RowSpacing="0" ColumnSpacing="0" >
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Text="{Binding PostOwner}" LineBreakMode="WordWrap" Font="Bold,16" />
<controls:CircleImage Grid.Row="0" Margin="10" BorderColor="white" BorderThickness="1" VerticalOptions="Start" HorizontalOptions="Start" Source="{Binding ProfileImage}" Aspect="AspectFit">
<controls:CircleImage.WidthRequest>
<OnPlatform x:TypeArguments="x:Double">
<On Platform="Android, iOS">65</On>
</OnPlatform>
</controls:CircleImage.WidthRequest>
<controls:CircleImage.HeightRequest>
<OnPlatform x:TypeArguments="x:Double">
<On Platform="Android, iOS">65</On>
</OnPlatform>
</controls:CircleImage.HeightRequest>
</controls:CircleImage>
<Label Grid.Row="1" Text="{Binding Post}" LineBreakMode="WordWrap" Font="Bold,16" />
<CarouselView x:Name="PostImages" Grid.Row="2" ItemsSource="{Binding PostImages}">
<CarouselView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding .}" Aspect="AspectFill" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<!--<Image Grid.Row="2" Source="{Binding ImageURL}" Aspect="AspectFill" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />-->
<BoxView Grid.Row="3" BackgroundColor="black" HeightRequest="1" HorizontalOptions="FillAndExpand"/>
<StackLayout Grid.Row="4" Orientation="Horizontal" >
<Label Text="Likes: " LineBreakMode="NoWrap" Font="Bold,14" />
<Label Text="0" LineBreakMode="NoWrap" FontSize="14" />
</StackLayout>
<StackLayout Grid.Row="5" Orientation="Horizontal" >
<Label Text="Comments: " LineBreakMode="NoWrap" Font="Bold,14" HorizontalOptions="End" />
<Label Text="0" HorizontalOptions="End" LineBreakMode="NoWrap" FontSize="14" />
</StackLayout>
<!--<Label Grid.Row="2" Text="{Binding OwnerFullName}" LineBreakMode="NoWrap" FontSize="16" />-->
</Grid>
</Frame>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
In my code behind I have this
public Posts (GroupInfo ginfo)
{
InitializeComponent ();
GroupTitle.Text = ginfo.Title;
CurrentGroupInfo = ginfo;
GetDataPosts();
ItemsListView.RefreshCommand = new Command(() => {
GetDataPosts();
ItemsListView.IsRefreshing = false;
});
}
public void GetDataPosts()
{
try
{
string apikey = Application.Current.Properties["api"].ToString();
ItemsListView.ItemsSource = null;
posts.Clear();
if (RestController.GetMyPostData(ref posts, CurrentGroupInfo.Id.ToString(), apikey))
{
ItemsListView.ItemsSource = posts;
}
}
catch(Exception e)
{
Debug.WriteLine(e.Message);
}
}
now up to this point everything works and no errors but when the app goes to render the page I get a error
System.TypeInitializationException: The type initializer for 'Xamarin.Forms.ItemsView' threw an exception.
which I trace back to the Carousel View. When I comment out the Carousel View the it works. so I'm thinking I can't bind OR use the Carousel View in the way I thought?
The CarouselView used to be a plugin that has now become part of Xamarin.Forms effective with version 4. You can use an earlier XF version but you will need to get this plugin, add assembly references to your XAML and put initialization code in your platform specific projects.
Alternatively, you could upgrade to Xamarin.Forms 4
Even though you can see the Carousel View on Xamarin.Forms 3.6.0.344457, it only defines an interface there. There're no implementations and properties in the Carousel View Class.
You can only utilize it under Xamarin.Forms 4.0. As it is still a preview version now, there're some limitations. See my post here: https://stackoverflow.com/a/56235795/8354952 for more information.
i would like to create a view like this :
. Where Contact1, Contact2 are models and ListViewis a list of these models.
Now i have code like this but i dont get the desired output.
<?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="KiaiDay.Pages.ConviteEmailPage"
NavigationPage.TitleView="Convive por email"
NavigationPage.HasBackButton="True"
NavigationPage.BackButtonTitle="Voltar"
BackgroundColor="AliceBlue">
<ContentPage.Content>
<AbsoluteLayout>
<ActivityIndicator x:Name="indicador" AbsoluteLayout.LayoutBounds="0.5,0.5,100,100" AbsoluteLayout.LayoutFlags="PositionProportional" Color="Blue"/>
<StackLayout>
<ListView x:Name="ListaContactos">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Image Source="{Binding Imagem}"/>
<Label Text="{Binding Nome}"/>
<Label Text="{Binding Email}"/>
<Label Text="{Binding Numero}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
As Jason said, you can use CollectionView to do it.However,you should note that:
The CollectionView is currently an early preview, and lacks much of its planned functionality. In addition, the API will change as the implementation is completed.
And CollectionView is available in Xamarin.Forms 4.0-pre1.
If no problem with version, using code as follow:(Update: Adding Frame to code)
<StackLayout Margin="20,35,20,20">
<CollectionView ItemsSource="{Binding Monkeys}" >
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10">
<Frame BackgroundColor="LightGray"
OutlineColor="Black"
CornerRadius="10">
<Grid Padding="5" WidthRequest="120" HeightRequest="120">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0"
Text="{Binding Name}"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
<Image Grid.Row="1"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Row="2"
Text="{Binding Location}"
LineBreakMode="TailTruncation"
FontAttributes="Italic"
VerticalOptions="End" />
<Label Grid.Row="3"
Text="{Binding Details}"
LineBreakMode="TailTruncation"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
Refer to official sample , binding source:
BindingContext = new MonkeysViewModel();
Here is the capture image of app.
I have a listview for displaying all the items that i getting from api.i have a live event which will modify one field inside the item of type observablecollection
<?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="Dyocense.Views.ManageJobs"
Title="All jobs">
<ContentPage.ToolbarItems>
<ToolbarItem Text="ADD" Clicked="AddJob"></ToolbarItem>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout>
<SearchBar x:Name="Search" SearchButtonPressed="SearchBar_SearchButtonPressed"></SearchBar>
<ListView x:Name="JobsListView"
ItemsSource="{Binding Items}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
CachingStrategy="RecycleElement"
ItemAppearing="BrowseJobList_ItemAppearing"
IsPullToRefreshEnabled="true"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10">
<Frame HasShadow="True" >
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Name}"
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
FontSize="Medium"
FontAttributes="Bold"/>
<Label Text="Status"
Grid.Row="1" Grid.Column="0"
FontSize="16"
FontAttributes="Bold"/>
<Label Text="{Binding Status}"
Grid.Row="1" Grid.Column="1"
FontSize="16"/>
<Label Text="Goal"
Grid.Row="2" Grid.Column="1"
FontSize="16"
FontAttributes="Bold"/>
<Label Text="{Binding Goal}"
Grid.Row="2" Grid.Column="2"
FontSize="16" />
<Label Text="Part"
Grid.Row="3" Grid.Column="1"
FontSize="16"
FontAttributes="Bold"/>
<Label Text="{Binding PartName}"
Grid.Row="3" Grid.Column="2"
FontSize="16" />
<Label Text="Assembly"
Grid.Row="4" Grid.Column="1"
FontSize="16"
FontAttributes="Bold"/>
<Label Text="{Binding NodeName}"
Grid.Row="4" Grid.Column="2"
FontSize="16" />
<Label Text="GoodCount"
Grid.Row="5" Grid.Column="0"
FontSize="16"
FontAttributes="Bold"/>
<Label Text="{Binding GoodCount}"
Grid.Row="6" Grid.Column="0"
FontSize="16"
HorizontalTextAlignment="Center"/>
<Label Text="RejectCount"
Grid.Row="5" Grid.Column="1"
FontSize="16"
FontAttributes="Bold"/>
<Label Text="{Binding RejectCount}"
Grid.Row="6" Grid.Column="1"
FontSize="16"
HorizontalTextAlignment="Center"/>
<Label Text="DownTimeCount"
Grid.Row="5" Grid.Column="2"
FontSize="16"
FontAttributes="Bold"/>
<Label Text="{Binding DownTimeCount}"
Grid.Row="6" Grid.Column="2"
FontSize="16"
HorizontalTextAlignment="Center"/>
</Grid>
</StackLayout>
</Frame>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Footer>
<Grid Padding="6" IsVisible="{Binding IsBusy}">
<!--set the footer to have a zero height when invisible-->
<Grid.Triggers>
<Trigger TargetType="Grid" Property="IsVisible" Value="False">
<Setter Property="HeightRequest" Value="0" />
</Trigger>
</Grid.Triggers>
<!--the loading content-->
<Label Text="Loading..." VerticalOptions="Center" HorizontalOptions="Center" />
</Grid>
</ListView.Footer>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
i want to update the good count on real time. i debugged the code its getting updated in my list but only updating the UI on a user scroll. Here is my viewmodel
public class JobViewModel: INotifyPropertyChanged
{
private ObservableCollection<Job> items;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<Job> Items
{
get { return items; }
set
{
items = value;
if (items != value)
{
items = value;
OnPropertyChanged(nameof(Items));
}
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
private void updateJoblistOnEvent(NotificationEntity message)
{
var jobId = message.JobId;
Job job = Items.FirstOrDefault(a => a.JobId.Equals(jobId));
switch (message.EventCode)
{
case MessageTypeEnum.Pulse: //Pulse
job.GoodCount = job.GoodCount + 1;
//job.Status = 'Running';
break;
default:
break;
}
}
i am suspecting two things
CachingStrategy="RecycleElement" i removed this one that its not updating with scroll also
any problem with INotifyPropertyChanged, i tried to remove one item from list its working and updating the ui.i want to update the field inside the item
can any one help me
As deduced from the comments, you need to also implement the INotifyPropertyChanged interface on the Job object. Using the ObservableCollection only helps for changes in that collection, so when you remove or add a Job object, not if something changes inside the Job object.
So, in your Job object do this (code reverse engineered from what you posted):
public class Job : INotifyPropertyChanged
{
private int goodCount;
public int GoodCount
{
get { return goodCount; }
set
{
if (goodCount != value)
{
goodCount = value;
OnPropertyChanged(nameof(GoodCount));
}
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
You could remove the INotifyPropertyChanged from your JobViewModel, but you probably need it there at some point as well
How can I remove the row Comment is on if its null or empty string?
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*" />
<ColumnDefinition Width="50*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding EntryDate}" Grid.Column="0" Grid.Row="0"></Label>
<Label Text="{Binding Sleep}" Grid.Column="1" Grid.Row="0"></Label>
<Label Text="{Binding Comment}" Grid.Column="0" Grid.ColumnSpan="4"
Grid.Row="1"></Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
This is the appropriate case to use a ValueConverter.
All you need to do is create a converter like this:
namespace App.Converters
{
public class TextToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value != null)
if (!(value is string)) return true;
return string.IsNullOrWhiteSpace(value as string) ? false : true;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
And use it on the IsVisible property of Label:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converters="clr-namespace:App.Converters"
x:Class="App.Views.SamplePage">
<ContentPage.Resources>
<ResourceDictionary>
<converters:TextToBoolConverter x:Key="TextToBoolConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*" />
<ColumnDefinition Width="50*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding EntryDate}" Grid.Column="0" Grid.Row="0"></Label>
<Label Text="{Binding Sleep}" Grid.Column="1" Grid.Row="0"></Label>
<Label Text="{Binding Comment}" Grid.Column="0" Grid.ColumnSpan="4"
Grid.Row="1"
IsVisible={Binding Comment, Converter={StaticResource TextToBoolConverter}}/>
</Grid>
</ContentPage>
Thus you can reuse it wherever you need.
Your model:
public class MyModel
{
//...other properties ...
public string Comment { get; set; }
public bool HasComment => !string.IsNullOrEmpty(Comment);
}
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*" />
<ColumnDefinition Width="50*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding EntryDate}" Grid.Column="0" Grid.Row="0"></Label>
<Label Text="{Binding Sleep}" Grid.Column="1" Grid.Row="0"></Label>
<Label Text="{Binding Comment}" Grid.Column="0" Grid.ColumnSpan="4"
Grid.Row="1" IsVisible = {Binding HasComment}></Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>