Search code examples
c#xamlxamarinxamarin.formsbindableproperty

Can I combine a Xaml <Label> into a C# template that I use to create a Frame?


I have XAML code that I use to set up a frame and frame heading like this:

<Label Text="ABC" />
<t:ContentFrame>
   <Label Text="ABC" />
</t:ContentFrame>

For ContentFrame I use a C# template here:

[Xamarin.Forms.ContentProperty("Contents")]
public class ContentFrame : CustomFrame
{
    StackLayout contentStack { get; } = new StackLayout()
    {
        Spacing = 0,
        Padding = new Thickness(0),
        Orientation = StackOrientation.Vertical
    };
    public IList<View> Contents { get => contentStack.Children; }

    public ContentFrame()
    {
        Content = contentStack;
        HasShadow = false;
        SetDynamicResource(BackgroundColorProperty, "ContentFrameBackgroundColor");
        SetDynamicResource(BorderColorProperty, "ContentFrameBorderColor");
        SetDynamicResource(CornerRadiusProperty, "ContentFrameCornerRadius");
    }
}

Is there a way that I could combine the setting of the heading into the ContentFrame class so the same thing could be achieved with:

<t:ContentFrame Heading="ABC">
   <Label Text="ABC" />
</t:ContentFrame>

Solution

  • You need a Bindable property for this:

    public class ContentFrame : CustomFrame
    {
    StackLayout contentStack { get; } = new StackLayout()
        {
            Spacing = 0,
            Padding = new Thickness(0),
            Orientation = StackOrientation.Vertical
        };
        public IList<View> Contents { get => contentStack.Children; }
        public static readonly BindableProperty HeadingProperty =
                BindableProperty.Create(nameof(Heading), typeof(string),
                typeof(ContentFrame), null, propertyChanged: OnHeadingChanged);
    
        public string Heading
        {
            get => (Heading)GetValue(HeadingProperty);
            set => SetValue(HeadingProperty, value);
        }
    
    static void OnHeadingChanged(BindableObject bindable, object oldValue, object newValue) {
    //whatever you want to handle
     }
    
        public ContentFrame()
        {
            Content = contentStack;
            HasShadow = false;
            SetDynamicResource(BackgroundColorProperty, "ContentFrameBackgroundColor");
            SetDynamicResource(BorderColorProperty, "ContentFrameBorderColor");
            SetDynamicResource(CornerRadiusProperty, "ContentFrameCornerRadius");
        }
    }
    

    If you don't require InotifypropertyChanged you can remove OnHeadingChanged (also from inside BindableProperty.Create(), if require you can add the below declaration.