Updating Labels within Grid from ObservableCollection - xaml

I am currently working with an app in Xamarin, building it for UWP.
In this app, I have a Stack that has an image of the human body with other images overlayed (colored circles). What I am trying to do is place a Label on top of the circles on the body and update them in real time based on data within an ObservableCollection (called TagInfoList) I am pulling from another file. To set this up, I have made a 5x4 Grid that the Body image takes up the entirety of, and have placed the circles within individual cells of the Grid. Additionally, the Labels go in their own cells. The issue I am running into is getting my Labels to show up and actively update from my TagInfoList.
Here is what I am trying to set up. I want my Labels to go on top of the colored circles.
Here is the XAML code:
<StackLayout Orientation="Horizontal" HorizontalOptions="EndAndExpand"> <!-- Body Model Section -->
<Grid VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" WidthRequest="400" ColumnSpacing="0">
<Grid.ColumnDefinitions> <!-- 4 equal size Columns-->
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions> <!-- 5 equal size Rows -->
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Image Source="{pages:ImageResource BLE.Client.Pages.body.png}" Aspect="AspectFit" Grid.Row="0" Grid.Column="0" Grid.RowSpan="5" Grid.ColumnSpan="4"/>
<Image Source="{pages:ImageResource BLE.Client.Pages.green.png}" Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Aspect="AspectFit" Opacity="0.6"/>
<Image Source="{pages:ImageResource BLE.Client.Pages.red.png}" Grid.Row="2" Grid.Column="0" Aspect="AspectFit" Opacity="0.6"/>
<Image Source="{pages:ImageResource BLE.Client.Pages.green.png}" Grid.Row="2" Grid.Column="3" Aspect="AspectFit" Opacity="0.6"/>
<Image Source="{pages:ImageResource BLE.Client.Pages.green.png}" Grid.Row="4" Grid.Column="1" Aspect="AspectFit" Opacity="0.6"/>
<Image Source="{pages:ImageResource BLE.Client.Pages.red.png}" Grid.Row="4" Grid.Column="2" Aspect="AspectFit" Opacity="0.6"/>
<CollectionView ItemsSource="{Binding TagInfoList}">
<CollectionView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding SensorAvgValue}" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Center" Grid.ColumnSpan="2"/>
<Label Grid.Row="2" Grid.Column="0" Text="{Binding SensorAvgValue}" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Center"/>
<Label Grid.Row="2" Grid.Column="3" Text="{Binding SensorAvgValue}" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Center"/>
<Label Grid.Row="4" Grid.Column="1" Text="{Binding SensorAvgValue}" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Center"/>
<Label Grid.Row="4" Grid.Column="2" Text="{Binding SensorAvgValue}" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Center"/>
</ViewCell>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</StackLayout> <!-- Body Model Section -->
I've tried putting the Labels within a CollectionView since I can bind it to the TagInfoList, something a Grid cannot do. However, I am unsure what changes I need to make with the hierarchy of my objects to get the Labels to actively update. The TagInfoList and SensorAvgValue that I am calling are both updating correctly in other StackLayout instances, so I know there is no issue with the ObservableCollection.
In addition, my next step will be to make the Images change based on the value in the Label, so I may need to also move the Image objects to whatever level the Labels are at so they can interact with each other.
If this would be easier to do in a .xaml.cs file, I could also transfer the code to one. One exists but it's only there for one part of a different Stack in my layout.
Any and all advice would be appreciated. Thank you all!

So as the user Jason mentioned: a mockup would be nice. anyway...
If you just want an Image and a batch over it, wrap it into a "BatchView".
Another easy way would be if you place all (Image, Label, Batch(?)) into an "AbsolutLayout" and then Position it, as the AbsolutLayout is like an overlay.
Finally set it all to a Binding with OnPropertyChanged, so it will update itself like in a CollectionView - in a CollectionView it's the same mechanism but automated.
Just draw an simple mockup and post ;)

Related

Is there a way for a ListView within Grid to inherit the grid's ColumnDefinitions & RowDefinitions?

I'm essentially trying to create a view that displays a list of items underneath an interactable header (a Button and an Image wrapped in a FlexLayout) that sorts that specific column A-Z / Z-A, my problem is that I can't figure out how to line them up neatly and without manually setting the column width in ColumnDefinition.
Normally I'd just set the width to some value but since its going to be cross platform (including tablets) I want to avoid doing that so I don't end up with everything squished to one side if the user decides to use a tablet with a much wider screen, does anyone know any fixes or have any advice on what I could look into trying?
Thanks in advance, and I'll post a snippet of what I'm trying to achieve below
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<FlexLayout AlignItems="Center" Grid.Row="0" Grid.Column="0">
<Button Text="Name" FontSize="8" Clicked="QuickSort" Padding="0"/>
<Image Source="" Aspect="AspectFit" HeightRequest="20" WidthRequest="20" IsVisible="False"/>
</FlexLayout>
<FlexLayout AlignItems="Center" Grid.Row="0" Grid.Column="1">
<Button Text="Type" FontSize="8" Clicked="QuickSort" Padding="0"/>
<Image Source="" Aspect="AspectFit" HeightRequest="20" WidthRequest="20" IsVisible="False"/>
</FlexLayout>
<FlexLayout AlignItems="Center" Grid.Row="0" Grid.Column="2">
<Button Text="Cost" FontSize="8" Clicked="QuickSort" Padding="0"/>
<Image Source="" Aspect="AspectFit" HeightRequest="20" WidthRequest="20" IsVisible="False"/>
</FlexLayout>
<ListView ItemSource="{Binding Collection}" Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding name}" Grid.Column="0"/>
<Label Text="{Binding type}" Grid.Column="1"/>
<Label Text="{Binding cost}" Grid.Column="2"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
A simple solution is to copy the Grid column declarations into the ItemTemplate's DataTemplate. This makes each item a Grid, whose columns match the outer Grid:
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid ColumnDefinitions="*, *, *">
<Label Text="{Binding name}" Grid.Column="0"/>
<Label Text="{Binding type}" Grid.Column="1"/>
<Label Text="{Binding cost}" Grid.Column="2"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
The labels all default to "Row=0", so each item is a one-row Grid.
If you like to make it easier, maybe try some datagrid libraries like https://github.com/akgulebubekir/Xamarin.Forms.DataGrid

Why is the edge of the Frame getting cut off? Frame inside a CollectionView with a CornerRadius

This is actually a nested CollectionView but I don't think that is part of the issue here- please let me know if it might be and I can include the rest.
Can someone help me understand why the right edge of my Frame is being cut off? Including the screenshot and code snippet below:
<CollectionView Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="4" Margin="5"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
ItemsSource="{Binding WeeklySchedules}"
EmptyView="No items currently exist !"
x:DataType="formsPages:GroupSchedule">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical" ItemSpacing="5"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Frame Grid.Row="0" VerticalOptions="Fill"
CornerRadius="4"
BorderColor="{StaticResource LightTextColor}"
HasShadow="False"
Margin="0"
BackgroundColor="White"/>
<Label Grid.Row="0" Text="{Binding DayOfWeek}"
VerticalOptions="Center"
FontSize="13"
Padding="6"
x:DataType="formsPages:WeeklyScheduleModel"/>
<Label Grid.Row="0" Text="{Binding TimeString}"
VerticalOptions="Center"
HorizontalTextAlignment="End"
FontSize="13"
Padding="6, 6,30,6"
x:DataType="formsPages:WeeklyScheduleModel"></Label>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Its because you are overlapping Label on top of Frame. So some part is invisible
You should use a stacklayout /grid as child of frame to position items.
Alternatively you can set right margin for TimeString Label.

Xamarin forms - unwanted extra space under TableView

I am creating my first Android app. I want to show TableView with some input fields and then a button to process the inputs.
I don't know why but there is extra space under TableView or the button is aligned to the bottom but it is opposite to the settings.
Can you help me fix it?
<StackLayout Orientation="Vertical" VerticalOptions="Start" Padding="20,15,20,0" Spacing="0">
<Label Text="This is TableView"></Label>
<TableView Intent="Settings" VerticalOptions="Start">
<TableRoot>
<TableSection>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="item 1"/>
<Entry></Entry>
</StackLayout>
</ViewCell>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="item 2"/>
<Entry></Entry>
</StackLayout>
</ViewCell>
</TableSection>
</TableRoot>
</TableView>
<Label Text="TableView - END"></Label>
<Button Text="My button" TextColor="DodgerBlue" VerticalOptions="Start" HorizontalOptions="Fill" Margin="40, 10, 40, 10"/>
<Frame VerticalOptions="StartAndExpand" BackgroundColor="Transparent" BorderColor="Black">
<StackLayout Orientation="Vertical">
<StackLayout Orientation="Horizontal" HorizontalOptions="Fill">
<Label Text="aaaa" HorizontalOptions="StartAndExpand"></Label>
<Label Text="value" HorizontalOptions="End"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="aaaa"></Label>
<Label Text="value"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="aaaa"></Label>
<Label Text="value"></Label>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
Your best option is to define the RowHeight for each cell, and then specify the HeightRequest for the tableview. this way you can define the space it will occupy
<TableView Margin="0" Intent="Settings" HeightRequest="120" RowHeight="60" VerticalOptions="Start">
Unfortunately, this is how Xamarin.Forms TableView/ListView works. It is not expected to have anything below it. If you need something below you can either set the height of TableView manually or to put the content in the last cell, neither thing is perfect but in any case you need to look for some workaround as this is behavior by design (it would be a bit easier if you could use the ListView instead of TableView).
As you were asking what you can do besides using a TableView, of course a Grid would be possible, please see the following example:
<Grid VerticalOptions="StartAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <!-- for the label -->
<ColumnDefinition Width="*" />
<Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="1" /> <!-- For the separator, you might have to experiment with the height -->
<RowDefinition Height="*" />
<RowDefinition Height="1" />
</Grid.RowDefinitions>
<Label Text="Item 1" />
<Entry Grid.Row="0" Grid.Column="1" />
<BoxView BackgroundColor="Black"
HeightRequest="1"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2" /> <!-- The separator -->
<Label Grid.Row="2" Grid.Column="0" Text="Item 2" />
<Entry Grid.Row="2" Grid.Column="1" />
<BoxView BackgroundColor="Black"
HeightRequest="1"
Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="2" /> <!-- The separator -->
</Grid>
I am using BoxViews with a black background color and a HeightRequest of 1 for the separator. You might have to experiment with the color and the height to get the results you want. Values below 1 are possible and result in finer lines. In a real world example I've used .5.
Anyway, this makes the XAML way more cluttered. Grid-designs (while I am using them myself) tend to get quite unwieldy.
I am not sure if this what you are looking for but my understanding of the question tells me you are talking about the label Value being away from the rest.
if you check the code for this label :
<Label Text="value" HorizontalOptions="End"></Label>
the HorizontalOptions is set to "End" which is causing this changing it to start will fix your problem
Feel free to revert in case if I missed anything
Goodluck

Empty space above and under images in grid

I am working on images in grid layout and i have problem with empty space below and above images. I would like these rows with dates to be exactly below icons without any empty space and to make icons with size just like they are on picture. When i use aspect fit, it makes icons streched vertically. I tried to set fixed size of row but it made a crap view when I rotaded phone.
<Grid
RowSpacing="0"
VerticalOptions="Center"
>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Source="kafelek_1.png"
Grid.Column="0" Grid.Row="0"
></Image>
<Image Source="kafelek_2.png"
Grid.Column="1" Grid.Row="0"
></Image>
<Image Source="kafelek_3.png"
Grid.Column="2" Grid.Row="0"
></Image>
<StackLayout BackgroundColor="#0078B7"
Grid.Column="0" Grid.Row="1"
Orientation="Horizontal"
HeightRequest="20"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Image Source="trojkat.png">
</Image>
<Label Text="Temp"
x:Name="DecisionDateLabel"></Label>
</StackLayout>
<StackLayout BackgroundColor="#0078B7"
Grid.Column="1" Grid.Row="1"
Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Image Source="trojkat.png"></Image>
<Label Text="Temp"
x:Name="KnowledgeDateLabel"></Label>
</StackLayout>
<StackLayout BackgroundColor="#0078B7"
Grid.Column="2" Grid.Row="1"
Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Image Source="trojkat.png"></Image>
<Label Text="Temp"
x:Name="PollsDateLabel"></Label>
</StackLayout>
</Grid>
Generally, this is what i would like to obtain:
This bug is created in bugzilla https://bugzilla.xamarin.com/show_bug.cgi?id=55294
You can actually try to implement workaround How can I make an image auto-resize so the width is 100% and the height adjusted accordingly?

Xamarin Forms: How can I make an Image Circle in a ListView?

Good Day Everyone. I'm currently creating a simple project that allows me to Add record of an Employee. All created records are displayed on a ListView. I was able to display the records and this turns out :
(I don't even know where this Xamarin Icon was pulled of.)
But what I want to achieve is this:
I heard about the use of RoundedBoxView. But since I'm new to Xamarin, I don't know if this is a case where I can use it. Thanks a lot guys.
Here's the code for the page that should display that Images.
<?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"
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>
<Image 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="Gray"
FontSize="18"
Opacity="0.6"/>
</Grid>
</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>
James Montemagno has an excellent Image Circle plugin which works with Xamarin.Forms. You can install it from NuGet:
Install-Package Xam.Plugins.Forms.ImageCircle
Then you need to initialize it per platform, same place as Xamarin.Forms.Init like:
Xamarin.Forms.Init();
ImageCircleRenderer.Init();
Then you can use CircleImage instead of Image in your XAML or in code behind.
Documentation on usage can be found in the GitHub repository for the plugin.
EDIT
From your edited answer, as mentioned above, you just replace Image in your XAML with CircleImage. So instead of:
<Image Source="icon.png"
HeightRequest="66"
HorizontalOptions="CenterAndExpand"
Aspect="AspectFill"
WidthRequest="66"
Grid.RowSpan="2"
/>
Modify it to:
<CircleImage Source="icon.png"
HeightRequest="66"
HorizontalOptions="CenterAndExpand"
Aspect="AspectFill"
WidthRequest="66"
Grid.RowSpan="2"
/>
In this case icon.png comes from the Android Resources/drawable folder, you might want to bind that to something else. Like an URL in your model you have in your ItemsSource.
You can simply use this code and not need a library or other codes:
<Frame
CornerRadius="100"
HeightRequest="200"
WidthRequest="200"
HasShadow="False"
HorizontalOptions="Center"
Padding="0"
IsClippedToBounds="True">
<Image Source="logo"
HorizontalOptions="Center"
VerticalOptions="Center" />
</Frame>