Reputation: 2985
Is it possible to have multiple ContentPresenters in a ControlTemplate?
I created a CustomControl with two BindableProperties of type View: ReadonlyContent
and WritableContent
.
The ControlTemplate Wraps two ContentPresenters where the Content is bound to either ReadonlyContent
or WritableContent
.
Misteriously it only shows the content of one ContentPresenter in that case always ReadonlyContent
uneffected by order of ContentPresenters or whatever.
So the question again: Is it possible to have two or more ContentPresenters in a ControlTemplate?
The ControlTemplate looks like this:
<ContentView.ControlTemplate>
<ControlTemplate>
<Grid HorizontalOptions="Fill" VerticalOptions="Fill" RowSpacing="0" Margin="0" Padding="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="2"
ImageSource="{TemplateBinding IsReadonly, Converter={StaticResource BooleanToImageSourceConverter}}"
BackgroundColor="Transparent"
WidthRequest="40"
HeightRequest="25"
Padding="0"
Clicked="OnToggleIsReadonly"
x:Name="btnToggleEditMode"
Margin="0" />
<StackLayout Grid.Column="1" Orientation="Vertical">
<ContentPresenter Content="{TemplateBinding ReadonlyContent, Mode=OneWay}" />
<ContentPresenter Content="{TemplateBinding WriteableContent, Mode=OneWay}" />
</StackLayout>
</Grid>
</ControlTemplate>
</ContentView.ControlTemplate>
while the code behind of the control looks like this:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ActivatableContent : ContentView
{
public static readonly BindableProperty IsReadonlyProperty = BindableProperty.Create(
"IsReadonly",
typeof(bool),
typeof(ActivatableContent),
true,
BindingMode.TwoWay,
propertyChanged: OnIsReadonlyChanged);
public static readonly BindableProperty ReadonlyContentProperty = BindableProperty.Create(nameof(ReadonlyContent), typeof(View), typeof(ActivatableContent), propertyChanged: OnReadonlyContentChanged);
public static readonly BindableProperty WritableContentProperty = BindableProperty.Create(nameof(WritableContent), typeof(View), typeof(ActivatableContent), propertyChanged: OnWritableContentChanged);
public bool IsReadonly
{
get { return (bool)GetValue(IsReadonlyProperty); }
set
{
SetValue(IsReadonlyProperty, value);
}
}
public View ReadonlyContent
{
get { return (View)GetValue(ReadonlyContentProperty); }
set { SetValue(ReadonlyContentProperty, value); }
}
public View WritableContent
{
get { return (View)GetValue(WritableContentProperty); }
set { SetValue(WritableContentProperty, value); }
}
public ActivatableContent()
{
InitializeComponent();
}
private static void OnIsReadonlyChanged(BindableObject bindable, object oldvalue, object newvalue)
{
((ActivatableContent)bindable).IsReadonly = (bool)newvalue;
}
private static void OnReadonlyContentChanged(BindableObject bindable, object oldvalue, object newvalue)
{
var readonlyContent = (View)newvalue;
((ActivatableContent)bindable).ReadonlyContent = readonlyContent;
SetInheritedBindingContext(readonlyContent, bindable.BindingContext);
}
private static void OnWritableContentChanged(BindableObject bindable, object oldvalue, object newvalue)
{
var writableContent = (View)newvalue;
((ActivatableContent)bindable).WritableContent = writableContent;
SetInheritedBindingContext(writableContent, bindable.BindingContext);
}
private void OnToggleIsReadonly(object sender, EventArgs e)
{
IsReadonly = !IsReadonly;
}
/// <summary>Method that is called when the binding context changes.</summary>
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
var controlTemplate = ControlTemplate;
if (ReadonlyContent != null && controlTemplate != null)
{
SetInheritedBindingContext(ReadonlyContent, BindingContext);
}
if (WritableContent != null && controlTemplate != null)
{
SetInheritedBindingContext(WritableContent, BindingContext);
}
}
}
Upvotes: 5
Views: 1680
Reputation: 10948
ContentPresenter always points to the control's content by default you can't define two different content.
However, we could do this in custom control. You could download folder of ContentPresenterDemo from GitHub for reference. https://github.com/WendyZang/Test.git
First, define two different bindable properties in your custom control
public static readonly BindableProperty ReadonlyContentProperty = BindableProperty.Create(nameof(ReadonlyContent), typeof(View), typeof(CustomContentView));
public View ReadonlyContent
{
get { return (View)GetValue(ReadonlyContentProperty); }
set { SetValue(ReadonlyContentProperty, value); }
}
public static readonly BindableProperty WritableContentProperty = BindableProperty.Create(nameof(WritableContent), typeof(View), typeof(CustomContentView));
public View WritableContent
{
get { return (View)GetValue(WritableContentProperty); }
set { SetValue(WritableContentProperty, value); }
}
Please note, do not forget to change ContentPage to ContentView in xaml.
And then define two views with template in Application.Resources
.
<Application.Resources>
<ControlTemplate x:Key="MyTemplate">
<StackLayout>
<ContentView Content="{TemplateBinding WritableContent}"/>
<ContentView Content="{TemplateBinding ReadonlyContent}"/>
</StackLayout>
</ControlTemplate>
<ContentView x:Key="MyContentView">
<StackLayout>
<Label Text="MyContentView" BackgroundColor="Red"></Label>
<!--code here...-->
</StackLayout>
</ContentView>
<ContentView x:Key="MyContentView2">
<StackLayout>
<Label Text="MyContentView2" BackgroundColor="Green"></Label>
<!--code here...-->
</StackLayout>
</ContentView>
And then use it in page.
<StackLayout>
<local:CustomContentView ReadonlyContent="{StaticResource MyContentView}"
WritableContent="{StaticResource MyContentView2}"
ControlTemplate="{StaticResource MyTemplate}" />
</StackLayout>
Or you could use Picker to do Multiple ContentPresenters.
Define a Picker with multiple ContentPresenters.
<Picker x:Name="picker" Title="Select a template" SelectedIndexChanged="SelectedIndexChanged">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Template 1</x:String>
<x:String>Template 2</x:String>
<x:String>Template 3</x:String>
<x:String>Template 4</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
You could download from the GitHub. https://github.com/CrossGeeks/ControlTemplateSample
Upvotes: 3