How to render x items in xamarin without scroll - c#

Ok, this is a little strange, but I need to take a screenshot of a list of items in Xamarin. The problem is that I'm using a ListView and it only renders about 5 items. I need to render all elements in the list. I don't care if it's smaller on-screen; I just want to take a screenshot of the view and be able to share it.
This is my .xaml:
<BoxView HorizontalOptions="FillAndExpand" HeightRequest="0.5" Color="Gray"/>
<controls:CustomListView x:Name="list"
ItemsSource="{Binding List}"
HeightRequest="1000" VerticalOptions="Fill"
HasUnevenRows="True">
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
<controls:CustomListView.ItemTemplate>
<DataTemplate>
<cell:ItemViewCell></cell:ItemViewCell>
</DataTemplate>
</controls:CustomListView.ItemTemplate>
</controls:CustomListView>
<BoxView HorizontalOptions="FillAndExpand" HeightRequest="0.5" Color="Gray"/>
This is for Android.

In the code behind you something like this on the OnAppearing method
list.HeightRequested = list.ItemSource.Count * list.RowHeight;
you can also try to do the same thing on the CustomList's OnPropertyChanged where propertyName is ItemSource whatever feels best for you

I had to create pdf, it is not possible to "overlap" the boundaries of the screen, At least no with a List, I went the pdf way

Related

Xamarin.Forms PullToRefresh not occuring when ListView is empty?

In Xamarin.Forms I have a simple ListView that is bound to a view model using MVVM.
<ListView Grid.Row="1"
ItemsSource="{Binding ContactsGrouped}"
IsGroupingEnabled="true"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"
GroupDisplayBinding="{Binding Key}"
GroupShortNameBinding="{Binding Key}"
BackgroundColor="Transparent"
SelectionMode="Single"
HasUnevenRows="true"
SeparatorColor="#cccccc">
<ListView.ItemTemplate>
<cr:MyItemTemplate>
</ListView.ItemTemplate>
</ListView>
This is my xaml code, which works perfectly fine if the list has at least 1 item. By tapping and pulling down on the item, the list view refreshes fine, however tapping and pulling down outside of the item, the list does not cause PullToRefresh to occur. It's almost as if the ListView has transparent input but its items do not, thus allowing it to work.
Anything in the red in my example image shows the area where if I tap and drag down the activity indicator appears fine and the refresh happens. Tap and dragging anywhere in the green however causes the View to not refresh and the activity indicator to not appear.
I won't show my view model as the issue is with the View. I've also tried setting background color to red, checking if transparent was causing an issue, sadly that is not the case. Any ideas?
I just reproduced your problem on my side. After some researching, I found it is known issue from Xamarin.forms 3.5.0 and it still exist in Latest stable 3.6.0.344457.
The WorkAround is downgrade your Xamarin.forms version to 3.4.0.
Also, I test it in the Latest prerelease 4.0.0.394984-pre10 and it works well. So, I believe this issue will be solved in the next release version.
You can follow this issue to check the process.
Try adding VerticalOptions="StartAndExpand".
<ListView Grid.Row="1"
ItemsSource="{Binding ContactsGrouped}"
IsGroupingEnabled="true"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"
GroupDisplayBinding="{Binding Key}"
GroupShortNameBinding="{Binding Key}"
BackgroundColor="Transparent"
SelectionMode="Single"
HasUnevenRows="true"
SeparatorColor="#cccccc"
VerticalOptions="StartAndExpand">
<ListView.ItemTemplate>
<cr:MyItemTemplate>
</ListView.ItemTemplate>
</ListView>
This property tells the View how much space of your screen should it cover. If you don't add it then the View will just cover whatever the required length to display the data it needs.

Continuously Updating Label in ListView Template

I've got a list of objects that I'm binding to a ListView and using a DataTemplate to show in a Xamarin app. So far, pretty simple. But the kicker is that I want one of the controls (a label specifically) to update continually.
So far this is what I have...
<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 Padding="10">
<Label Text="{Binding Title}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<mycountdown:TimerLabel Text="{Binding TimeRemainingString}"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And the code behind for my TimerLabel class...
public class TimerLabel : Label
{
private bool beating;
public TimerLabel()
{
StartHeartbeat();
}
public void StartHeartbeat()
{
//only start beating again if not currently beating.
if (!beating)
{
beating = true;
Heartbeat();
}
}
public void StopHeartbeat()
{
beating = false;
}
async void Heartbeat()
{
while (beating)
{
this.Text = DateTime.UtcNow.ToLongTimeString();
}
}
}
This works, but the problem is that the heartbeat for each item in the list keeps running even when I navigate away from the page.
Ideally, the heartbeat would only run for items that are visible on screen, but I would settle for letting them all run and just disabling them when I leave the page.
The problem is I can't figure out how to access the StopHeartbeat() method from the page's code behind or the view model.
It's not going to be limited to only Labels either. I will end up having a few other controls that need to update in the UI thread continuously, but this is the simplest one to start with.
If there's another way I should be doing this, please say so.
Thanks!
if you are Bind List in ListItem Source then please change it from List to ObservableCollection it will work let me know if any question or can you upload viewModel code as well
Answered by the top comment in my post.

How to Delete / Show a StackLayout through the code behind of my View with MVVM

You want to hide a StackLayout depending on the value of a property that is evaluated in the constructor, but when hiding it xamarin leaves the blank and does not upload the lower elements upwards, so I will remove the element through code behind (I'm using MVVM)
But I do not know how to structure my code so that I can evaluate whether or not I eliminate the StackLayout when loading the Vista
In my view I occupy X: Name to identify the element that I want to eliminate or show, after evaluating the condition.
MyView.XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
BindingContext="{Binding Main, Source={StaticResource Locator}}"
x:Class="AppValora.Views.Sisquim.VerSisquimView">
<StackLayout
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand"
VerticalOptions="Start">
<Image
HorizontalOptions="Center"
Source="{Binding ImageRombo}"
HeightRequest="160"
WidthRequest="160"
IsVisible="{Binding IsVisibleImagenRombo}">
</Image>
<Image
HorizontalOptions="Center"
Source="cuadro_nch"
HeightRequest="160"
WidthRequest="160">
</Image>
</StackLayout>
// STACKLAYOUT YOU WANT TO ELIMINATE
<StackLayout
x:Name="StackIsVisible">
<Image
Source="{Binding ImageRomboDos}"
HeightRequest="160"
WidthRequest="160"
IsVisible="{Binding IsVisibleImagenRombo}">
</Image>
</StackLayout>
</ContentPage>
In my ViewModel, I receive the parameter that I then evaluate in a conditional
MyViewModel.CS:
public VerSisquimViewModel(SqsHelper sqsHelper)
{
if (sqsHelper.RSEC == null)
{
IsVisibleLabelRomboImagenDos = false;
}
}
What magic can I do in my Code Behind so that when the condition is met, eliminate the StackLayout and disappear that blank space?
currently I have....
MyView.cs (CODE BEHIND):
public partial class MyView : ContentPage
{
StackLayout hiddenStackLayout;
public VerSisquimView ()
{
NavigationPage.SetBackButtonTitle(this, "");
StackIsVisible.Children.RemoveAt(1);
InitializeComponent();
}
}
how can I from the code behind change the value of the property when I start this page?
Is it a bad practice to use code behind with the MVVM pattern?
How can i fix this? any help for me?
Is it a bad practice to use code behind with the MVVM pattern?
If the code is view related, than it's necessary. Sometimes you just can't avoid code in the code-behind. A Rule to keep in mind, typically when you start working with the view, managing things can get to be quite cumbersome. If you find a way to leverage the platform, in this case Xaml, let it do the work for you.
the thing about visibility, the element is rendered on the screen. The user just can't see it. This is why the space is being taken up. Sometimes visibility will work, other times not so much.
In this situation, you can avoid code in code-behind and stick to your VM.
I would suggest using a grid and use a converter to hide a grid row. When I say hide the row, I mean by setting a row's height to 0. So it's rendered but we are going to collapse it. I only added two rows, you can add more to accommodate more content as you see fit.
Edit: added sample namespace. If you are using Visual Studio, there should be intellisense. You have to add the local namespace, so the xaml engine can find the converter class.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converter="clr-namespace:DataBindingDemos" <-- set the appropriate value
BindingContext="{Binding Main, Source={StaticResource Locator}}"
x:Class="AppValora.Views.Sisquim.VerSisquimView">
<ContentPage.Resources>
<converter:BoolToGridRowVisibilityConverter key="BoolToGridRowVisibilityConverter">
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="{Binding IsStackVisible, Converter={StaticResource BoolToGridRowVisibilityConverter}}" />
</Grid.RowDefinitions>
<StackLayout
Grid.Row="0"
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand"
VerticalOptions="Start">
<Image
HorizontalOptions="Center"
Source="{Binding ImageRombo}"
HeightRequest="160"
WidthRequest="160"
IsVisible="{Binding IsVisibleImagenRombo}">
</Image>
<Image
HorizontalOptions="Center"
Source="cuadro_nch"
HeightRequest="160"
WidthRequest="160">
</Image>
</StackLayout>
<!-- STACKLAYOUT YOU WANT TO ELIMINATE -->
<StackLayout Grid.Row="1"
x:Name="StackIsVisible">
<Image
Source="{Binding ImageRomboDos}"
HeightRequest="160"
WidthRequest="160"
IsVisible="{Binding IsVisibleImagenRombo}">
</Image>
</StackLayout>
</Grid>
</ContentPage>
Add a converter
public class BoolToGridRowVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? new GridLength(1, GridUnitType.Auto) : new GridLength(0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException("Only one way bindings are supported with this converter");
}}
}
For more information, see a post on Xamarin forums
You can put the IsVisible="{Binding IsVisibleImagenRombo}" to the StackIsVisible stacklayout, so that the entire space will be erased.

xamarin.forms - uniquely identify controls in listview in XAML

I am new to xamarin.forms
I have a listview that is filled from backend c# code.
I have one label and one image defined in it. And I have given x:Name property in XAML.
Now, my question is I want to access those two labels in backend c# code. But both the labels are not accessible because they are in listview. If I put label outside listview, I can access it in the code.
Please avoid syntax errors. My code works fine. I want to access these elements so that I can change style for phone and tablet.
My XAML code :
// ...
<ListView x:Name="DentistList">
<Listview.ItemTemplate>
<DataTemplate>
<ViewCell>
<Image Source="{Binding ImagePath}" x:Name="DoctorImage"/>
<Label Text="{Binding Name}" x:Name="DoctorName" />
</ViewCell>
</DataTemplate>
</Listview.ItemTemplate>
</ListView>
My c# code :
......
DentistList.ItemSource = new List<Doctor>
{
// List of items defined here like...
Name = "ABC",
ImagePath = "img1.jpg"
// Etc...
};
Now, Below this list, I want to change style(like, fontsize etc...) of label and image. But I can not access them.
I tried to access them with FindByName() method but could not do that.
So, can anyone please answer ?
Thank you in advance.
From Jason's comment, you can change the Label.FontSize and Label.TextColor using OnIdiom like so:
<Label Text="{Binding Name}" x:Name="DoctorName">
<Label.TextColor>
<OnIdiom x:TypeArguments="Color"
Phone="Yellow"
Tablet="Blue"/>
</Label.TextColor>
<Label.FontSize>
<OnIdiom x:TypeArguments="NamedSize"
Phone="Small"
Tablet="Large"/>
</Label.FontSize>
</Label>
*Edit: Example using regular integer:
<Label.FontSize>
<OnIdiom x:TypeArguments="x:Double"
Phone="20"
Tablet="30"/>
</Label.FontSize>
*Edit #2:
If you plan to use your Label.FontSize and Label.TextColor on multiple pages I would suggest adding the values into your App.xaml and then referencing them from your ContentPages (you could also just add the value to the ContentPage's ResourceDictionary if you are using the values multiple times but only on a single page):
App.xaml:
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.App">
<Application.Resources>
<ResourceDictionary>
<Color x:Key="MyTextColor">
<Color.Accent>
<OnIdiom x:TypeArguments="Color"
Phone="Yellow"
Tablet="Blue"/>
</Color.Accent>
</Color>
<x:Double x:Key="MyFontSize">
<OnIdiom x:TypeArguments="x:Double"
Phone="20"
Tablet="30"/>
</x:Double>
</ResourceDictionary>
</Application.Resources>
</Application>
Now in your ContentPages:
<Label x:Name="DoctorName"
Text="{Binding Name}"
TextColor="{StaticResource MyTextColor}"
FontSize="{StaticResource MyFontSize}"/>
If you want to use NamedSize instead you might need to use converter that I have seen on the Xamarin Forums. Let me know if you cannot find it and I can try to look around.

Building comment tree efficiently in Metro XAML

I am trying to build a 'comments control' (In a win8 XAML app, which is similar to Silverlight) which will load and render a comment tree for the user.
Each comment can have 0 or 1+ children comments (which recurses through each comment).
Each comment displays a set of info, including author, time, the comment itself, etc.
The approach I initially took to build this is to use a ListView which has a 'CommentItem' control binding.
<TextBlock Grid.Row="1" TextWrapping="Wrap" Text="{Binding commentText}" FontSize="11" FontFamily="Global User Interface" />
<ListView Grid.Row="2" x:Name="CommentRepliesList" ItemsSource="{Binding}" >
<ListView.ItemTemplate>
<DataTemplate>
<local:CommentItem Tag="{Binding}"></local:CommentItem>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The above will just recurse through each comment, apply the comment text, and then create a new commentitem for each comment child, recurse through again, etc.
The issue, however, is this is extremely slow and non-performant.
Does anyone know a more efficient way to do this? Is ListView the appropriate control to use for this?

Categories

Resources