xamarincontroltemplatecontentpresenterbindableproperty

Xamarin conditionally show in derived ControlTemplate ContentPresenter


Not quite finding what I am looking for. Newbie for any android / iPhone type of development, but do have WPF experience with control templates, styles and working with xaml.

Here is an example image of what I am trying to accomplish but cant quite get it to work with bindings. I have a control template that gives me the top image. A header/label at the top and 3 buttons to the right and then the "ContentPresenter". These all work on their own to the base class they are defined against. (control template simplified for post)

<ControlTemplate x:Key="MyCommonTemplate" >
    <StackLayout>
        <StackLayout Orientation="Horizontal">
            <Label Text="{TemplateBinding Title}" />
            <Button Text="x" />
            <Button Text="y" />
            <Button Text="z" />
        </StackLayout>

        <ContentPresenter/>
    </StackLayout>
</ControlTemplate>

<Style TargetType="{x:Type myApp:MyCommonControl}" x:Key="MyCommonStyle">
    <Style.Setters>
        <Setter Property="ControlTemplate" Value="{StaticResource MyCommonTemplate}" />
    </Style.Setters>
</Style>

What I am trying to accomplish

Now, the TWO images below the top sample template. Each of these are derived from the top template, but each one of them has their own inner content where the content presenter is represented. As shown in the image, the first derived control has its content to always be shown, but in the second, it has TWO parts. One to always be shown, the other conditionally shown.

This would represent the first derived control from same control template. The Content Presenter does properly reflect the inner content as the image would show

<?xml version="1.0" encoding="UTF-8"?>
<myApp:MyCommonControl
    x:Class="MyApp.MySubControl1"
    ...
    xmlns:myapp="clr-namespace:MyApp">

    <!-- This properly shows within the "ContentPresenter" as expected -->
    <StackLayout>
        <Label Text="Always show..." />
        <Label Text="for this..." />
    </StackLayout>
</myApp:MyCommonControl>

Now, the second derived control

<?xml version="1.0" encoding="UTF-8"?>
<myApp:MyCommonControl
    x:Class="MyApp.MySubControl2"
    ...
    xmlns:myapp="clr-namespace:MyApp">

    <!-- This properly shows within the "ContentPresenter" as expected -->
    <StackLayout>
        <Label Text="Different sub-panel..." />
        <Label Text="Always show..." />
    </StackLayout>

    <StackLayout IsVisible="{TemplateBinding OkToShowThis}">
        <Label Text="This secondary sub-panel..." />
        <Label Text="Based on..." />
    </StackLayout>    
</myApp:MyCommonControl>

The actual baseclass of "MyCommonControl" has a variety of

public static readonly BindableProperty…

of which one is data type bool "OkToShowThis". For the top label and common button areas, they all respectively recognized being changed from visible to hidden when appropriate, so I KNOW they work.

My problem is that of the derived control that is populated from the "ContentPresenter" of the base control template. The "OkToShowThis" of this child control is NOT being refreshed. Not sure proper binding reference in this scenario.

Appreciate any assistance.

SOLUTION APPRECIATION

Thanks to solution offered by Leo Zhu, and my interpretation works like this. The outermost xaml where the

x:Name=myCommonControl

is referring to the SPECIFIC instance of the class created. From there, I can then bind the specific INNER CONTROL to that object via

<StackLayout BindingContext="{x:Reference Name=myCommonControl}" 

Now that I have correct binding to the class instance as known by the "Name=myCommonControl", I can reference any property OF that class instance thus completing my need via

<StackLayout BindingContext="{x:Reference Name=myCommonControl}" 
    IsVisible="{Binding OkToShowThis}">

And the inner control will dynamically show/hide as expected. Thank you so much.


Solution

  • first in your MyCommonControl you could define BindableProperty OkToShowThis:

    public static readonly BindableProperty OkToShowThisProperty = BindableProperty.Create("OkToShowThis", typeof(bool), typeof(MyCommonControl), true);
    public bool OkToShowThis
        {
            get { return (bool)GetValue(OkToShowThisProperty); }
        }
    

    then in your second derived control:

    <?xml version="1.0" encoding="UTF-8"?>
    <myApp:MyCommonControl
        x:Class="MyApp.MySubControl2"
        ...
        xmlns:myapp="clr-namespace:MyApp"
        OkToShowThis ="False"   
        x:Name="myCommonControl"
        >
    
       <!-- This properly shows within the "ContentPresenter" as expected -->
       <StackLayout>
          <Label Text="Different sub-panel..." />
          <Label Text="Always show..." />        
          <StackLayout BindingContext="{x:Reference Name=myCommonControl}"  IsVisible="{Binding OkToShowThis}">
             <Label Text="This secondary sub-panel..." />
             <Label Text="Based on..." />
          </StackLayout> 
       </StackLayout>
    

    is this what you want ?