Stavrogin
Stavrogin

Reputation: 143

Bind Data from Bindablelayout.ItemTemplate in ViewModel in Xamarin

I had an Issue in Dynamically adding Entry Controls, which Wendy Zang - MSFT helped and solved it.

The code to Get the list of entries from API is written in .xml.cs page, and in .xml page, the Bindablelayout.ItemTemplate of StackLayout is being used to setup the template of Entry.

It's working perfectly, but the Code to Submit the Form is written in ViewModel.

When I paste the code of .xml.cs page in ViewModel, I can't get the Entries and when the code is in xml.cs for which I have to set the this.BindingContext = this; code in the ViewModel isn't executing.

.xml

<StackLayout BindableLayout.ItemsSource="{Binding forms}">
    <BindableLayout.ItemTemplate>
        <DataTemplate>
            <Entry Name="{Binding name}" Placeholder="{Binding label}" />
        </DataTemplate>
    </BindableLayout.ItemTemplate>
</StackLayout>

xml.cs

RootObject list = JsonConvert.DeserializeObject<RootObject>(fields);

forms = new List<Form>();
forms = list.data.FirstOrDefault().Form.ToList();

this.BindingContext = this;

Button in XAML & ViewModel

<Button
x:Name="SubmitButton"
Text="Submit"
Command="{Binding FormCommand}">
public ICommand FormCommand=> new Command(async (x) => await FormButton(default, default));

UPDATE

Code to fetch the dynamic fields from server.

public async Task CreateCollection()
{
    Uri uri = new Uri(string.Format("http://example.com/entry"));

    HttpClient httpClient = new HttpClient(new NativeMessageHandler());

    HttpResponseMessage response = await httpClient.GetAsync(uri);
    string entries = await response.Content.ReadAsStringAsync();

    RootObject list = JsonConvert.DeserializeObject<RootObject>(entries);

    form = new List<Form>();
    form = list.data.FirstOrDefault().form.ToList();
}

Upvotes: 0

Views: 1350

Answers (2)

Stavrogin
Stavrogin

Reputation: 143

For complete understanding, have a look at @Wendy's solution. The problem was that, Form wasn't appearing when Page opens up, but when I was in Debug Mode, and refresh the .xml page, it appears.

@Shaw recommend to use ObservableCollection<> instead of List<>, but on list.data.FirstOrDefault().form.ToList(); it said cannot convert 'System.Collection.Generic.List<>' to 'System.Collections.ObjectModel.ObservableCollection<>'.

I fixed it.. here is the complete solution.

private ObservableCollection<Form> _forms = new ObservableCollection<Form>();
public ObservableCollection<Form> Forms
{
    get
    {
        return _forms;
    }
    set
    {
        this.RaiseAndSetIfChanged(ref _forms, value);
    }
}
var list = JsonConvert.DeserializeObject<Rootobject>(json);

foreach (var i in list.data.Where(c => c.id == ""))
{
    _forms.Add(i.form.ToList());
}

Upvotes: 0

Wendy Zang - MSFT
Wendy Zang - MSFT

Reputation: 10948

If you want to do this with ViewModel, you could refer to the code below.

Xaml:

      <StackLayout>
        <Button
    x:Name="SubmitButton"
    Text="Submit"
    Command="{Binding FormCommand}"></Button>
        <StackLayout x:Name="DynamicEntry" BindableLayout.ItemsSource="{Binding forms}">
            <BindableLayout.ItemTemplate>
                <DataTemplate>
                    <Entry Placeholder="{Binding label}" MaxLength="{Binding max_length}" />

                </DataTemplate>
            </BindableLayout.ItemTemplate>
        </StackLayout>
    </StackLayout>

Code behind:

public partial class MainPage : ContentPage
{

    public MainPage()
    {
        InitializeComponent();

        this.BindingContext = new ViewModel();
    }
}

ViewModel:

public class ViewModel
{
    public List<Form> forms { get; set; }
    public ICommand FormCommand { get; set; }
    public ViewModel()
    {
        CreateCollection();
        FormCommand = new Command(async (x) => await FormButton(default, default));
    }

    private Task FormButton(object p1, object p2)
    {
        return Task.Delay(2000);
    }

    public void CreateCollection()
    {
        var json = @"{
'success': 'true',
'data': [
{
    'form': [
        {
            'label': 'Name',
            'name': 'name',
            'type': 'text',
            'max_length': '15',
            'required': 'true'
        },
        {
            'label': 'Email',
            'name': 'email',
            'type': 'email',
            'max_length': '30',
            'required': 'true'
        }
    ]
}
]
}";
        var list = JsonConvert.DeserializeObject<Rootobject>(json);

        forms = new List<Form>();
        forms = list.data.FirstOrDefault().form.ToList();
    }
}

Output:

enter image description here

Upvotes: 2

Related Questions