我正在尝试使用需要绑定到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>
答案 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;
}