在 Xamarin 的 ViewModel 中绑定来自 Bindablelayout.ItemTemplate 的数据

Posted

技术标签:

【中文标题】在 Xamarin 的 ViewModel 中绑定来自 Bindablelayout.ItemTemplate 的数据【英文标题】:Bind Data from Bindablelayout.ItemTemplate in ViewModel in Xamarin 【发布时间】:2021-08-02 15:34:58 【问题描述】:

我在Dynamically adding Entry Controls 中遇到了一个问题,Wendy Zang - MSFT 帮助并解决了它。

从API获取条目列表的代码写在.xml.cs页面中,在.xml页面中,StackLayout的Bindablelayout.ItemTemplate用于设置条目模板

它运行良好,但提交表单的代码写在ViewModel

当我将.xml.cs 页面的代码粘贴到ViewModel 时,我无法获取条目,并且当代码在xml.cs 中时,我必须在ViewModel 中设置this.BindingContext = this; 代码没有执行。

.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;

XAML 和 ViewModel 中的按钮

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

更新

从服务器获取动态字段的代码。

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();

【问题讨论】:

您的 xaml 文件中有 &lt;ContentPage.Content&gt; 吗?如果是这样,应该是this.Content.BindingContent = this; @Shaw 感谢您的回复,我使用了这个但仍然无法在ViewModel 中提交表单(我从.xml 页面和ViewModel 发布了按钮代码示例).. 如果有在xml.cs中不是this.Content.BindingContent = this;,那么它是可点击的,否则它不是 如果我在ViewModel 中粘贴xml.cs 代码(从api 获取条目),则无法查看条目.. 去掉“x”,改成async () =&gt; 。如果列表绑定没问题,继续使用之前的绑定代码。 @Shaw 我尝试了 Wendy 的解决方案,当应用程序处于调试模式时,我刷新 .xml 页面,出现表单,否则它不会在第一次出现页面时出现.. 任何想法为什么会这样? 【参考方案1】:

如果你想用 ViewModel 做这个,你可以参考下面的代码。

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>

后面的代码:

public partial class MainPage : ContentPage


    public MainPage()
    
        InitializeComponent();

        this.BindingContext = new 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();
    

输出:

【讨论】:

嗨,我使用了静态 JSON 条目,它工作正常,但是当我从 api 获取条目时,无法在视图中获取它(虽然我可以从 api 获取条目)。 当应用程序处于调试模式时,我刷新.xml 页面,出现表单..为什么会这样?以及如何解决这个问题? 我创建了CreateCollection() 函数,包括voidasync 并且还在MainThread.BeginInvokeOnMainThreadDevice.BeginInvokeOnMainThread 中编写了api 调用/响应。但仍然没有显示页面出现时表单,但是当我刷新.xml页面时(当它处于调试模式时,与PC连接时),它出现... @Stavrogin 1. 尝试在OnAppearing 中调用CreateCollection() 方法而不是构造函数。 2.尽量用ObservableCollection&lt;Form&gt; Forms代替list OnAppearing 中调用CreateCollection() 方法没有任何区别,我使用了ObservableCollection&lt;Form&gt; Forms 但在list.data.FirstOrDefault().form.ToList(); 上它说无法转换'System.Collection.Generic.List' 到 'System.Collections.ObjectModel.ObservableCollection'【参考方案2】:

要全面了解,请查看@Wendy's 解决方案。问题是,打开页面时表单没有出现,但是当我处于调试模式并刷新 .xml 页面时,它出现了。

@Shaw 建议使用ObservableCollection&lt;&gt; 而不是List&lt;&gt;,但在list.data.FirstOrDefault().form.ToList(); 上它说无法将'System.Collection.Generic.List' 转换为'System.Collections.ObjectModel.ObservableCollection '.

我修好了..这是完整的解决方案。

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());

【讨论】:

如果form = list.data.FirstOrDefault().form.ToList(); 以前有效,您应该可以改用form = new ObservableCollection&lt;Form&gt;(list.data.FirstOrDefault().form);。但是我不太确定list.data.FirstOrDefault().form的类型

以上是关于在 Xamarin 的 ViewModel 中绑定来自 Bindablelayout.ItemTemplate 的数据的主要内容,如果未能解决你的问题,请参考以下文章

如何绑定到CarouselView(Xamarin.Forms)(MVVM)内部的ViewModel元素?

绑定到 ViewModel 在 Xamarin.Forms 中不起作用

从 ViewModel 绑定到 Xamarin.Forms.Maps.Map

Xamarin.Forms 无法通过 ViewModel 将 ObservableCollection 绑定到 CollectionList

Xamarin 形成 MVVM Stacklayout 内容绑定

Xamarin 表单绑定 - 访问父属性