1
votes

Coming from my original post, I was trying to create a custom control and build a control template for it much like in WPF, but failed on triggers. I was provided a link that indicated that Control Templates are not allowed on all controls, but only certain ones via another S/O link provided by @Raimo on my other question.

So now on to part 2. I have changed the control from an "Entry" type to a "ContentView" type so a control template can be applied. So that was the only thing changed

namespace MyAndroidApp
{
    public class MyTextboxEntry : ContentView
    {
        public MyTextboxEntry()
        {}

        public static readonly BindableProperty IsRequiredProperty 
            = BindableProperty.Create(nameof(IsRequired), typeof(bool),
                typeof(MyTextboxEntry), false, BindingMode.TwoWay);
        public bool IsRequired
        {
            get { return (bool)GetValue(IsRequiredProperty); }
            set { SetValue(IsRequiredProperty, value); }
        }
    }
}

Namespace references..

xmlns:myCtrls="clr-namespace:MyAndroidApp"

Now, on to the control template. I am actually defining multiple parts in the control but have abbreviated here for simple context.

<ControlTemplate x:Key="CT_MyTextboxEntry" >
    <!--having a grid as an outer wrapper for multiple internal controls...-->
    <Grid HorizontalOptions="StartAndExpand" x:Name="UpdateThisGridControl" >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150*" />
            <ColumnDefinition Width="50" />
            <ColumnDefinition Width="16" />
        </Grid.ColumnDefinitions>


        <Entry Text="Sample" Grid.Column="0"  />
        <Label Text="junk" Grid.Column="1" />
        <Image Source="Sample.jpg" Grid.Column="2" />

    <Grid.Triggers>
        <Trigger TargetType="myCtrls:MyTextboxEntry" Property="IsRequired" Value="True">
            <Setter Property="BackgroundColor" Value="Red"/>
        </Trigger>
    </Grid.Triggers>

    </Grid>
</ControlTemplate>

And the final instance of the control in the page to be displayed via

<myCtrls:MyTextboxEntry ControlTemplate="{StaticResource CT_MyTextboxEntry}" />

So, my failure is within the Grid.Triggers section. The intent here is to use the bindable property of the new entry control (based on ContentView) with proper BindableProperty declaration for "IsRequired", but to set the background color of the GRID.

In WPF, you can say use the trigger from this thing here, but update this other control within the control template as referenced by an "x:Name" reference which I have in-place as "UpdateThisGridControl".

If I disable the [Grid.Triggers] part, the control and template show as expected. As soon as I enable the trigger, it fails with

"bindable not an instance of AssociatedType

But, if you take into consideration that an entry ContentView has a background color property and so too does the Grid control, why is it choking when trying to set via trigger.

Greatly appreciate assistance with this type of binding for the property from the custom control to update a property within the specific control template. Thanks

1

1 Answers

2
votes

If you used Grid.Triggers, You should set the TargetType="Grid" in the Trigger Tab like following code.

         <ControlTemplate x:Key="CT_MyTextboxEntry" >
            <!--having a grid as an outer wrapper for multiple internal controls...-->
            <Grid HorizontalOptions="StartAndExpand" x:Name="UpdateThisGridControl" IsEnabled="True" >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150*" />
                <ColumnDefinition Width="50" />
                <ColumnDefinition Width="16" />
            </Grid.ColumnDefinitions>


            <Entry Text="Sample" Grid.Column="0"  />
            <Label Text="junk" Grid.Column="1" />
            <Image Source="Sample.jpg" Grid.Column="2" />

 <!--For Testing, I set the value of `Property` is `IsEnabled`, it worked as normal  -->
                <Grid.Triggers>
                    <Trigger TargetType="Grid" Property="IsEnabled" Value="True">
                        <Setter Property="BackgroundColor" Value="Red"/>
                    </Trigger>
                </Grid.Triggers>


            </Grid>
        </ControlTemplate>

But you want to set the TargetType="myCtrls:MyTextboxEntry" for Trigger,

you can try to use Style to achieve it for myCtrls:MyTextboxEntry.

    <ContentPage.Resources>

        <ResourceDictionary>
           <Style TargetType="myCtrls:MyTextboxEntry">
                <Style.Triggers>
                    <Trigger TargetType="myCtrls:MyTextboxEntry"
                         Property="IsRequired" Value="True">
                        <Setter Property="BackgroundColor" Value="Red" />

                        <!-- multiple Setters elements are allowed -->
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ResourceDictionary>

        <ControlTemplate x:Key="CT_MyTextboxEntry" >
            <!--having a grid as an outer wrapper for multiple internal controls...-->
            <Grid HorizontalOptions="StartAndExpand" x:Name="UpdateThisGridControl"  >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150*" />
                <ColumnDefinition Width="50" />
                <ColumnDefinition Width="16" />
            </Grid.ColumnDefinitions>


            <Entry Text="Sample" Grid.Column="0"  />
            <Label Text="junk" Grid.Column="1" />
            <Image Source="Sample.jpg" Grid.Column="2" />


                <!--<Grid.Triggers>
                    <Trigger TargetType="Grid" Property="IsEnabled" Value="True">
                        <Setter Property="BackgroundColor" Value="Red"/>
                    </Trigger>
                </Grid.Triggers>-->


            </Grid>
        </ControlTemplate>
    </ContentPage.Resources>
    <StackLayout>

        <myCtrls:MyTextboxEntry ControlTemplate="{StaticResource CT_MyTextboxEntry}" IsRequired="True" />

    </StackLayout>

Here is running screenshot.

enter image description here