can't bind a viewmodel to a ResourceDictionary - xamarin.forms

I am trying to bind my ViewModelBase in a ResourceDictionary so that I can call some of the properties to set the properties on my controls, for example I have a label and I want to set its color by one of the properties in my ViewModelBase...
Update: The ResourceDictionary resides in my styles folder and gets called on bootup, it does not reside in a page like so...
void LoadStyles()
{
if (IsASmallDevice())
{
MyResources.MergedDictionaries.Add(SmallDevicesStyle.SharedInstance);
}
else
{
MyResources.MergedDictionaries.Add(GeneralDevicesStyle.SharedInstance);
}
}
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary 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"
xmlns:viewModels="clr-namespace:MyApp.ViewModels"
mc:Ignorable="d"
x:Class="MyApp.Styles.GeneralDevicesStyle">
<viewModels:ViewModelBase x:Key="BaseView"/>
<OnIdiom x:TypeArguments="x:Double" Tablet="30" Phone="10" x:Key="PageSpacing" />
<OnIdiom x:TypeArguments="Thickness" Tablet="10" Phone="10" x:Key="PagePadding" />
<Style TargetType="Label" x:Key="LabelStyle1">
<Setter Property="FontSize">
<Setter.Value>
<OnIdiom x:TypeArguments="x:Double" Phone="15" Tablet="15"/>
</Setter.Value>
</Setter>
<Setter Property="HorizontalOptions" Value="FillAndExpand" />
<Setter Property="VerticalOptions" Value="FillAndExpand" />
<Setter Property="BackgroundColor" Value="{Binding DefaultLabelColor}" />
</Style>
</ResourceDictionary>
public class ViewModelBase : BaseViewModel
{
sting BackGroundColor = "aqua";
public string DefaultBackGroundColor { get return BackGroundColor; }
}
So my question is, How can I bind my ViewModelBase in my ResourceDictionary so that I can access the properties/Methods that reside in the ViewModelBase?

You need to set the BindingContext for Label.
ViewModelBase:
public class ViewModelBase
{
//public string DefaultBackGroundColor { get; set; } = "Aqua";
private string BackGroundColor = "Aqua";
public string DefaultBackGroundColor
{
get { return BackGroundColor; }
}
}
Xaml:
<ContentPage.Resources>
<ResourceDictionary>
<viewModels:ViewModelBase x:Key="BaseView" />
</ResourceDictionary>
<Style TargetType="Label">
<Setter Property="BackgroundColor" Value="{Binding DefaultBackGroundColor}" />
<Setter Property="BindingContext" Value="{StaticResource BaseView}"></Setter>
</Style>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>

Related

Not working ListView GetContainerForItemOverride method

GetContainerForItemOverride method working in WinUI UWP
but not working in Uno Platform.
how to do GetContainerForItemOverride???
this is Implemented Method in Uno platform reference Docs > Itemcontrol(https://platform.uno/docs/articles/implemented/windows-ui-xaml-controls-itemscontrol.html)
anyway. this is my code
public partial class Breadcrumb : ListView
{
public Breadcrumb()
{
this.DefaultStyleKey = typeof(Breadcrumb);
}
protected override DependencyObject GetContainerForItemOverride()
{
return new BreadcrumbItem();
}
}
public partial class BreadcrumbItem : ListViewItem
{
public BreadcrumbItem()
{
var test = this.Content;
this.DefaultStyleKey = typeof(BreadcrumbItem);
this.Loaded += OnLoaded;
}
........
}
XAML
<Style TargetType="controls:Breadcrumb">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:Breadcrumb">
.......Text....
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="controls:BreadcrumbItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border
Margin="4"
Padding="4"
Background="Red">
<Grid>
<ContentPresenter Content="{TemplateBinding Content}" />
<TextBlock
x:Name="separator"
HorizontalAlignment="Right"
Text=" / " />
</Grid>
</Border>
<!-- mouse over -->
<!-- IsSelected -->
<!-- IsFirst -->
<!-- IsLast -->
<!-- <ControlTemplate.VisualTree -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
ItemsSources
xmlns:c="using:My.Controls"
<StackPanel Orientation="Horizontal">
<c:Breadcrumb ItemsSource="{x:Bind HistoryItemsSource, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
NavigationHistoryControl.cs
[ContentProperty(Name = "HistoryItemsSource")]
public sealed partial class NavigationHistoryControl : UserControl, INotifyPropertyChanged
{
public NavigationHistoryControl()
{
this.InitializeComponent();
this.HistoryItemsSource = new List<NavigationItem>()
{
new NavigationItem(){
Content = "Content1",
Icon = new SymbolIcon(Symbol.Home),
ViewPathType= typeof(Views.View1)
},
new NavigationItem(){
Content = "Content2",
Icon = new SymbolIcon(Symbol.Home),
ViewPathType= typeof(Views.View2)
},
};
public IEnumerable<NavigationItem> HistoryItemsSource
{
get { return (IEnumerable<NavigationItem>)GetValue(HistoryItemsSourceProperty); }
set => SetValue(HistoryItemsSourceProperty, value);
}
public static readonly DependencyProperty HistoryItemsSourceProperty = DependencyProperty.Register("HistoryItemsSource", typeof(IEnumerable<NavigationItem>), typeof(NavigationHistoryControl), new PropertyMetadata(null));
public event PropertyChangedEventHandler PropertyChanged;
}

VisualStateManager change background frame/pancakeview does not work

Problem
Visual state manager does not kick in
How do I change background of
the selected frame?
Any suggestions of what I am doing wrong?
I need to create an horizontal list with a set of frames that when selected change background color.
The obvious implementation would be a collectionView and that has a SelectedItem that would just work , so what is the problem with that?
Well if you have a pancakeView/frame with rounded corners in iOS you can see the grey background and its a bug reported in xamarin forms.
So I decided to implement a bindableLayout, this works fine however I have tried all sorts but I cannot change the background color of the pancake/frame and a label on selection , below is what I have done
MAIN PAGE
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Grid">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="LightSkyBlue" />
<Setter TargetName="LabelA" Property="Label.TextColor" Value="Red"/>
<Setter TargetName="Labelb" Property="Label.TextColor" Value="Red"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<FlexLayout x:Name="Flex"
Direction="Row"
BindableLayout.ItemsSource="{Binding Cities}"
Position="Relative"
AlignItems="Start"
FlowDirection="LeftToRight"
JustifyContent="SpaceEvenly">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid x:Name="myGrid" Padding="8,0" FlexLayout.AlignSelf="Start" >
<pancakeView:PancakeView x:Name="myPancake"
Padding="20"
Margin="5"
CornerRadius="5"
WidthRequest="60"
HeightRequest="60"
BackgroundColor="White" >
<pancakeView:PancakeView.Border>
<pancakeView:Border Thickness="1" Color="Blue" />
</pancakeView:PancakeView.Border>
<StackLayout >
<Label x:Name="LabelA" Margin="0,0,0,0"
Text="{Binding Name }"
TextColor="Gray"
HorizontalOptions="Center" VerticalOptions="Center">
</Label>
<Label x:Name="Labelb" VerticalOptions="EndAndExpand"
HorizontalTextAlignment="Center"
TextColor="Gray"
FontSize="12"
Text="SomeText Here" />
</StackLayout>
<pancakeView:PancakeView.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_OnTapped">
</TapGestureRecognizer>
</pancakeView:PancakeView.GestureRecognizers>
</pancakeView:PancakeView>
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>
</ContentPage>
MAIN PAGE CODE BEHIND
using System;
using Xamarin.Forms;
namespace BlankApp2.Views
{
public partial class MainPage
{
string currentColorState = "Normal";
public MainPage()
{
InitializeComponent();
}
private void TapGestureRecognizer_OnTapped(object sender, EventArgs e)
{
currentColorState = currentColorState == "Normal" ? "Focused" : "Normal";
//below has errors since "myPancake, LabelA Labelb are not recognized WHY????
// VisualStateManager.GoToState(myPancake,_currentColorState);
// VisualStateManager.GoToState(LabelA, _currentColorState);
// VisualStateManager.GoToState(Labelb, _currentColorState);
}
}
}
VIEWMODEL
using Prism.Navigation;
using System.Collections.ObjectModel;
namespace BlankApp2.ViewModels
{
public class MainPageViewModel : ViewModelBase
{
public MainPageViewModel(INavigationService navigationService)
: base(navigationService)
{
Title = "Main Page";
Cities = GetCities();
}
private ObservableCollection<City> cities;
public ObservableCollection<City> Cities
{
get => cities;
set => SetProperty(ref cities, value);
}
private ObservableCollection<City> GetCities()
{
var list = new ObservableCollection<City>
{
new City {Name = "London"},
new City {Name = "Rome"},
new City {Name = "New York"}
};
return list;
}
}
public class City
{
public string Name { get; set; }
}
}
Try to add VisualStateManager.VisualStateGroups your frame/pancakeviw(Here I'm testing with frame).
create a custom frame:
class MyFrame :Frame
{
public bool IsFoucs { get; set; }
}
the page.xaml:
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="local:MyFrame">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" >
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="White" />
<Setter TargetName="LabelA" Property="Label.TextColor" Value="Gray"/>
<Setter TargetName="Labelb" Property="Label.TextColor" Value="Gray"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="LightSkyBlue" />
<Setter TargetName="LabelA" Property="Label.TextColor" Value="Red"/>
<Setter TargetName="Labelb" Property="Label.TextColor" Value="Red"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<FlexLayout x:Name="Flex"
Direction="Row"
BindableLayout.ItemsSource="{Binding Cities}"
Position="Relative"
AlignItems="Start"
FlowDirection="LeftToRight"
JustifyContent="SpaceEvenly">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid x:Name="myGrid" Padding="8,0" FlexLayout.AlignSelf="Start" >
<local:MyFrame x:Name="myPancake"
Padding="20"
Margin="5"
CornerRadius="5"
WidthRequest="60"
HeightRequest="60"
BorderColor="Blue"
BackgroundColor="White" >
<StackLayout >
<Label x:Name="LabelA" Margin="0,0,0,0"
Text="{Binding .}"
TextColor="Gray"
HorizontalOptions="Center" VerticalOptions="Center">
</Label>
<Label x:Name="Labelb" VerticalOptions="EndAndExpand"
HorizontalTextAlignment="Center"
TextColor="Gray"
FontSize="12"
Text="SomeText Here" />
</StackLayout>
<local:MyFrame.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_OnTapped">
</TapGestureRecognizer>
</local:MyFrame.GestureRecognizers>
</local:MyFrame>
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>
then in the page.cs:
private void TapGestureRecognizer_OnTapped(object sender, EventArgs e)
{
foreach (var item in Flex.Children)
{
MyFrame frame = (MyFrame)item.FindByName("myPancake");
frame.IsFoucs = false;
VisualStateManager.GoToState(frame, "Normal");
}
MyFrame myFrame = sender as MyFrame;
myFrame.IsFoucs = !myFrame.IsFoucs;
VisualStateManager.GoToState(myFrame, myFrame.IsFoucs ? "Focused" : "Normal");
}
the effect is like below:

How paint a item selected with differents colors?

i have a collection
<CollectionView SelectionMode="Single"
ItemsSource="{Binding Cities}"
ItemsLayout="HorizontalList">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="5">
<Image Source="{Binding Image}" />
<Label TextColor="Black" text="Text"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
How can i painting with diferents colors the image and label when i select a item?
According to your description, you have Image and Label in CollectionView DataTemplate, you want to set Image and Label different background color when you select one item, am I right?
If yes, I suggest you can use binding Background color to do this, please take a look my code:
<ContentPage.Resources>
<Style TargetType="StackLayout">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<CollectionView
ItemsSource="{Binding images}"
SelectionChanged="CollectionView_SelectionChanged"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="5">
<Frame BackgroundColor="{Binding imagecolor}" CornerRadius="5">
<Image Source="{Binding Image}" />
</Frame>
<Label
BackgroundColor="{Binding labelcolor}"
Text="{Binding cityname}"
TextColor="Black" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage.Content>
public partial class Page3 : ContentPage
{
public ObservableCollection<imagemodel> images { get; set; }
public Page3()
{
InitializeComponent();
images = new ObservableCollection<imagemodel>()
{
new imagemodel(){Image="a5.jpg",cityname="beijing",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a6.jpg",cityname="shanghai",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a7.jpg",cityname="shenzhen",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a8.jpg",cityname="xiamen",imagecolor=Color.White,labelcolor=Color.White}
};
this.BindingContext = this;
}
private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
imagemodel previous = (e.PreviousSelection.FirstOrDefault() as imagemodel);
imagemodel current = (e.CurrentSelection.FirstOrDefault() as imagemodel);
//Set the current to the color you want
current.imagecolor = Color.Pink;
current.labelcolor = Color.Green;
if (previous != null)
{
//Reset the previous to defaulr color
previous.imagecolor = Color.White;
previous.labelcolor = Color.White;
}
}
}
public class imagemodel:ViewModelBase
{
public string Image { get; set; }
public string cityname { get; set; }
private Color _imagecolor;
public Color imagecolor
{
get { return _imagecolor; }
set
{
_imagecolor = value;
RaisePropertyChanged("imagecolor");
}
}
private Color _labelcolor;
public Color labelcolor
{
get { return _labelcolor; }
set
{
_labelcolor = value;
RaisePropertyChanged("labelcolor");
}
}
}
The ViewModelbase implement INotifyPropertyChanged interface:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Update:
If you want to use mvvm mode to do this, and put CollectionView_SelectionChanged method in my viewModel, I suggest you can bind SelectionChangedCommand to do this, please take a look my code:
The ContentPage:
<ContentPage.Resources>
<Style TargetType="StackLayout">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<CollectionView
ItemsSource="{Binding images}"
SelectedItem="{Binding CurrentSelection}"
SelectionChangedCommand="{Binding selectioncommand}"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="5">
<Frame BackgroundColor="{Binding imagecolor}" CornerRadius="5">
<Image Source="{Binding Image}" />
</Frame>
<Label
BackgroundColor="{Binding labelcolor}"
Text="{Binding cityname}"
TextColor="Black" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage.Content>
public partial class Page3 : ContentPage
{
public Page3()
{
InitializeComponent();
this.BindingContext = new imageviewmodel();
}
}
The imageviewmodel.cs:
public class imageviewmodel:ViewModelBase
{
public ObservableCollection<imagemodel> images { get; set; }
private imagemodel _PreviousSelection;
public imagemodel PreviousSelection
{
get { return _PreviousSelection; }
set
{
_PreviousSelection = value;
RaisePropertyChanged("PreviousSelection");
}
}
private imagemodel _CurrentSelection;
public imagemodel CurrentSelection
{
get { return _CurrentSelection; }
set
{
if(CurrentSelection!=value)
{
PreviousSelection = CurrentSelection;
_CurrentSelection = value;
RaisePropertyChanged("CurrentSelection");
}
}
}
public Command selectioncommand { get; set; }
public imageviewmodel()
{
images = new ObservableCollection<imagemodel>()
{
new imagemodel(){Image="a5.jpg",cityname="beijing",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a6.jpg",cityname="shanghai",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a7.jpg",cityname="shenzhen",imagecolor=Color.White,labelcolor=Color.White},
new imagemodel(){Image="a8.jpg",cityname="xiamen",imagecolor=Color.White,labelcolor=Color.White}
};
selectioncommand = new Command(changecolor);
}
private void changecolor()
{
foreach(imagemodel model in images)
{
if(model.cityname==CurrentSelection.cityname)
{
model.imagecolor = Color.Pink;
model.labelcolor = Color.Green;
}
else if(PreviousSelection != null && model.cityname==PreviousSelection.cityname)
{
model.imagecolor = Color.White;
model.labelcolor = Color.White;
}
}
}
}
The screenshot is same.
The screenshot:

Xamarin Forms TemplateBinding to Command In BasePage

I have a BasePage created using ControlTemplates that contains a loading overlay for each child to use - This overlay has a "cancel" button on it, but for some reason I can't get ICommands to execute when I tap the buttons. Clicked events work fine but I'd like to understand what the problem is with Commands.
I researched the issue and found I should be binding using Command="{TemplateBinding MyCommand}" since my content is within a ControlTemplate but still no luck, however I am also binding the Text property and this is working fine, so I'm a bit confused.
Here's a cut down version of what I've hacked together.
Here's my BasePage XAML with the button in question:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage x:Name="this" NavigationPage.HasNavigationBar="False" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:helpers="clr-namespace:ShoppingListNEW.MarkupExtensions" xmlns:views="clr-namespace:ShoppingListNEW.Views" x:Class="ShoppingListNEW.Pages.BasePage">
<ContentPage.ControlTemplate>
<ControlTemplate>
<Grid Padding="0" RowSpacing="0" ColumnSpacing="0">
<StackLayout>
<StackLayout.Padding>
<OnPlatform x:TypeArguments="Thickness" iOS="0,30,0,0"/>
</StackLayout.Padding>
<ScrollView VerticalOptions="FillAndExpand" >
<StackLayout RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width}" RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height}" Orientation="Vertical">
<ContentPresenter />
</StackLayout>
</ScrollView>
</StackLayout>
<AbsoluteLayout IsVisible="False" Grid.Row="0" Grid.Column="0" x:Name="loading" BackgroundColor="#85000000" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1">
<ActivityIndicator Color="Lime" Scale="2" IsRunning="true" IsEnabled="true" IsVisible="true" AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5,0.4" />
<Button IsVisible="True" Text="{TemplateBinding MyTextLabel}" AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5,0.5" Command="{TemplateBinding MyCommand}" />
</AbsoluteLayout>
</Grid>
</ControlTemplate>
</ContentPage.ControlTemplate>
</ContentPage>
And here's the C# for that BasePage:
using System;
using System.Windows.Input;
using ShoppingListNEW.Views;
using Xamarin.Forms;
namespace ShoppingListNEW.Pages
{
public partial class BasePage : ContentPage
{
public string MyTextLabel { get; set; } = "This Works";
public ICommand MyCommand { get; set; }
public BasePage()
{
InitializeComponent();
MyCommand = new Command(() =>
{
Console.Write("But this doesn't work :(");
});
}
public void ShowHideLoading(bool showhide, bool allowCancel = false)
{
var loadingLayout = (AbsoluteLayout)GetTemplateChild("loading");
var cancelButton = loadingLayout.FindByName<Button>("btnCancel");
cancelButton.IsVisible = allowCancel;
loadingLayout.IsVisible = showhide;
}
}
}
Any ideas?
On your ControlTemplate binding, please use the following code:
<Button
AbsoluteLayout.LayoutBounds="0.5,0.5"
AbsoluteLayout.LayoutFlags="PositionProportional"
Command="{TemplateBinding BindingContext.MyCommand}"
IsVisible="True"
Text="{TemplateBinding BindingContext.MyTextLabel}" />
I use your code to create simple that you can take a look, please don't set AbsoluteLayout IsVisible="False".
<ContentPage.ControlTemplate>
<ControlTemplate>
<Grid Padding="0">
<StackLayout>
<ScrollView VerticalOptions="FillAndExpand">
<StackLayout
Orientation="Vertical"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Height}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Width}">
<ContentPresenter />
</StackLayout>
</ScrollView>
</StackLayout>
<AbsoluteLayout
x:Name="loading"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="#85000000">
<ActivityIndicator
AbsoluteLayout.LayoutBounds="0.5,0.4"
AbsoluteLayout.LayoutFlags="PositionProportional"
IsEnabled="true"
IsRunning="true"
IsVisible="true"
Scale="2"
Color="Lime" />
<Button
AbsoluteLayout.LayoutBounds="0.5,0.5"
AbsoluteLayout.LayoutFlags="PositionProportional"
Command="{TemplateBinding BindingContext.MyCommand}"
IsVisible="True"
Text="{TemplateBinding BindingContext.MyTextLabel}" />
</AbsoluteLayout>
</Grid>
</ControlTemplate>
</ContentPage.ControlTemplate>
public partial class Page19 : ContentPage
{
public Page19()
{
InitializeComponent();
this.BindingContext = new Viewmodel1();
}
}
public class Viewmodel1:ViewModelBase
{
private string _MyTextLabel;
public string MyTextLabel
{
get { return _MyTextLabel; }
set
{
_MyTextLabel = value;
RaisePropertyChanged("MyTextLabel");
}
}
public RelayCommand MyCommand { get; set; }
public Viewmodel1()
{
MyCommand = new RelayCommand(method);
MyTextLabel = "this is test";
}
private void method()
{
Console.WriteLine("this is test!");
}
}
Problem solved. Thanks to Mikolaj Kieres for the answer, it was a simple case of initialising the Command earlier so I moved it up above the InitializeComponent and that kicked it into life. Thanks!

OnApplyTemplate doesn't capture the BindingContext of the parent?

In a test project, I'm trying to get the BindingContext of the parent control with template binding,
here, in the MainPage, I have two templates temp1 and temp2
<?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:vm="clr-namespace:MyXam.ViewModels"
xmlns:views="clr-namespace:MyXam.Views"
x:Class="MyXam.Views.MainPage"
x:DataType="vm:MainViewModel">
<ContentPage.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="temp1">
<views:View1/>
</ControlTemplate>
<ControlTemplate x:Key="temp2">
<views:View2/>
</ControlTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout x:Name="stk">
<Button Text="Switch view" Command="{Binding SwitchViewCommand}"/>
<ContentView x:Name="cv" ControlTemplate="{StaticResource temp2}" VerticalOptions="Start" HorizontalOptions="Center">
<ContentView.Triggers>
<DataTrigger TargetType="ContentView" Binding="{Binding IsView1}" Value="False">
<Setter Property="ControlTemplate" Value="{StaticResource temp2}"/>
</DataTrigger>
<DataTrigger TargetType="ContentView" Binding="{Binding IsView1, Mode=TwoWay}" Value="True">
<Setter Property="ControlTemplate" Value="{StaticResource temp1}"/>
</DataTrigger>
</ContentView.Triggers>
</ContentView>
</StackLayout>
</ContentPage>
I want to get the BindingContext of the MainPage in View2, in the ctor:
SetBinding(BindingContextProperty, new Binding("Parent.BindingContext", source: RelativeBindingSource.TemplatedParent));
but when I try to get its vzlue in the OnApplyTemplate it's null:
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
vm = this.GetValue(BindingContextProperty);
}
However binding is resolved in xaml:
<Label Text="{Binding Name, Source={Reference this}}"/>
I couldn't see the detail of your other code, but you can refer to the following code.
Define a BindableProperty for this Label in xaml.cs and use the Name Property,e.g. x:Name="TestControlView" and binding like this
<Label Text="{Binding Source={x:Reference TestControlView}, Path=TestText}" />
You can check the full demo here.
The main code is like this:
TestControl.xaml.cs(TestControl is a ContentView)
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TestControl : ContentView
{
public static readonly BindableProperty TestTextProperty = BindableProperty.Create(nameof(TestText), typeof(string), typeof(TestControl));
public string TestText
{
get { return (string)GetValue(TestTextProperty); }
set { SetValue(TestTextProperty, value); }
}
public TestControl()
{
InitializeComponent();
}
}
TestControl.xaml
MainPage.xaml
<ListView x:Name="lstView" HorizontalOptions="Fill" HasUnevenRows="True" RefreshAllowed="true" IsPullToRefreshEnabled="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame CornerRadius="10" BackgroundColor="White" Margin="0,5,0,5">
<StackLayout Orientation="Horizontal" HorizontalOptions="Center">
<controls:TestControl TestText="{Binding Title}" VerticalOptions="Center"/>
<Label Text="{Binding Type}" FontSize="Medium" TextColor="#F0BB7F" FontAttributes="Bold" VerticalOptions="Center"/>
</StackLayout>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
public ObservableCollection<TestModel> veggies { get; set; }
public MainPage()
{
InitializeComponent();
veggies = new ObservableCollection<TestModel>();
veggies.Add(new TestModel { Title = "Tomato", Type = "Fruit" });
veggies.Add(new TestModel { Title = "Zucchini", Type = "Vegetable" });
veggies.Add(new TestModel { Title = "Tomato" , Type = "Vegetable" });
veggies.Add(new TestModel { Title = "Romaine", Type = "Fruit" });
veggies.Add(new TestModel { Title = "Zucchini", Type = "Vegetable" });
lstView.ItemsSource = veggies;
BindingContext = this;
}
}

Resources