I'm stuck trying to reuse an control template for a independent ContentPage
as well as a ContentPage
in a CarouselPage
...
The main problem is that the CarouselPage
doesn't support the ControlTemplate
property. Therefore I'm forced to insert a ContentPage
in the DataTemplate
of the CarouselPage
. This ContentPage
then can get the ControlTemplate
assigned but I run into the problem that the BindingContext
is not the root of the ViewModel
.
I'll also try to explain the issues with code:
I've create the template as shown below.
<!-- Loader view template -->
<ControlTemplate x:Key="LoaderViewTemplate">
<AbsoluteLayout Padding="0" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<!-- Content -->
<ContentPresenter AbsoluteLayout.LayoutBounds="0, 0, 1, 1" AbsoluteLayout.LayoutFlags="All" />
<!-- Loader -->
<BoxView IsVisible="{TemplateBinding BindingContext.IsBusy}" BackgroundColor="Green" Opacity="0.5" AbsoluteLayout.LayoutBounds="0, 0, 1, 1" AbsoluteLayout.LayoutFlags="All" />
<StackLayout IsVisible="{TemplateBinding BindingContext.IsBusy}" Padding="6" BackgroundColor="Gray" Orientation="Horizontal" AbsoluteLayout.LayoutBounds="0.5, 0.5, -1, -1" AbsoluteLayout.LayoutFlags="PositionProportional">
<ActivityIndicator Color="White" IsRunning="{TemplateBinding BindingContext.IsBusy}" VerticalOptions="Center" WidthRequest="20" HeightRequest="20" />
<Label TextColor="White" Text="Loading..." VerticalOptions="Center" />
</StackLayout>
</AbsoluteLayout>
</ControlTemplate>
The template is working correctly for the ContentPage
shown below.
<ContentPage ...
ControlTemplate="{StaticResource LoaderViewTemplate}">
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
...
</StackLayout>
</ContentPage>
But it doesn't work in the CarouselPage
as shown below.
<CarouselPage ...
ItemsSource="{Binding Tournament.Rounds}">
<CarouselPage.ItemTemplate>
<DataTemplate>
<ContentPage ControlTemplate="{StaticResource LoaderViewTemplate}">
...
</ContentPage>
</DataTemplate>
</CarouselPage.ItemTemplate>
</CarouselPage>
The BindingContext
in the CarouselPage
becomes a TournamentRoundModel
from the Tournament.Rounds
collection.
Does any one has an idea on how I can reach the root of the ViewModel
within the independent ContentPage
and the CarouselPage
nested ContentPage
?
Kind regards, Jop Middelkamp
First of all if you need each ContentPage
in CarousalPage
to be able to refer to the root view-model, while providing the same to the ControlTemplate
's binding(s).
Simplest way to do that would be to extend ContentPage
to support a bindable property to hold this reference (to root view-model).
public class ExContentPage : ContentPage
{
public static readonly BindableProperty RootViewModelProperty =
BindableProperty.Create(
"RootViewModel", typeof(object), typeof(ExContentPage),
defaultValue: default(object));
public object RootViewModel
{
get { return (object)GetValue(RootViewModelProperty); }
set { SetValue(RootViewModelProperty, value); }
}
}
Then you can update your shared control-template as:
<!-- Loader view template -->
<ControlTemplate x:Key="LoaderViewTemplate">
<AbsoluteLayout Padding = "0" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<!-- Content -->
<ContentPresenter .. />
< !--Loader-- >
<BoxView IsVisible= "{TemplateBinding RootViewModel.IsBusy}" BackgroundColor= "Green" .. />
<StackLayout IsVisible= "{TemplateBinding RootViewModel.IsBusy}" .. >
<ActivityIndicator Color= "White" IsRunning= "{TemplateBinding RootViewModel.IsBusy}" />
<Label TextColor= "White" Text= "Loading..." VerticalOptions= "Center" />
</StackLayout>
</AbsoluteLayout>
</ControlTemplate>
Sample usage would look like:
<local:ExContentPage ...
xmlns:local="clr-namespace:CustomNamespace"
RootViewModel="{Binding}"
ControlTemplate="{StaticResource LoaderViewTemplate}">
<StackLayout HorizontalOptions = "Center" VerticalOptions="Center">
...
</StackLayout>
</local:ExContentPage>
and,
<CarouselPage...
x:Name="Parent"
ItemsSource="{Binding Tournament.Rounds}">
<CarouselPage.ItemTemplate>
<DataTemplate>
<local:ExContentPage
ControlTemplate = "{StaticResource LoaderViewTemplate}"
RootViewModel="{Binding BindingContext, Source={x:Reference Parent}}">
...
</ContentPage>
</DataTemplate>
</CarouselPage.ItemTemplate>
</CarouselPage>
Furthermore, if IsBusy
is the only property that you need to refer in ControlTemplate
- you can create an IsBusy
bindable property in extended content-page; instead of RootViewModel
.