Is instantiating a class in VM, MVVM compliant ? How else if so? - xaml

I have a contentpage and a ContentView with the content property bound to the view model
MainPage:
`
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="MvvM.Views.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MvvM.Views"
xmlns:vm="clr-namespace:MvvM.ViewModels">
<!-- ViewModel BindingContext -->
<ContentPage.BindingContext>
<vm:MainViewModel />
</ContentPage.BindingContext>
<Grid>
<Grid.RowDefinitions>
<!-- Header Row -->
<RowDefinition Height="50" />
<!-- ContentView Row -->
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Header -->
<Grid Grid.Row="0"
BackgroundColor="CornflowerBlue"
VerticalOptions="FillAndExpand">
<!-- Button On Header -->
<Button Command=""
Text="Page Switch"
VerticalOptions="Center">
<Button.GestureRecognizers>
<TapGestureRecognizer Command="TapGestureCommand" />
</Button.GestureRecognizers>
</Button>
</Grid>
<!-- Content Container -->
<Grid Grid.Row="1" VerticalOptions="Center">
<ContentView Content="{Binding DisplayPage}" />
</Grid>
</Grid>
</ContentPage>
`
ViewModel:
`using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using MvvM.Views;
using Xamarin.Forms;
namespace MvvM.ViewModels
{
public class MainViewModel :INotifyPropertyChanged
{
public MainViewModel()
{
DisplayPage = new Views.MainPage();
}
private ContentPage _displayPage;
public ContentPage DisplayPage
{
get { return _displayPage; }
set
{
if (value != _displayPage)
{
_displayPage = value;
}
}
}
private ContentView _contentToDisplayView;
public ContentView SelectedView
{
get => _contentToDisplayView;
set
{
_contentToDisplayView = value;
OnPropertyChanged();
}
}
public Command TapGestureCommand
{
get
{
return new Command(TapGesture);
}
}
private void TapGesture()
{
_contentToDisplayView = new RedView();
_displayPage.Content = _contentToDisplayView.Content;
OnPropertyChanged();
}
#region PropertyChangedHandler
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}`
and the second page called "RedPage" want to access the content from
`
<?xml version="1.0" encoding="utf-8" ?>
<ContentView x:Class="MvvM.Views.RedView"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:MvvM.ViewModels"
BindingContext="vm:MainViewModel">
<ContentView.Content>
<Grid Width="*"
Height="*"
BackgroundColor="Red" />
</ContentView.Content>
</ContentView> `
The outcome I want is the ContentView content on the RedPage to be displayed in the mainpage contentview.
is creating an instance of the redpage in the view model MVVM complaint ? (I feel that this would tightly bind view to view model?)
how else can i get the content property on red page into the view model ?(cant bind it and sets elements in it as you can only set content property once)

Ideally you would want the ViewModel not to know anything about the View and vice versa, so from that perspective this is not something you would want.
To overcome this, you would want ViewModel-to-ViewModel navigation. So, you just specify to which ViewModel you want to go and the associated View will be loaded. You can implement this manually, and depending on your chosen implementation you would have some way of resolving a View that is linked to that ViewModel.
One way to do this would be by naming conventions and reflection. This means you name all your pages like:
MyPage
YourPage
OurPage
And all the ViewModels like:
MyPageModel
YourPageModel
OurPageModel
Then with reflection you can simply strip off the "Model" suffix and resolve the page from there. Note that I use the Page and PageModel naming, but of course this works for View and ViewModel as well. After you do, you will still have to account for the navigation to and from this views, is it modal or not, etc.
While you can implement all of this manually it would probably be worth while to look into a MVVM framework. The method I just described is how FreshMvvm does this for instance. But there are other good frameworks out there like Prism, Exrin, MvvmCross, etc.

Related

How do you find the newly focused element in .net-maui (used inside unfocused event handler)

Case:
I want to keep an element focused unless the element that tries to grab focus is a another Entry element.
I have this component (SearchBar.xaml)
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:localization="clr-namespace:POS365.Src.Extensions"
xmlns:fontAwesome="clr-namespace:FontAwesome"
x:Class="SomeApp.Src.Components.SearchBar">
<Grid ColumnDefinitions="32,*">
<Label Grid.Column="0" FontFamily="FAS" Text="{x:Static fontAwesome:FontAwesomeIcons.MagnifyingGlass}" FontSize="Large" Style="{DynamicResource HeaderBarSearchIconStyle}"/>
<Entry Grid.Column="1" x:Name="SearchField" MaxLength="20" Text="" HeightRequest="32" />
</Grid>
</ContentView>
and (SearchBar.xaml.cs)
using System.ComponentModel;
namespace SomeApp.Src.Components;
public partial class SearchBar : ContentView
{
public SearchBar()
{
InitializeComponent();
SearchField.Unfocused += OnLostFocus;
}
public void OnLostFocus(object sender, FocusEventArgs e)
{
// TODO: Find out when to focus this, probably based on what takes focus if possible
// FocusSearchField();
}
// Used by Loaded event elsewhere
public void FocusSearchField()
{
SearchField.Focus();
}
}
It seems that OnLostFocus only gets the element that lost focus and not the element that took focus.
How do I get the current focused element, so I can see which type of element it is?
You can determine this by iterating through root's child view and calling the view.IsFocused method.
var views = rootLayout.Children;
foreach (View view in views)
{
if (view != null && view.IsFocused)
{
System.Diagnostics.Debug.WriteLine("view focused is : " + view);
}
}
Note:
rootLayout is the parent view of current page.

Xamarin: Set multiple viewmodels by reference from code behind

I need to set two ViewModels from the code behind in the xaml code. Or if there is better way doing would be great to.
When I do it like this way the application crashes. When I set ProductDetailViewModel in the code behind (BindingContext = ViewModel) everything works fine.
update
It's not an good idea to pass viewModels as parameters.
I have now one class "ViewModelLocator" which contains all the ViewModels as static properties. Use Google for more info. This way things are way easier.
example
ViewModelLocator
public static class ViewModelLocator
{
public static AddProductViewModel AddProductViewModel { get; set; } = new AddProductViewModel(App.ProductDataStore, App.NavigationService);
}
end update
update 2
As #Waescher stated, it's better to use FreshMvvm. The static approach is simple and fast but not good for slow devices or larger apps. Thanks.
end update 2
**Xamarin.Forms.Xaml.XamlParseException:** 'Position 9:10. Can not find the object referenced by `ProductDetailViewModel`'
Since I can't set the ViewModels directly in the xaml I need to do it by reference from code behind.
See < *** First ViewModel *** > and < *** Second ViewModel *** > in the xaml code.
<?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:controls="clr-namespace:BoerPlaza.Controls"
xmlns:flv="clr-namespace:DLToolkit.Forms.Controls;assembly=DLToolkit.Forms.Controls.FlowListView"
xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
x:Class="BoerPlaza.Views.Product.ProductCustomerPictures">
<ContentPage.BindingContext>
<x:Reference Name="ProductDetailViewModel" /><!-- *** First ViewModel ***!-->
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout>
<!-- Total image count -->
<Label Text="{Binding Product.UserImages.Total}"
Style="{StaticResource H2}" />
<!-- Title -->
<Label Text="{Binding Product.Title}"
Style="{StaticResource H1}" />
<!-- reviews -->
<StackLayout Orientation="Horizontal">
<controls:StarDisplayTemplateView x:Name="customRattingBar"
SelectedStarValue="{Binding Product.RatingTotal}" />
<Label Text="{Binding Product.RatingAmount, StringFormat='{0} reviews | '}" />
<Label Text="Schrijf een review" />
</StackLayout>
<Label Text="{Binding Product.Title, StringFormat='Heb je een productfoto van {0} die je wilt delen? '}" />
<Button Text="Foto's toevoegen"
Command="{Binding SelectImagesCommand}"
BackgroundColor="{StaticResource neutral-color}"
BorderColor="{StaticResource alt-color}"
BorderWidth="1"
TextColor="{StaticResource primary-color}"
HorizontalOptions="Start"
HeightRequest="40"
FontSize="12" />
<!-- hr -->
<BoxView Style="{StaticResource separator}" />
<flv:FlowListView FlowColumnCount="3"
x:Name="listItems"
FlowItemsSource="{Binding Media}"
SeparatorVisibility="None"
HasUnevenRows="false"
RowHeight="100"
HeightRequest="0">
<flv:FlowListView.BindingContext>
<x:Reference Name="MultiMediaPickerViewModel" /> <!-- *** Second ViewModel ***!-->
</flv:FlowListView.BindingContext>
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<Grid>
<ffimageloading:CachedImage DownsampleToViewSize="true"
HeightRequest="100"
Source="{Binding PreviewPath}"
Aspect="AspectFill"
HorizontalOptions="FillAndExpand">
</ffimageloading:CachedImage>
<Image Source="play"
IsVisible="false"
HorizontalOptions="End"
VerticalOptions="End">
<Image.Triggers>
<DataTrigger TargetType="Image"
Binding="{Binding Type}"
Value="Video">
<Setter Property="IsVisible"
Value="True" />
</DataTrigger>
</Image.Triggers>
</Image>
</Grid>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Code behind:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ProductCustomerPictures : ContentPage
{
public ProductDetailViewModel ProductDetailViewModel
{
get { return _productDetailViewModel; }
set { _productDetailViewModel = value; }
}
public MultiMediaPickerViewModel MultiMediaPickerViewModel
{
get { return _multiMediaPickerViewModel; }
set { _multiMediaPickerViewModel = value; }
}
private ProductDetailViewModel _productDetailViewModel;
private MultiMediaPickerViewModel _multiMediaPickerViewModel;
public ProductCustomerPictures(ProductDetailViewModel viewModel)
{
InitializeComponent();
ProductDetailViewModel = viewModel;
MultiMediaPickerViewModel = new MultiMediaPickerViewModel(MultiMediaPickerServiceStaticVariableHolder.MultiMediaPickerService);
}
}
If I understood this correctly and if you want to keep the pattern to pass in the view model as constructor argument ...
public ProductCustomerPictures(ProductDetailViewModel viewModel)
{
InitializeComponent();
ProductDetailViewModel = viewModel;
MultiMediaPickerViewModel = new MultiMediaPickerViewModel(MultiMediaPickerServiceStaticVariableHolder.MultiMediaPickerService);
}
... then you can remove this completely ...
<ContentPage.BindingContext>
...
</ContentPage.BindingContext>
... and this property ...
public ProductDetailViewModel ProductDetailViewModel
{
get { return _productDetailViewModel; }
set { _productDetailViewModel = value; }
}
Instead, just set the BindingContext directly in the constructor.
public ProductCustomerPictures(ProductDetailViewModel viewModel)
{
InitializeComponent();
BindingContext = viewModel; // <-- here
MultiMediaPickerViewModel = new MultiMediaPickerViewModel(MultiMediaPickerServiceStaticVariableHolder.MultiMediaPickerService);
}
Now, each and every control in the XAML is binding to the ProductDetailViewModel.
But you still have the FlowListView which should bind to the MultiMediaPickerViewModel. Instead of setting its binding context directly in XAML, it is common to use the binding with a reference, but first you have to give the whole page a name with which we can refer in the binding:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
...
...
x:Name="thisPage" <--- here
x:Class="BoerPlaza.Views.Product.ProductCustomerPictures">
Now, you can use the name as reference in the binding expression:
<flv:FlowListView FlowColumnCount="3"
x:Name="listItems"
FlowItemsSource="{Binding Source={x:Reference thisPage}, Path=MultiMediaPickerViewModel.Media}"
SeparatorVisibility="None"
HasUnevenRows="false"
RowHeight="100"
HeightRequest="0">
"{Binding Source={x:Reference thisPage}, Path=MultiMediaPickerViewModel.Media}" uses the page itself (by name thisPage) and binds to the property Media of the property MultiMediaPickerViewModel of the page.
With that, you can safely remove this code as well:
<flv:FlowListView.BindingContext>
...
</flv:FlowListView.BindingContext>
By the way, you can condense the properties in the code behind:
public MultiMediaPickerViewModel MultiMediaPickerViewModel { get; private set; }
public ProductCustomerPictures(ProductDetailViewModel viewModel)
{
InitializeComponent();
BindingContext = viewModel;
MultiMediaPickerViewModel = new MultiMediaPickerViewModel(MultiMediaPickerServiceStaticVariableHolder.MultiMediaPickerService);
}

Xamarin Forms, Dynamic ScrollView in XAML

I'm wanting to create a GUI that has a similar to what the following code generates, a scroll of frames.
However I want to be able to have a scroll of dynamic content frames, ideally in XAML and populated with an Item source. I don't think this is possible without creating a custom view based on itemsview from what I can see. ListView and CollectionView don't quite do what I want.
I think I need to use the preview CarouselView, I was wondering if there is a way of doing what I'm after without.
<?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="FlexTest.MainPage">
<ContentPage.Resources>
<Style TargetType="Frame">
<Setter Property="WidthRequest" Value="300"/>
<Setter Property="HeightRequest" Value="500"/>
<Setter Property="Margin" Value="10"/>
<Setter Property="CornerRadius" Value="20"/>
</Style>
</ContentPage.Resources>
<ScrollView Orientation="Both">
<FlexLayout>
<Frame BackgroundColor="Yellow">
<FlexLayout Direction="Column">
<Label Text="Panel 1"/>
<Label Text="A Panel"/>
<Button Text="Click Me"/>
</FlexLayout>
</Frame>
<Frame BackgroundColor="OrangeRed">
<FlexLayout Direction="Column">
<Label Text="Panel 2"/>
<Label Text="Another Panel"/>
<Button Text="Click Me"/>
</FlexLayout>
</Frame>
<Frame BackgroundColor="ForestGreen">
<FlexLayout Direction="Column">
<Label Text="Panel 3"/>
<Label Text="A Third Panel"/>
<Button Text="Click Me"/>
</FlexLayout>
</Frame>
</FlexLayout>
</ScrollView>
</ContentPage>
Thanks
Andy.
Do you want to implement a scrollable view and each child contains multiple content that can be scrolled horizontally?
For this feature, try to display the CarouselView in a ListView.
Check the code:
<ListView ...>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<CarouselView>
<CarouselView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Tutorial about CarouselView:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/carouselview/introduction
Preface: I hope I understood your request correctly :)
If by dynamic content you mean having a dynamic ItemTemplate then you can try doing following:
Step One:
Define an ItemTemplateSelector, you can give it w.e name you want. In this class we will define what sort of templates we have, let us say we have the three which you defined: Yellow, OrangeRed, ForestGreen
public class FrameTemplateSelector : DataTemplateSelector {
public DataTemplate YellowFrameTemplate {get; set;}
public DataTemplate OrangeRedFrameTemplate {get; set;}
public DataTemplate ForestGreenFrameTemplate {get; set;}
public FrameTemplateSelector() {
this.YellowFrameTemplate = new DataTemplate(typeof (YellowFrame));
this.OrangeRedFrameTemplate = new DataTemplate(typeof (OrangeRedFrame));
this.ForestGreenFrameTemplate = new DataTemplate(typeof (ForestGreenFrame));
}
//This part is important, this is how we know which template to select.
protected override DataTemplate OnSelectTemplate(object item, BindableObject container) {
var model = item as YourViewModel;
switch(model.FrameColor) {
case FrameColorEnum .Yellow:
return YellowFrameTemplate;
case FrameColorEnum .OrangeRed:
return OrangeRedFrameTemplate;
case FrameColorEnum .ForestGreen:
return ForestGreenFrameTemplate;
default:
//or w.e other template you want.
return YellowFrameTemplate;
}
}
Step Two:
Now that we have defined our Template Selector let us go ahead and define our templates, in this case our Yellow, OrangeRed, and ForestGreen frames respectively. I will simply show how to make one of them since the others will follow the same paradigm excluding, with of course the color changing. Let's do the YellowFrame
In the XAML you will have:
YellowFrame.xaml:
<StackLayout 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="YourNameSpaceGoesHere.YellowFrame">
<Frame BackgroundColor="Yellow">
<FlexLayout Direction="Column">
<Label Text="Panel 1"/>
<Label Text="A Panel"/>
<Button Text="Click Me"/>
</FlexLayout>
</Frame>
</StackLayout>
In the code behind:
YellowFrame.xaml.cs:
public partial class YellowFrame : StackLayout {
public YellowFrame() {
InitializeComponent();
}
}
Step Three
Now we need to create our ViewModel that we will use for our ItemSource that we will apply to FlexLayout, per the documentation for Bindable Layouts, any layout that "dervies from Layout" has the ability to have a Bindable Layout, FlexLayout is one of them.
So let us make the ViewModel, I will also create an Enum for the Color frame we want to render as I showed in the switch statement in step one, however, you can choose what ever means of deciding how to tell which template to load; this is just one possible example.
BaseViewModel.cs:
public abstract class BaseViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = ""){
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public virtual void CleanUp(){
}
}
ParentViewModel.cs:
public class ParentViewModel: BaseViewModel {
private ObservableCollection<YourViewModel> myViewModels {get; set;}
public ObservableCollection<YourViewModel> MyViewModels {
get { return myViewModels;}
set {
myViewModels = value;
OnPropertyChanged("MyViewModels");
}
}
public ParentViewModel() {
LoadData();
}
private void LoadData() {
//Let us populate our data here.
myViewModels = new ObservableCollection<YourViewModel>();
myViewModels.Add(new YourViewModel {FrameColor = FrameColorEnum .Yellow});
myViewModels.Add(new YourViewModel {FrameColor = FrameColorEnum .OrangeRed});
myViewModels.Add(new YourViewModel {FrameColor = FrameColorEnum .ForestGreen});
MyViewModels = myViewModels;
}
}
YourViewModel.cs:
public class YourViewModel : BaseViewModel {
public FrameColorEnum FrameColor {get; set;}
}
FrameColorEnum.cs:
public enum FrameColorEnum {
Yellow,
OrangeRed,
ForestGreen
}
We're almost there, so what we have done so far is we defined our view models that we will use on that page, the final step is to update our overall XAML where we will call our Template Selector. I will only update the snippets needed.
<ContentPage
...
**xmlns:views="your namespace where it was defined here,
normally you can just type the name of the Selector then have VS add the proper
namespace and everything"**
<ContentPage.Resources>
<!--New stuff below-->
<ResourceDictionary>
<views:FrameTemplateSelector x:Key="FrameTemplateSelector"/>
</ResourceDictionary>
</ContentPage.Resources>
<ScrollView Orientation="Both">
<FlexLayout BindableLayout.ItemsSource="{Binding MyViewModels, Mode=TwoWay}"
BindableLayout.ItemTemplateSelector ="{StaticResource FrameTemplateSelector}"/>
</ScrollView>
Live Picture:

How to Bind Static Class property to UI component in XAML / Xamarin

In Xamarin application, I am not able to Bind the static property of the C# user defined static Class property (Colors.BackgroundColor) to XAML. I need to set the background of the color of grid by static value defined in static class.
But I am getting the error
Type UserInterfaceDefinitions not found in xmlns
on this XAML
BackgroundColor = "{Binding Source = {x:Static MyNamespace.Mobile:UserInterfaceDefinitions.Colors} }"
Static Class code
namespace MyNamespace.Mobile
{
public static class UserInterfaceDefinitions
{
public static class Colors
{
public static string BackgroundColor = "#DCECE";
}
}
}
XAML Code
<?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:buttons="clr-namespace:MyNamespace.Mobile.UI.Buttons"
xmlns:Status="clr-namespace:MyNamespace.Mobile.UI.StatusDetails"
x:Class="MyNamespace.Mobile.UI.TestAndDemoSelection">
<ContentPage.Content Margin="0,0,0,0" BackgroundColor="White">
<Grid x:Name="ChildGrid" Grid.Row="1" Grid.Column="0" ColumnSpacing="10" BackgroundColor="White" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<!-- I am getting the error as Type UserInterfaceDefinitions not found in xmlns-->
<BoxView Grid.Column="0" BackgroundColor = "{Binding Source = {x:Static MyNamespace.Mobile:UserInterfaceDefinitions.Colors} }" />
</Grid>
</ContentPage.Content>
</ContentPage>
Code Behind .cs
using MyNamespace.Mobile.UI.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace MyNamespace.Mobile.UI
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TestAndDemoSelection : ContentPage
{
public TestAndDemoSelection()
{
InitializeComponent();
}
}
}
How to bind the static class property to XAML ?
I have got the resolutions. It was because of Nested Static class was not accessible inside the XAML the correct code as below.
user defined static class:
namespace MyNamespace.Mobile
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public static class UserInterfaceDefinitions
{
public static string BackgroundColor { get; } = "#DCECEC";
}
}
XAML file:
<?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:local="clr-namespace:MyNamespace.Mobile"
x:Class="MyNamespace.Mobile.UI.TestAndDemoSelection">
<ContentPage.Content Margin="0,0,0,0" BackgroundColor="White">
<Grid x:Name="ChildGrid" Grid.Row="1" Grid.Column="0" ColumnSpacing="10" BackgroundColor="White" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<BoxView Grid.Column="0" BackgroundColor = "{Binding Source = {x:Static local:UserInterfaceDefinitions.BackgroundColor}}" />
</Grid>
</ContentPage.Content>
</ContentPage>
In order to bind on a Static Property:
1) Declare the namespace to import using xmlns
2) Use the xmlns accordingly in Source
=>
<?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:buttons="clr-namespace:MyNamespace.Mobile.UI.Buttons"
xmlns:Status="clr-namespace:MyNamespace.Mobile.UI.StatusDetails"
xmnlns:local="clr-namespace:MyNamespace.Mobile"
x:Class="MyNamespace.Mobile.UI.TestAndDemoSelection">
<ContentPage.Content Margin="0,0,0,0" BackgroundColor="White">
<Grid x:Name="ChildGrid" Grid.Row="1" Grid.Column="0" ColumnSpacing="10" BackgroundColor="White" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<BoxView Grid.Column="0" BackgroundColor = "{x:Static local:UserInterfaceDefinitions.Colors.BackgroundColor}" />
</Grid>
</ContentPage.Content>
</ContentPage>
Moreover, BackgroundColor should be a property in order to be accessible:
public static string BackgroundColor {get;} = "#DCECE";
XAML works very poorly with nested classes.
Yes, and in general, a public nested class is often a very bad technique.
Example:
namespace MyNamespace.Mobile
{
public static class Colors
{
public static string BackgroundColor { get; } = "Red";
}
}
XAML:
<StackPanel xmlns:Circassia.Mobile="clr-namespace:MyNamespace.Mobile"
Background ="{Binding Source={x:Static Circassia.Mobile:Colors.BackgroundColor}}"/>
Second example:
namespace MyNamespace.Mobile
{
public static class UserInterfaceDefinitions
{
public static ColorsClass Colors{ get; } = new ColorsClass();
public class ColorsClass
{
private static readonly string s_BackgroundColor = "Red";
public static string BackgroundColor { get; } = s_BackgroundColor;
}
}
}
XAML:
<StackPanel xmlns:Circassia.Mobile="clr-namespace:MyNamespace.Mobile"
Background ="{Binding BackgroundColor, Source={x:Static Circassia.Mobile:UserInterfaceDefinitions.Colors}}"/>

Xamarin Forms - binding to a ControlTemplate

I am having trouble getting bindings defined in a ControlTemplate to work against my model.
Notice in the below ControlTemplate, I am using a TemplateBinding to bind to a property called Count (olive label). I am using Parent.Count as prescribed by this article, but neither values of Parent.Count nor Count are working.
The following page uses the ControlTemplate. Just to prove my ViewModel works I have a gray Label bound to the Count property as well.
Notice the resulting screen. The gray label is showing the Count property. The olive label from the ControlTemplate is not showing anything.
How can I make the Label in the ControlTemplate show the Count property from the ViewModel?
VIEW MODEL
namespace SimpleApp
{
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
_count = 10;
Uptick = new Command(() => { Count++; });
}
private int _count;
public int Count
{
get { return _count; }
set
{
_count = value;
OnPropertyChanged("Count");
}
}
public ICommand Uptick { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
XAML
<?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:local="clr-namespace:SimpleApp"
x:Class="SimpleApp.MainPage"
ControlTemplate="{StaticResource ParentPage}">
<StackLayout>
<Button Command="{Binding Uptick}" Text="Increment Count" />
<Label Text="{Binding Count}" BackgroundColor="Gray" />
</StackLayout>
</ContentPage>
CODE BEHIND
Notice the BindingContext is set to MainViewModel here. I need to use my own ViewModel and not the code behind.
namespace SimpleApp
{
public partial class MainPage : ContentPage
{
public MainPage()
{
BindingContext = new MainViewModel();
InitializeComponent();
}
}
}
CONTROL TEMPLATE
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SimpleApp.App">
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="ParentPage">
<StackLayout>
<Label Text="{TemplateBinding Parent.Count}" BackgroundColor="Olive" />
<ContentPresenter />
</StackLayout>
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
On your ControlTemplate please use the following code:
<Label Text="{TemplateBinding BindingContext.Count}" BackgroundColor="Olive" />
It seems that BindingContext is not being automatically applied to your ContentPage child, maybe it could be a bug in Xamarin.