Kasper
Kasper

Reputation: 831

Property Getter on Grid in Xamarin

How do I create a property for an item that contains multiple controls?

I have a UserControl that inherits from Grid. I have an Add method to add children to it. Everything works fine if I create the UserControl in code behind and use my Add method. However I want to be able to add to it in Xaml. So I made a property called Content. The Setter works fine but I cannot figure out what to put in the Getter. Everything I have tried has failed. I am not really sure what I should be getting since it can contain multiple items. My Add method simply creates Row or Column Definitions and performs other layout functions. The Setter gets called for each item that is added in the Content (so twice in my example).

    public class MyControl : Grid
    {
    public View Content
    {
        get { return WHAT?; }
        set { Add(value); }
    }

I want to use it like this:

<controls:MyControl>
  <controls:MyControl.Content>
    <Label Text="test" />
    <Label Text="test" />
  </controls:MyControl.Content>
</controls:MyControl>

Everything I try gives the error "Property Content is null or is not IEnumerable".

Upvotes: 1

Views: 591

Answers (1)

Timo Salom&#228;ki
Timo Salom&#228;ki

Reputation: 7189

With the first code sample, you're describing a control that can only hold one child control inside. That's basically what ContentPage does. If you look at the source code of ContentPage, it has a simple bindable property Content:

public static readonly BindableProperty ContentProperty = BindableProperty.Create(nameof(Content), typeof(View), typeof(ContentPage), null, propertyChanged: TemplateUtilities.OnContentChanged);

public View Content
{
    get { return (View)GetValue(ContentProperty); }
    set { SetValue(ContentProperty, value); }
}

What you're looking for is something closer to StackLayout that can have multiple child views. In stack layout, Children is the ContentProperty (instead of Content in ContentPage) which means that when you write this:

<StackLayout>
    <Label>
    <Label>
</StackLayout>

it actually means this:

<StackLayout>
    <StackLayout.Children>
        <Label>
        <Label>
    </StackLayout.Children>
</StackLayout>

StackLayout itself doesn't contain much of the interesting code but you should take a look at how its parent class Layout< T> and its base class Layout handle things. Since Children is actually a collection, it only provides the get mechanism. Once you have the handle to the collection, you can add and remove from it without ever needing the set method.

public IList<T> Children
{
    get { return _children; }
}

In the constructor you can see how _childrenis instantiated as an ElementCollection<T>object.

To sum it up, you'll most likely be just fine with having a List of View objects like this:

public IList<View> Children
{
    get { return _children; }
}

// and the constructor
public MyControl() {
    _children = new List<View>();
}

No need for the set method after all.

Upvotes: 1

Related Questions