XamarinForm DataTemplate ListView Binding - data-binding

I want to bind to a variable from inside a CustomControl referenced in a ListView DataTemplate
This is the situation:
I have a custom control containing a ListView with many DataTemplates to display the various ViewCell (it's basically a set of dynamic fields that must be displayed according to their "type").
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:s4gvForms="clr-namespace:S4GVMobile.Forms;assembly=S4GVMobile"
xmlns:s4gvControls="clr-namespace:S4GVMobile.Controls;assembly=S4GVMobile"
x:Class="S4GVMobile.Controls.AttributesList"
x:Name="S4GVAttributesListControl"
>
<ContentView.Resources>
<ResourceDictionary>
<!-- MANY DATA TEMPLATES HERE, ONLY ONE LEFT FOR REFERENCE -->
<DataTemplate x:Key="s4gvAttributePictureTemplate">
<ViewCell x:Name="s4gvAttributePictureViewCell">
<ViewCell.View>
<StackLayout Orientation="Vertical">
<Label Text="{Binding Attribute.Key}" />
<s4gvControls:AttributePicture ParentID="{Binding Source={x:Reference s4gvAttributePictureViewCell}, Path=Parent.BindingContext.EntityID}" AttributeValue="{Binding .}" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
<!-- ... -->
<!-- AGAIN, LONG LIST IN THE SELECTOR -->
<s4gvForms:AttributeDataTemplateSelector x:Key="s4gvAttributeDataTemplateSelector"
AttributePictureTemplate="{StaticResource s4gvAttributePictureTemplate}"
/>
</ResourceDictionary>
</ContentView.Resources>
<StackLayout>
<ListView x:Name="s4gvAttributes" HasUnevenRows="True" ItemTemplate="{StaticResource s4gvAttributeDataTemplateSelector}" ItemsSource="{Binding AttributeValues}" />
</StackLayout>
I'm passing to this custom control both the list of items (required by the ListView) and an additional EntityID.
<s4gv:AttributesList x:Name="s4gvSerialAttributes" AttributeValues="{Binding Serial.AttributeValues}" EntityID="{Binding Serial.SerialID}" VerticalOptions="FillAndExpand"/>
The custom control has the required bindable properties (AttibuteValues and EntityID) and relies on a dedicated ViewModel
I need to retrieve the EntityID from inside the DataTemplate (and put it in the ParentID property); this value is in the custom control's ViewModel but it is "outside" the ListView's DataTemplates. I've tried using the Parent.BindingContext (it works on Command and CommandParameter) but it seems that it can only go up to the ListView's context and not higher though I need to move one further step up to the CustomControl itself.
<s4gvControls:AttributePicture ParentID="{Binding Source={x:Reference s4gvAttributePictureViewCell}, Path=Parent.BindingContext.EntityID}" AttributeValue="{Binding .}" />
Any idea? I'm happy to restructure the whole thing if required.

Related

Add Content Programatically to TabViewItem in TabView Xamarin forms

I am using TabView in my project. I've installed Xamarin.community.toolkit.
I am trying to add Content for TabViewitem programmatically instead of xaml because each ContentView of TabViewItem has service calls in it's constructor which is causing the issue when all the TabViewItems load at once.
Below is my code:
<xcl:TabView x:Name="MainTabView"
TabStripPlacement="Top">
<xcl:TabViewItem
x:Name="Tab1"
Text="Details"
Margin="16,0,16,0"
TextColor="Black"
FontFamily="{StaticResource SFProRegular}"
TextColorSelected="Black"
FontSize="15">
</xcl:TabViewItem>
------
</xcl:TabView>
And I 'm trying to add Content to TabViewItem programatically like below (Page1 is a ContentView)
var stackPanel = new StackLayout { Orientation = StackOrientation.Vertical };
stackPanel.Children.Add(new Page1());
DetailsTabView.Content = stackPanel;
But the UI is not rendering in my app.
The same works If I add the Page1 like below:
<xcl:TabView x:Name="MainTabView"
TabStripPlacement="Top" >
<xcl:TabViewItem
x:Name="Tab1"
Text="Details"
Margin="16,0,16,0"
TextColor="Black"
FontFamily="{StaticResource SFProRegular}"
TextColorSelected="Black"
FontSize="15">
<template:Page1 />
</xcl:TabViewItem>
------
</xcl:TabView>
Any help is appreciated!
And I 'm trying to add Content to TabViewItem programatically like below (Page1 is a ContentView)
If you want to add one COntentview in one TabViewItem by code behind, you can take a look:
<xct:TabView
x:Name="mytabview"
TabIndicatorColor="Yellow"
TabStripBackgroundColor="Blue"
TabStripHeight="60"
TabStripPlacement="Bottom">
<xct:TabViewItem
x:Name="tb1"
FontSize="12"
Text="Tab 1"
TextColor="White"
TextColorSelected="Yellow">
<StackLayout />
</xct:TabViewItem>
<xct:TabViewItem
x:Name="tb2"
FontSize="12"
Text="Tab 2"
TextColor="White"
TextColorSelected="Yellow">
</xct:TabViewItem>
</xct:TabView>
Then adding ContentView to TabViewItem.
public MainPage()
{
InitializeComponent();
mytabview.TabItems[0].Content = new contentview1();
mytabview.TabItems[1].Content = new contentview2();
}
Note: please forget to add Stacklayout or other layout inside TabViewItem by xaml, then code you add contentview will be effective.
you need to do somethig like this
<xct:TabView TabItemsSource="{Binding TabVms}"
TabStripPlacement="Top"
TabStripBackgroundColor="LightGray"
TabIndicatorColor="Gray" IsTabStripVisible="True">
<xct:TabView.TabViewItemDataTemplate>
<DataTemplate>
<Grid>
// tabs
</Grid>
</DataTemplate>
</xct:TabView.TabViewItemDataTemplate>
<xct:TabView.TabContentDataTemplate>
<DataTemplate>
<Grid>
// content`enter code here`
</Grid>
</DataTemplate>
</xct:TabView.TabContentDataTemplate>
</xct:TabView>

Can I create some small views including created views to use it in mainPage?

Can I create a view including Entry Progress bar or others to make a view which I can use in other places?
for example I want to create a card view which I can use to list the lists.
I can only write in the list not to write the card in every list.
Yes, you can create a custom view and use it in the MainPage or other Pages, Views you want.
To create a custom view, add a new item --> ContentView,let's call it CardView:
In .cs of CardView:
public partial class CardView : ContentView
{
public CardView()
{
InitializeComponent();
}
}
In xaml of CardView, add your labels,progressbar, entry there:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="App35.CardView">
<ContentView.Content>
<StackLayout>
<Label Text="Hello Xamarin.Forms!" />
<ProgressBar Progress="0.5" />
<Entry Placeholder="I'm entry"/>
</StackLayout>
</ContentView.Content>
</ContentView>
To use it in MainPage, in listView or in the page:
<StackLayout>
<projectName:CardView HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
<ListView x:Name="listView" RowHeight="70">
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>mono</x:String>
<x:String>monodroid</x:String>
</x:Array>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<projectName:CardView HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
I upload a sample here and you can check.
Yes you can do that using ContentView, if you want to use it as views
Or you can make ViewCells if you want to use it in ListViews. Its easy and almost every project does that.
You can refer this link :- https://xamarinhelp.com/xamarin-forms-user-control/
Let me know if you have more questions on this. Thanks!

How to provide BindingContext to Control template

I have a template defined in App.Xaml
<ResourceDictionary>
<ControlTemplate x:Key="HomePageTemplate">
<Label Text="{Binding MyLabelText}"/>
</ControlTemplate>
</ResourceDictionary>
And I use it in my Home page
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cv="clr-namespace:Xamarin.Forms;assembly=Xamarin.Forms.CarouselView"
xmlns:local="clr-namespace:App.Converters"
x:Class="App.Views.HomePage"
ControlTemplate="{StaticResource HomePageTemplate}">
</ContentPage>
I set the BindingContext of my Homepage in code behind.
Now shouldn't the ControlTemplate inherit the HomePage's BindingContext ? Because I thought that was the case but my Label doesn't keep the text from MyLabelText. What's the work around to work with Bindings in these templates ?
EDIT:
Using this option
<ResourceDictionary>
<ControlTemplate x:Key="HomePageTemplate">
<Label Text="{TemplateBinding Parent.BindingContext.MyLabelText}"/>
</ControlTemplate>
</ResourceDictionary>
Also does not work for me, because I use the ControlTemplatein the header of the HomePage and not inside it's body.
This works BUT IT'S NOT what I'm looking for:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cv="clr-namespace:Xamarin.Forms;assembly=Xamarin.Forms.CarouselView"
xmlns:local="clr-namespace:App.Converters"
x:Class="App.Views.HomePage"
>
<ContentView ControlTemplate="{StaticResource HomePageTemplate}" />
</ContentPage>
With ControlTemplate controls the binding is slightly different. Have a look at these docs: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/control-templates/template-binding
Assuming that the MyLabelText property is part of the BindingContext of the parent control your code could look like this:
<ResourceDictionary>
<ControlTemplate x:Key="HomePageTemplate">
<Label Text="{TemplateBinding Parent.BindingContext.MyLabelText }"/>
</ControlTemplate>
</ResourceDictionary>
App.xaml should have a BindingContext. Let's call it AppViewmodel, with a namespace vm (or any other key) defined at the top of App.xaml. This AppViewmodel can be bound to from within the ControlTemplate. In this example a button (placed in a stacklayout) is bound to a command named AppCommand, which resides in AppViewmodel. When this ControlTemplate is applied in a ContentPage, it binds to the ViewModel of App.xaml, not to the VM of that particular ContentPage. Perhaps the latter is also possible, for example by choosing the right settings for RelativeSource and AncestorType, but I haven't figured that out.
see also
<ControlTemplate x:Key="HomePageTemplate">
<StackLayout BindingContext="{Binding Source={RelativeSource TemplatedParent}}">
<Button
Command="{Binding Source={RelativeSource AncestorType={x:Type vm:AppViewModel}}, Path=AppCommand}"
/>
</StackLayout>
</ControlTemplate>
If anyone its interested, the way this works its just adding Path after TemplateBinding, specifying BindingContext on it and then the public var name:
<ResourceDictionary>
<ControlTemplate x:Key="HomePageTemplate">
<Label Text="{ TemplateBinding Path=BindingContext.MyLabelText }"/>
</ControlTemplate>
</ResourceDictionary>

binding a Custom control in DataTemplate

I've been tackling a problem regarding databinding in XAML for a little while now.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Pedagouge.Views;assembly=Pedagouge"
x:Class="Pedagouge.Views.StudentGroupView">
<StackLayout>
<ListView x:Name="Students">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<local:PhotoView x:Name="Photo" Persona="{Binding}" />
<StackLayout Orientation="Vertical" HorizontalOptions="StartAndExpand" VerticalOptions="StartAndExpand">
<Label Text="{Binding FullName}" />
<Label Text="{Binding StudentIsAt.Group.Name}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
I thought I had binding figured, but the problem I'm having clearly shows that I'm not.
Anyways, the problem is that for the custom control PhotoView it seems that the binding context used by {Binding} to the property Persona is the PhotoView's BindingContext, not the DataTemplate's context, as it is for the Labels a couple of rows down.
Had this been WPF, I would have just changed the binding to
Persona="{Binding DataContext,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBoxItem}}"
and that would probably have fixed it, but that won't work here (RelativeSource is apparently not defined).
How come? How can I make Persona bound to the DataTemplates context, as is the case with the Labels, instead?
Xamarin.Forms (up to 1.2.x) bindings always use the BindableObject.BindingContext as the context binding.
In the case of templates items, the item context is set to the template element, in this case the ViewCell, and recursively to the ViewCell.View, the StackLayout, your PhotoView, the inner StackLayout and the 2 Labels.
The fact that FullName and StudentIsAt.Group.Name works is a strong hint.
So, when you say
[...] for the custom control PhotoView it seems that the binding context used by
{Binding} to the property Persona is the PhotoView's BindingContext, not the
DataTemplate's context, [...]
it's both true and wrong.
The binding context used by {Binding} is the PhotoView's Bindingcontext, which is also the DataTemplate's context.
If the Binding does not work as you expect, it's probably because PhotoView somehow set the BindingContext to this, and prevent the {Binding} to work as expected, but I can't say without seeing PhotoView's code.

Silverlight 3 IValueConverter troubles

First let me say I'm new to Silverlight. But I have most of the "basic" Silverlight stuff figured out. I'm using Silverlight 3 at the moment.
In a nutshell, I am not seeing my IValueConverter called inside a UserControl. But as with many things, it's not quite that simple. The UserControl is in a DataGrid cell, in a column whose DataColumnTemplate is generated at runtime by XAML.
Here's my DataTemplate for the Column:
StringBuilder CellTemp = new StringBuilder();
CellTemp.Append("<DataTemplate ");
CellTemp.Append("xmlns:aa='clr-namespace:InvTech.AA.Silverlight.UI;assembly=AASilverlight' ");
CellTemp.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
CellTemp.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ");
CellTemp.Append(">");
CellTemp.AppendFormat("<aa:ProductAssetView DataContext='{{Binding Products[{0}]}}' />", index);
CellTemp.Append("</DataTemplate>");
return CellTemp.ToString();
So the cell's contents are getting bound to my UserControl. This works; I just can't get my IValueConverter called to format the contents of the UserControl the way I want.
The operative parts of the UserControl XAML:
(declare prefix)
xmlns:aaConv="clr-namespace:InvTech.AA.Silverlight.Core;assembly=AA.Core"
(bound controls inside Grid layout)
<TextBox x:Name="txtSAA" Grid.Row="0" Grid.Column="0" Text="{Binding SAA, Converter={StaticResource PercentConverter}, Mode=TwoWay}" Width="35" FontSize="9"/>
<TextBox x:Name="txtOVR" Grid.Row="0" Grid.Column="1" Text="{Binding Overlay, Converter={StaticResource PercentConverter}, Mode=TwoWay}" Width="35" FontSize="9" />
<TextBox x:Name="txtTAA" Grid.Row="0" Grid.Column="2" Text="{Binding TAA, Converter={StaticResource PercentConverter}, Mode=TwoWay}" Width="35" FontSize="9" />
<TextBlock x:Name="tbkCurrent" Grid.Row="0" Grid.Column="3" Text="TODO" Width="35" FontSize="9" />
<Grid.Resources>
<aaConv:PercentValueConverter x:Key="PercentConverter" />
</Grid.Resources>
Is there something obviously wrong here? Is the dynamic XAML a factor? I feel like this should be trivial compared to the dynamic XAML template...
Thanks
Finally figured this out. By moving the Resource declaration to <UserControl.Resources> and putting that tag before the content, my IValueConverters were exercised.

Resources