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
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;
}
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:
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:
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!
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;
}
}