I have a ListView in Xamarin forms which has a Viewcell in it. The Viewcell contains an lable control with a x:Name attribute. Now I tried to x:name in code behind but it is showing compile time error(The x:name does not exists in current context).
The below code im using.
<ListView x:Name="UnPaidInvoicesList"
SeparatorVisibility="None" IsPullToRefreshEnabled="True"
HasUnevenRows="True"
ItemSelected="UnPaidInvoicesList_ItemSelected"
VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout x:Name="stkDuedate" Orientation="Horizontal">
<Label x:Name="lblDueDate1" Text="Due Date:" TextColor="Gray" />
<Label x:Name="lblDueDate" TextColor="{StaticResource Pink}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>```
Im new to this xamarin forms. Please help on this.
What features do you want to implement?
Just as Jason said,elements inside a template cannot be referenced by name.
If you want to disply a data list , you can bind the data to a ListView.
For this, you can refer to the following code:
<ListView x:Name="lstView" RowHeight="60" ItemsSource="{Binding veggies}" HasUnevenRows="True" IsPullToRefreshEnabled="False" SelectionMode="None">
<ListView.ItemTemplate >
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" HorizontalOptions="Fill" BackgroundColor="Olive">
<StackLayout Orientation="Vertical">
<Label Text = "{Binding Name}" FontSize="24" AbsoluteLayout.LayoutBounds="0.25, 0.25, 400, 40"/>
<Label Text = "{Binding Type}" AbsoluteLayout.LayoutBounds="50, 35, 200, 25"/>
</StackLayout>
<Image Source="{Binding Image}" HorizontalOptions="End" AbsoluteLayout.LayoutBounds="250.25, 0.25, 50, 50 "/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
For more,you can check document Xamarin.Forms ListView and
Customizing ListView Cell Appearance.
You can also check the sample Xamarin.Forms - ListView Sample: Custom Cells.
I have created a ControlTemplate in the app.xaml, defining the graphic part, only in the cs I would like to take some elements, to which I have given the name, to assign them the click event, but it signals me that they do not exist in the current context .
Someone who could kindly tell me how to please?
Someone, if possible, modify the source of the webview present in the main page, directly from app.xaml.cs
My code in the template is this:`
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="HeaderFooterTemplate"><ContentPresenter />
<StackLayout>
<BoxView HorizontalOptions="FillAndExpand" BackgroundColor="#DDDDDD" HeightRequest="2" Margin="0" />
<ScrollView Orientation="Horizontal">
<Grid RowSpacing="0">
<StackLayout Background="#c9ced6" HeightRequest="120" MinimumHeightRequest="120" Orientation="Horizontal" Grid.Row="0" Spacing="2">
<Grid WidthRequest="100" MinimumHeightRequest="120" BackgroundColor="#373B53" Padding="10" x:Name="Dashboard">
<Image Source="homeArancione" x:Name="imgDashboard" HorizontalOptions="Center" VerticalOptions="Center" WidthRequest="30" HeightRequest="30" Grid.Row="0" />
<Label Text="DASHBOARD" TextColor="#c9ced6" FontAttributes="Bold" HorizontalOptions="Center" Grid.Row="1" />
</Grid></Grid>
And in the reference page I recall it like this:
ControlTemplate="{StaticResource HeaderFooterTemplate}"
Graphically it works, but in the cs is I can't modify the texts to the labels or assign click events to the elements because it tells me that they don't exist in the current context
If you want to change the text or trigger the click event of the label in ControlTemplate, you could use the GestureRecognizers. The x:Name could not be found in the ControlTemplate directly.
<ControlTemplate x:Key="HeaderFooterTemplate">
<!--<ContentPresenter />-->
<StackLayout>
<BoxView HorizontalOptions="FillAndExpand" BackgroundColor="#DDDDDD" HeightRequest="2" Margin="0" />
<ScrollView Orientation="Horizontal">
<Grid RowSpacing="0">
<StackLayout Background="#c9ced6" HeightRequest="120" MinimumHeightRequest="120" Orientation="Horizontal" Grid.Row="0" Spacing="2">
<Grid WidthRequest="100" MinimumHeightRequest="120" BackgroundColor="#373B53" Padding="10" x:Name="Dashboard">
<Image Source="homeArancione" x:Name="imgDashboard" HorizontalOptions="Center" VerticalOptions="Center" WidthRequest="30" HeightRequest="30" Grid.Row="0" />
<Label Text="DASHBOARD" TextColor="#c9ced6" FontAttributes="Bold" HorizontalOptions="Center" Grid.Row="1">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"></TapGestureRecognizer>
</Label.GestureRecognizers>
</Label>
</Grid>
</StackLayout>
</Grid>
</ScrollView>
</StackLayout>
</ControlTemplate>
Code behind: App.xaml.cs
private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
Console.WriteLine("-----------");
var label = sender as Label;
label.Text = "Hello";
}
Update:
update the text of the label as soon as the page loads, without
having to click
Xamarin provide GetTemplateChild to get a named element from a template. The GetTemplateChild method should only be called after the OnApplyTemplate method has been called. If you want to call the OnApplyTemplate method, this template should be added for the contentpage.
You could refer to the thread i done before.
Xamarin SwipeView Open Left Item In ControlTemplate
I have a flexlayout inside of a frame, a grid and a stacklayout:
<CollectionView x:Name="collectionView"
Margin="20"
SelectionMode="Single"
SelectionChanged="OnSelectionChanged">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical"
ItemSpacing="10" />
</CollectionView.ItemsLayout>
<!-- Define the appearance of each item in the list -->
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="0,10,0,0" Spacing="0">
<StackLayout Orientation="Horizontal" Margin="0">
<Label FontSize="Medium" FontAttributes="Bold" Text="{Binding Name, Mode=OneWay}" />
<Label Text="{Binding Bottle.ID, Mode=OneWay}" FontSize="Medium"
FontAttributes="Italic" VerticalTextAlignment="Center"
Margin="20,0,0,0"/>
</StackLayout>
<Frame CornerRadius="10" BorderColor="Black" IsVisible="{Binding IsConnected, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}" Padding="10">
<Label Text="not connected" FontSize="Small"/>
</Frame>
<Frame CornerRadius="10" BorderColor="Black" IsVisible="{Binding IsConnected, Mode=OneWay}" Padding="10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<StackLayout Grid.Column="0">
<FlexLayout BindableLayout.ItemsSource="{Binding Bottle.Components, Mode=OneWay}"
Direction="Row" JustifyContent="Start" Wrap="Wrap"
AlignItems="Center" AlignContent="Start"
>
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label FontSize="Small" Text="{Binding DisplayString}" VerticalOptions="CenterAndExpand" Margin="0,0,10,0" Padding="0"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>
<StackLayout Orientation="Horizontal" IsVisible="{Binding IsConnected, Mode=OneWay}" VerticalOptions="FillAndExpand">
<Label FontSize="Small" Text="in " IsVisible="{Binding Bottle.IsCarrier, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"/>
<Label FontSize="Small" Text="{Binding Bottle.CarrierGas, Mode=OneWay}"/>
<Label FontSize="Small" Text=" 100%" IsVisible="{Binding Bottle.IsCarrier, Mode=OneWay}" />
</StackLayout>
</StackLayout>
<Label FontSize="Small" Text="(ISO)" FontAttributes="Italic" Grid.Column="1" IsVisible="False">
<Label.Triggers>
<MultiTrigger TargetType="Label">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Bottle.IsISOCertified, Mode=OneWay}" Value="True" />
<BindingCondition Binding="{Binding IsConnected, Mode=OneWay}" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="IsVisible" Value="True" />
</MultiTrigger>
</Label.Triggers>
</Label>
</Grid>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
At a specific input data, the flexlayout is not displayed correctly (see first element in the list):
If I remove the frame, the texts are displayed correctly:
If I keep the frame and increase the margin or the padding of the flexlayout elements by one, the text is displayed correctly in 2 lines.
<DataTemplate>
<Label FontSize="Small" Text="{Binding DisplayString}" VerticalOptions="CenterAndExpand" Margin="0,0,11,0"/>
</DataTemplate>
Also if I increase the fontsize to medium, it is displayed correctly. Plus, if I do not restart the application but let visual studio automatically update the form, after decreasing the font size, the display is correct. However, if I restart the Android Emulator, the problem is there again.
With font size medium:
<DataTemplate>
<Label FontSize="Medium" Text="{Binding DisplayString}" VerticalOptions="CenterAndExpand" Margin="0,0,10,0"/>
</DataTemplate>
After resetting it to small, but not restarting the app:
I guess, increasing the Margin/Padding or increasing the font size or removing the frame would not work correctly on the long run, because there's always going to be some data/screen size combination which breaks the layout.
It seems to me, that the layout only fails in some corner cases. However, when the element widths (+margins) are over some limit, the flexlayout recognizes that the elements have to be displayed in 2 lines, and after that the layout is ok.
Is this a bug of xamarin/android, or is there a problem in my code? Could anyone suggest a workaround, solution, that works reliably?
Some extra information, not sure what is necessary:
Target Android Version: Android 9.0 (API Level 28 - Pie)
emulator: Pixel 2 Pie 9.0 - API28 1080x1920 420dpi
Edit: I also tested with 1020x1920, 1000x1920, 800x1920, 1200x1920 display size, all of them showed the same problem. So either the setting in Android Device Manager was not taken over (hw.lcd.width), or the problem is independent of the display size.
Edit2: changing the display size in Settings/Display affects the layout, and fixes it, if I set it to lower or larger. But I guess it is only changing the FontSize parameter of the labels.
While testing #ToolmakerSteve's solution, I found out, that the children bound.Width-s are higher if I remove the last item in the list (NO 2100ppm). Then I called measure for each children, and I saw, that the widths match those bound.Width-s when the last item was missing. So I ended up with this code:
//https://stackoverflow.com/a/70526712/9963147
class FlexLayoutImproveMeasure : FlexLayout
{
protected override void LayoutChildren(double x, double y, double width, double height)
{
base.LayoutChildren(x, y, width, height);
foreach (var child in Children)
{
Rectangle cb = child.Bounds;
Size s = child.Measure(double.PositiveInfinity, cb.Height).Request;
double newW = s.Width;
var childBounds2 = new Rectangle(cb.X, cb.Y, newW, cb.Height);
child.Layout(childBounds2);
}
}
}
I discovered that FlexLayout sometimes doesn't give each label quite enough room; the labels get truncated.
Here is a subclass of FlexLayout, that adds a small amount of width to each Label.
FlexLayoutImproveMeasure.cs:
using Xamarin.Forms;
namespace XFSOAnswers
{
class FlexLayoutImproveMeasure : FlexLayout
{
protected override void LayoutChildren(double x, double y, double width, double height)
{
base.LayoutChildren(x, y, width, height);
//var childBoundss = new List<Rectangle>();
foreach (var child in Children)
{
Rectangle cb = child.Bounds;
// Make each child slightly wider: labels were being truncated.
// Less than 2 didn't always work. Increase as needed, up to right margin.
const int extraW = 2;
double newX = cb.X;
// TBD whether part of the problem is label that isn't pixel-aligned.
// (So far, seems more reliable to increase extraW instead.)
//MAYBE double newX = Math.Floor(cb.X);
double newW = cb.Width + extraW;
// TBD whether it helps to ensure width extends to next pixel.
// (So far, seems more reliable to increase extraW instead.)
//MAYBE double newW = Math.Ceiling(cb.Width) + extraW;
//double ceilingRight = Math.Ceiling(cb.X + cb.Width);
//MAYBE double newW = ceilingRight - Math.Floor(cb.X) + extraW;
var childBounds2 = new Rectangle(newX, cb.Y, newW, cb.Height);
child.Layout(childBounds2);
//childBoundss.Add(child.Bounds);
//childBoundss.Add(cb);
}
}
}
}
Use this in place of FlexLayout. This is done by adding to a page an xmlns: declaration to access a namespace in your project. Here the namespace is XFSOAnswers. Change xmlns:local line to refer to whatever namespace you put the above class in.
XAML of a page:
<?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:local="clr-namespace:XFSOAnswers"
x:Class="XFSOAnswers.FlexLayoutInItemTemplatePage">
<ContentPage.Content>
<StackLayout>
<!-- labels truncated at width in range 188-194 -->
<CollectionView ItemsSource="{Binding Items}"
WidthRequest="190" HorizontalOptions="Center"
Margin="20" >
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical" ItemSpacing="10" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Frame CornerRadius="10" BorderColor="Black"
BackgroundColor="LightBlue" Padding="10">
<local:FlexLayoutImproveMeasure
Wrap="Wrap"
BindableLayout.ItemsSource="{Binding Items2}"
BackgroundColor="LightGray" >
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label FontSize="Small" Text="{Binding .}"
VerticalOptions="Start" HorizontalOptions="Start" Margin="0,0,10,0" Padding="0"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
</local:FlexLayoutImproveMeasure>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
page's code behind has the bindings:
using System.Collections.Generic;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace XFSOAnswers
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FlexLayoutInItemTemplatePage : ContentPage
{
public FlexLayoutInItemTemplatePage()
{
InitializeComponent();
BindingContext = this;
}
public List<ListModel> Items { get; } = new List<ListModel> {
new ListModel(),
new ListModel(),
};
}
public class ListModel
{
public List<string> Items2 { get; } = new List<string> {
"aaa", "bbbbbbbbb", "cc", "dddd", "e",
};
}
}
Items2 strings chosen such that at WidthRequest=190, "dddd" barely fit on first line. Tests were done with and without the final "e", to see what FlexLayout did in both cases.
Original FlexLayout, truncating labels:
Using FlexLayoutImproveMeasure with extraW = 2:
I have a ListView displaying multiple cases, and I would like to display its page details when I click on the the Reference from the list. I only get a blank page.
I have tried EventHandler from my XAML and did not work.
<ListView ItemsSource="{Binding GetCases}" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Margin="20,0,20,0">
<Label Text="Case Reference:" FontSize="14" TextColor="Green"/>
<Label FontSize="12" TextColor="Blue" FontAttributes="Bold">
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding Reference}" TextColor="Blue" TextDecorations="Underline"> // I can get the list of References here, but can go to their details
<Span.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_OnTapped" NumberOfTapsRequired="1" />
<TapGestureRecognizer Command="{Binding Path=BindingContext.GoToPageDetails, Source={x:Reference Page}}" /> //This approach takes me to the Page Details, but it is blank
</Span.GestureRecognizers>
</Span>
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
VIEWMODEL
public CasesViewModel(INavigation navigation)
{
IGetDataFromServer cases = new GetDataFromServer();
Navigation = navigation;
GoToPageDetails = new Command(async () => await PageDetails());
GetCases = cases.GetCases(); // This code retrieves my data from server - it Works fine
}
public Command GoToPageDetails { get; set; }
public async Task PageDetails()
{
await Navigation.PushAsync(new CaseDetails());
}
CASE DETAILS XAML
<ListView ItemsSource="{Binding GetCases}" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Margin="20,0,20,0">
<Label Text="PERSONAL DETAILS" FontSize="Large" TextColor="Black" Margin="0,0,0,20" />
<Label Text="Status:" FontSize="14" TextColor="Green"/>
<Label Text="{Binding status}"
FontSize="12" TextColor="Black" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</ DataTemplate>
</ ListView.ItemTemplate>
</ ListView>
CASE DETAILS VIEWMODEL
public CaseDetailsViewModel(INavigation navigation)
{
IGetDataFromServer cases = new GetDataFromServer();
Navigation = navigation;
GetCases = cases.GetCases().FirstOrDefault();
}
public CasesFull GetCases { get; set; }
I can navigate to Case Details page, but it is blank. Maybe I am not passing the reference to the page, or maybe it is something else.
Thanks for your help.
I finally solved the problem.
The issue was in my Case Details View Model, as I had to add the Model in all properties of the Cases Details View model (see below).
<ListView ItemsSource="{Binding GetCases}" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Margin="20,0,20,0">
<Label Text="PERSONAL DETAILS" FontSize="Large" TextColor="Black" Margin="0,0,0,20" />
<Label Text="Status:" FontSize="14" TextColor="Green"/>
<Label Text="{Binding Case.status}"
FontSize="12" TextColor="Black" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</ DataTemplate>
</ ListView.ItemTemplate>
Where Case is my Model.
If anyone wants to display details of an object, this code can be your solution.
Thanks Umar3x for your help.
I have a ListView with several items in it. I am running the app as a UWP app on my local machine, but for some reason, displaying an image via a url doesn't work?
The tag I'm using is
<Image Source="https://en.bitcoin.it/w/images/en/2/29/BC_Logo_.png" HeightRequest="20" WidthRequest="20" />
I have tried using several different images from different domains as I thought it could be an authorisation issue? But no images that I've tried seem to be working.
As I define the space for the image, there is a gap in the list where it should be.
For reference, here is the whole list code:
<ContentPage Title="Coins">
<ContentPage.Content>
<ListView x:Name="coins" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Spacing="5" Orientation="Horizontal" Padding="10,10,10,10">
<Label Text="{Binding Path=Rank}" FontSize="10" VerticalTextAlignment="Center"/>
<Image Source="https://en.bitcoin.it/w/images/en/2/29/BC_Logo_.png" HeightRequest="20" WidthRequest="20" />
<Label Text="{Binding Path=Name}" TextColor="Black" FontSize="19" VerticalTextAlignment="Center"/>
<Label Text="{Binding Path=PercentChange24h, StringFormat='{0}%'}" VerticalTextAlignment="Center" TextColor="{Binding PercentTextColour}"/>
<Label Text="{Binding Path=LivePrice, StringFormat='${0}'}" VerticalTextAlignment="Center" HorizontalTextAlignment="End" HorizontalOptions="EndAndExpand"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
This issue was down to UWP not being able to display images, this works on Android and iOS.