xamarin 表单:无法绑定数据
xamarin forms : can't bind data
我正在尝试创建一个从我的 api 检索数据的应用程序,但我只是不知道为什么绑定不起作用。这是 C# 代码
public partial class PageData : ContentPage
{
TodoList tdl { get; set; }
public PageData()
{
tdl = new TodoList();
this.BindingContext = tdl;
InitializeComponent();
}
private async void ContentPage_Appearing(object sender, EventArgs e)
{
var httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
HttpClient client = new HttpClient(httpClientHandler);
var WebAPIUrl = @"http://192.168.x.xx:65xxx/api/data";
var uri = new Uri(WebAPIUrl);
var response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
string responseBody = await response.Content.ReadAsStringAsync();
var tmp = JsonConvert.DeserializeObject<List<TodoItem>>(responseBody);
tdl.todoLists = new System.Collections.ObjectModel.ObservableCollection<TodoItem>(tmp);
}
// MyListView.ItemsSource = tdl.todoLists;
}
}
当我使用我评论的最后一行时它起作用了,但感觉有点像“作弊”,因为这不是使用 MVVM 时的最佳实践。我知道有办法解决这个问题,但我只是不知道我做错了什么。谢谢。
这里是 xaml 代码:
<ContentPage.Content>
<ListView x:Name="MyListView" ItemsSource="{Binding todoLists}" RowHeight="70">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Spacing="20" Padding="5">
<StackLayout Orientation="Vertical">
<Label Text="To do: " FontAttributes="Bold" FontSize="17"></Label>
<Label Text="Is completed: " FontAttributes="Bold" FontSize="17"></Label>
</StackLayout>
<StackLayout Orientation="Vertical">
<Label Text="{Binding name}" FontSize="17"></Label>
<Label Text="{Binding isCompleted}" FontSize="17"></Label>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
这是我的 MVVM class :
using ExamenAout.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
namespace ExamenAout.MVVM
{
public class TodoList : INotifyPropertyChanged
{
private ObservableCollection<TodoItem> _todoLists { get; set; }
public ObservableCollection<TodoItem> todoLists
{
get { return this._todoLists; }
set
{
this._todoLists = value;
OnPropertyRaised("todoList");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyRaised(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
}
}
这是 TodoItem class :
using System;
using System.Collections.Generic;
using System.Text;
namespace ExamenAout.Models
{
public class TodoItem
{
public Guid userid { get; set; }
public string name { get; set; }
public bool isCompleted { get; set; }
}
}
下次可以用nameof expression来避免这个错误:) :
public ObservableCollection<TodoItem> todoLists
{
get { return this._todoLists; }
set
{
this._todoLists = value;
OnPropertyRaised(nameof(todoLists));
}
}
要扩展 Jack Hua 的答案,您还可以使用 CallerMemberNameAttribute。如文档所述:
Implementing the INotifyPropertyChanged interface when binding data. This interface allows the property of an object to notify a bound control that the property has changed, so that the control can display the updated information. Without the CallerMemberName attribute, you must specify the property name as a literal.
您可以这样使用它:
using System.Runtime.CompilerServices;
private void OnPropertyRaised([CallerMemberName]string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
这使得您正在设置的 属性 的名称会自动传递
public ObservableCollection<TodoItem> todoLists
{
get => _todoLists;
set
{
_todoLists = value;
OnPropertyRaised(); // You don't need to pass "todoLists" here
}
}
我正在尝试创建一个从我的 api 检索数据的应用程序,但我只是不知道为什么绑定不起作用。这是 C# 代码
public partial class PageData : ContentPage
{
TodoList tdl { get; set; }
public PageData()
{
tdl = new TodoList();
this.BindingContext = tdl;
InitializeComponent();
}
private async void ContentPage_Appearing(object sender, EventArgs e)
{
var httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
HttpClient client = new HttpClient(httpClientHandler);
var WebAPIUrl = @"http://192.168.x.xx:65xxx/api/data";
var uri = new Uri(WebAPIUrl);
var response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
string responseBody = await response.Content.ReadAsStringAsync();
var tmp = JsonConvert.DeserializeObject<List<TodoItem>>(responseBody);
tdl.todoLists = new System.Collections.ObjectModel.ObservableCollection<TodoItem>(tmp);
}
// MyListView.ItemsSource = tdl.todoLists;
}
}
当我使用我评论的最后一行时它起作用了,但感觉有点像“作弊”,因为这不是使用 MVVM 时的最佳实践。我知道有办法解决这个问题,但我只是不知道我做错了什么。谢谢。
这里是 xaml 代码:
<ContentPage.Content>
<ListView x:Name="MyListView" ItemsSource="{Binding todoLists}" RowHeight="70">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Spacing="20" Padding="5">
<StackLayout Orientation="Vertical">
<Label Text="To do: " FontAttributes="Bold" FontSize="17"></Label>
<Label Text="Is completed: " FontAttributes="Bold" FontSize="17"></Label>
</StackLayout>
<StackLayout Orientation="Vertical">
<Label Text="{Binding name}" FontSize="17"></Label>
<Label Text="{Binding isCompleted}" FontSize="17"></Label>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
这是我的 MVVM class :
using ExamenAout.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
namespace ExamenAout.MVVM
{
public class TodoList : INotifyPropertyChanged
{
private ObservableCollection<TodoItem> _todoLists { get; set; }
public ObservableCollection<TodoItem> todoLists
{
get { return this._todoLists; }
set
{
this._todoLists = value;
OnPropertyRaised("todoList");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyRaised(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
}
}
这是 TodoItem class :
using System;
using System.Collections.Generic;
using System.Text;
namespace ExamenAout.Models
{
public class TodoItem
{
public Guid userid { get; set; }
public string name { get; set; }
public bool isCompleted { get; set; }
}
}
下次可以用nameof expression来避免这个错误:) :
public ObservableCollection<TodoItem> todoLists
{
get { return this._todoLists; }
set
{
this._todoLists = value;
OnPropertyRaised(nameof(todoLists));
}
}
要扩展 Jack Hua 的答案,您还可以使用 CallerMemberNameAttribute。如文档所述:
Implementing the INotifyPropertyChanged interface when binding data. This interface allows the property of an object to notify a bound control that the property has changed, so that the control can display the updated information. Without the CallerMemberName attribute, you must specify the property name as a literal.
您可以这样使用它:
using System.Runtime.CompilerServices;
private void OnPropertyRaised([CallerMemberName]string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
这使得您正在设置的 属性 的名称会自动传递
public ObservableCollection<TodoItem> todoLists
{
get => _todoLists;
set
{
_todoLists = value;
OnPropertyRaised(); // You don't need to pass "todoLists" here
}
}