How to provide BindingContext to Control template - xamarin.forms

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>

Related

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!

Xamarin.Forms: How to hide the Navigation Bar Separator on iOS devices?

I have changed the default color of the navigation bar by using these codes in app.xaml as I am unable to make it transparent on iOS devices:
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor" Value="#0a82b8" />
<Setter Property="BarTextColor" Value="#ffffff" />
</Style>
Now, there is an unnecessary navigation bar separator on iOS:
On Microsoft's official website, it says these codes can be helpful:
This platform-specific hides the separator line and shadow that is at
the bottom of the navigation bar on a NavigationPage. It's consumed in
XAML by setting the NavigationPage.HideNavigationBarSeparator bindable
property to false:
<NavigationPage ...
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:NavigationPage.HideNavigationBarSeparator="true">
</NavigationPage>
Alternatively, it can be consumed from C# using the fluent API:
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
public class iOSTitleViewNavigationPageCS : Xamarin.Forms.NavigationPage
{
public iOSTitleViewNavigationPageCS()
{
On<iOS>().SetHideNavigationBarSeparator(true);
}
}
Source: Hiding the Navigation Bar Separator on a NavigationPage
The problem is that when I want to paste the ios:NavigationPage.HideNavigationBarSeparator="true" property into the <NavigationPage>tag, it gives this error:
No property, bindable property, or event found for 'HideNavigationBarSeparator', or mismatching type between value and property.
My full codes are:
<?xml version="1.0" encoding="utf-8"?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:My.App" x:Class="My.App.MainPage">
<MasterDetailPage.Master>
<ContentPage Title="Menu" BackgroundColor="#0a82b8" Icon="menu.png">
<StackLayout Orientation="Vertical">
<ListView x:Name="navigationDrawerList" RowHeight="55" SeparatorVisibility="None" BackgroundColor="#ffffff" ItemSelected="OnMenuItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<!-- Main design for our menu items -->
<StackLayout VerticalOptions="FillAndExpand" Orientation="Horizontal" Padding="20,10,0,10" Spacing="20">
<Label Text="{Binding Title}" FontSize="Large" VerticalOptions="Start" HorizontalOptions="CenterAndExpand" TextColor="#28DDFF" FontAttributes="Bold" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:NavigationPage.HideNavigationBarSeparator="true">
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
Here is the tutorial which I followed for the MasterDetail navigation. The file which has <NavigationPage> tag is named as MainPage.xaml
You can use a custom renderer to hide that shadow:
[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationPage))]
namespace CustomNavigationPage.iOS
{
public class CustomNavigationPage : NavigationRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
NavigationBar.SetBackgroundImage(new UIKit.UIImage(), UIKit.UIBarMetrics.Default);
NavigationBar.ShadowImage = new UIKit.UIImage();
}
}
}
While you have accepted the answer, this one is more precise - you haven't followed the instructions that you have pasted from the site as you have ommited this line:
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
Place UINavigationBar.Appearance.ShadowImage = new UIImage(); inside the public override bool FinishedLaunching(UIApplication app, NSDictionary options) method within AppDelegate.cs file. AppDelegate.cs resides within the iOS project of Xamarin.Forms

xamarin.forms add switch in toolbar

Is it possible to add a switch on the toolbar?
<ContentPage.ToolbarItems>
<ToolbarItem>
<Switch x:Name="Switch1" IsToggled="True" Margin="5,0,0,0"/>
</ToolbarItem>
</ContentPage.ToolbarItems>
Does anybody have any ideas?
Thanks!
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TitleViewSample"
x:Class="TitleViewSample.MainPage">
<NavigationPage.TitleView>
<Switch x:Name="Switch1" IsToggled="True" Margin="5,0,0,0"/>
</NavigationPage.TitleView>
<ContentPage.Content>
<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
I don't think it is possible. You can, however, take the same approach I did when I needed to customise my title bar.
First, you hide the navigation bar, then you can specify your bar at the top, and use the controls you would like.

XFGloss: How to define as global style in App.xaml

I want to each content page contain the following element
<xfg:ContentPageGloss.BackgroundGradient>
<xfg:Gradient Rotation="170">
<xfg:GradientStep StepColor="#9DCC5F" StepPercentage="0" />
<xfg:GradientStep StepColor="#00B0CD" StepPercentage="1" />
</xfg:Gradient>
</xfg:ContentPageGloss.BackgroundGradient>
How can I do?
Why not create an overload of the ContentPage?
Create a file, for instance, GlossContentPage.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:xfg="clr-namespace:XFGloss;assembly=XFGloss"
x:Class="YourApp.Pages.GlossContentPage">
<xfg:ContentPageGloss.BackgroundGradient>
<xfg:Gradient Rotation="170">
<xfg:GradientStep StepColor="#9DCC5F" StepPercentage="0" />
<xfg:GradientStep StepColor="#00B0CD" StepPercentage="1" />
</xfg:Gradient>
</xfg:ContentPageGloss.BackgroundGradient>
</ContentPage>
Now just start using your new GlossContentPage, instead of a regular ContentPage, like:
<pages:GlossContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:YourApp.Pages;assembly=YourApp"
x:Class="YourApp.Pages.MyNewShinyPage">
<Label Text="Welcome to Xamarin.Forms" HorizontalOptions="Center" VerticalOptions="Center" />
</pages:GlossContentPage>

XamarinForm DataTemplate ListView 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.

Resources