Xamarin Forms MVVM UWP ListView绑定不起作用

时间:2019-02-19 15:36:33

标签: mvvm xamarin.forms uwp-xaml

我正在尝试使用需要绑定到ViewModel中已填充的XML模型对象的通用列表的ListView来实现MVVM ContentPage,但是绑定失败。显示的代码调用一个API,该API确实返回XML数据的有效列表。当直接在XAML Xamarin内容页面后面的代码中进行绑定(通过在代码后面设置ItemSource)时,相同的代码可以正常工作。如前所述,仅当尝试通过分配给内容页的ViewModel传递ListView时,才会发生此问题。我已经逐步完成了ViewModel中的代码,并且成功填充了ListView,但是绑定不起作用。我在模型绑定确实适用的页面上还有其他控件,但是唯一无效的控件是ListView。代码如下所示:

ViewModel:

using RestDemo.Model;
using RestDemo.Views;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using System.ComponentModel;
using System.Windows.Input;
using System.Collections.ObjectModel;

namespace RestDemo.ViewModel
{
    
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public ViewModel ()
        {
           GetRequest();
        }

        List<XmlPizzaDetails> _objPizzaList;
        string _selectedDescription = "Descriptions: ";
        bool _progress;
        string _cusButtonText = "Hello";

        public bool Progress
        {
            get { return _progress; }
            set { _progress = value; }
        }

        public string CusButtonText
        {
            get { return _cusButtonText; }
            set { _cusButtonText = value; }
        }

        public string SelectedDescription
        {
            get { return _selectedDescription; }
            set { _selectedDescription = value; }
        }

        public List<XmlPizzaDetails> ObjPizzaList
        {
            get { return _objPizzaList; }

            set
            {
                if (_objPizzaList != value)
                {
                    _objPizzaList = value;
                    OnPropertyChanged("ObjPizzaList");
                }
            }
        }

        public string Description
        {
            get { return _selectedDescription; }
            set { _selectedDescription = value; }
        }

        public ICommand SelectedCommand => new Command(() =>
        {
            CusButtonText = "Goodby";
        });

       event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
        {
            add
            {
            }

            remove
            {
            }
        } 

        public async void GetRequest()
        {
            if (NetworkCheck.IsInternet())
            {

                Uri geturi = new Uri("http://api.androidhive.info/pizza/?format=xml"); //replace your                       xml url
                HttpClient client = new HttpClient();
                HttpResponseMessage responseGet = await client.GetAsync(geturi);
                string response = await responseGet.Content.ReadAsStringAsync();

                //Xml Parsing
                ObjPizzaList = new List<XmlPizzaDetails>();
                XDocument doc = XDocument.Parse(response);
                foreach (var item in doc.Descendants("item"))
                {
                    XmlPizzaDetails ObjPizzaItem = new XmlPizzaDetails();
                    ObjPizzaItem.ID = item.Element("id").Value.ToString();
                    ObjPizzaItem.Name = item.Element("name").Value.ToString();
                    ObjPizzaItem.Cost = item.Element("cost").Value.ToString();
                    ObjPizzaItem.Description = item.Element("description").Value.ToString();
                    ObjPizzaList.Add(ObjPizzaItem);
                }
                Progress = false;
            }
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this,
                    new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

XAML

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:xlocal="clr-namespace:RestDemo.ViewModel"
             xmlns:local="clr-namespace:RestDemo"
             xmlns:Views="clr-namespace:RestDemo.Views"
             x:Class="RestDemo.XmlParsingPageBehavior">
    <ContentPage.BindingContext>
        <xlocal:ViewModel />
    </ContentPage.BindingContext>
    <Grid>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Views:CustomButton Grid.Row="0" Grid.Column="0" Text="HOME"  />
                <Views:CustomButton Grid.Row="0" Grid.Column="1" Text="Administrative Maintence"  />
                <Views:CustomButton Grid.Row="0" Grid.Column="2" Text="User Maintence"  />
                <Views:CustomButton Grid.Row="0" Grid.Column="3" Text="About" />
            </Grid>
            <Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <Views:CustomButton Grid.Row="0" Grid.Column="0" Text="{Binding CusButtonText,                             Mode=TwoWay}">
                    <Views:CustomButton.Behaviors>
                        <local:ItemSelectedToCommandBehavior />
                    </Views:CustomButton.Behaviors>
                </Views:CustomButton>
            </Grid>
            <Frame Margin="5, 5, 5, 5" Grid.Row="2" Grid.Column="1" BackgroundColor = "Cyan">
                <ListView x:Name="PizzaListView" ItemsSource="{Binding ObjPizzaList}"  Margin="5, 0, 5,                     0" Grid.Row="2" Grid.Column="1" HorizontalOptions="FillAndExpand"                                     HasUnevenRows="True">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <Grid HorizontalOptions="FillAndExpand" Margin="0,0,0,0" Padding="20">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="Auto"/>
                                    </Grid.RowDefinitions>
                                    <Label Text="{Binding Name}" HorizontalOptions="StartAndExpand"                                             Grid.Row="0" TextColor="Blue"  FontAttributes="Bold"/>
                                    <Label Text="{Binding Cost}" HorizontalOptions="StartAndExpand"                                             Grid.Row="1" TextColor="Orange"  FontAttributes="Bold"/>
                                    <Label Text="{Binding Description}"                                                                         HorizontalOptions="StartAndExpand" Grid.Row="2"                                                       TextColor="Gray"  FontAttributes="Bold"/>
                                    <BoxView HeightRequest="2" Margin="0,10,10,0"                                                               BackgroundColor="Gray" Grid.Row="3" HorizontalOptions="Fill" />
                                </Grid>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </Frame>
        </Grid>
        <ActivityIndicator x:Name="ProgressLoader" IsVisible="{Binding Progress}" IsRunning="True"/>
    </Grid>
</ContentPage>

1 个答案:

答案 0 :(得分:0)

我正在使用它。是的,ObservableCollections是可行的方法,但是通用列表也可以。问题在于,当绑定模型时,WebService调用尚未完成,因此,当绑定列表属性时,它仍然为null。即使此时更新,ObservableCollection也将无法工作,因为它尚未被植入。解决方案是在Page的OnAppearing事件上植入ObservableCollection或List,并在此事件中将ViewModel绑定为BindingContext。我的解决方案如下:

protected override async void OnAppearing()
{
    var vm = new ViewModel.ViewModel();
    if (vm == null)
        return;

    HttpClient client = new HttpClient();
    HttpResponseMessage responseGet = await client.GetAsync(vm.Geturi);
    string response = await responseGet.Content.ReadAsStringAsync();

    //Xml Parsing
    var _objPizzaList = new ObservableCollection<XmlPizzaDetails>();
    XDocument doc = XDocument.Parse(response);

    vm.GetRequest(doc);

    this.BindingContext = vm;
}