为什么我的 Xamarin.Forms ListView 数据绑定不会反映在其他视图中?



我的MainPage.xaml页面绑定到ClientsViewModel.cs. 此页具有绑定到ObservableCollection属性的ListView

NewClient.xaml页面和输入字段也绑定到ClientsViewModel.cs

当我使用NewClient.xaml窗体保存新客户端并导航回MainPage.xaml(使用导航后退箭头)时,我希望在MainPage.xamlListView中看到新添加的客户端,但我没有看到此更改。

为什么MainPage.xaml中的ListView没有显示新更新的记录?我哪里出错了?

值得一提的是,我的实际项目将使用SQLite,因此ObseravbleCollection最终将直接从SQLite数据库中获取记录,因此任何有关此的帮助或建议也将不胜感激。

请参阅下面的代码,或从我的 GitHub 存储库克隆 https://github.com/minlopalis/XamarinForms-ListView-DataBinding.git

(模型)客户端.cs

public class Client
{
public int Id { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
}

(视图模型) 基本视图模型.cs

public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

(视图模型) 客户端视图模型.cs

public class ClientViewModel : BaseViewModel
{
private ObservableCollection<Client> clients;
public ObservableCollection<Client> Clients 
{
get { return clients; } 
set
{
clients = value;
OnPropertyChanged();
}
}
public Command SaveClientCommand { get; }
public ClientViewModel()
{
this.Clients = new ObservableCollection<Client>();
SaveClientCommand = new Command(()=> {
Client client = new Client()
{
Name = Name,
Phone = Phone
};
Clients.Add(client);
OnPropertyChanged(nameof(Clients));
});
}

private int id;
public int Id 
{
get { return id; }
set
{
id = value;
OnPropertyChanged();
}
}
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged();
}
}
private string phone;
public string Phone
{
get { return phone; }
set 
{
phone = value;
OnPropertyChanged();
}
}
}

(查看) 主页.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:viewModels="clr-namespace:DataBinding.ViewModels"
x:Class="DataBinding.MainPage">

<ContentPage.BindingContext>
<viewModels:ClientViewModel/>
</ContentPage.BindingContext>

<StackLayout>
<Label Text="Client List"></Label>
<ListView ItemsSource="{Binding Clients}">
<ListView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}"/>
<Label Text="{Binding Phone}"/>
</StackLayout>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Text="Add Client"
Clicked="AddClientButton_Clicked"/>
</StackLayout>
</ContentPage>

(查看) NewClient.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:viewModels="clr-namespace:DataBinding.ViewModels"
x:Class="DataBinding.Views.NewClient">
<ContentPage.BindingContext>
<viewModels:ClientViewModel/>
</ContentPage.BindingContext>

<ContentPage.Content>
<StackLayout>
<Label Text="Add New Client" />
<Label Text="Name"/>
<Entry Text="{Binding Name}"/>
<Label Text="Phone"/>
<Entry Text="{Binding Phone}"/>
<Button Text="Save"
Command="{Binding SaveClientCommand}"/>
<!-- Added ListView -->
<ListView ItemsSource="{Binding Clients}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}"/>
<Label Text="{Binding Phone}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>

我已经从存储库下载了您的代码,我认为它有一个很大的缺陷导致这种情况。你在两个页面上都以 XAML 格式设置BindingContext。如果您在ClientViewModel的构造函数中设置断点,您会注意到它被调用了两次:一次在应用程序启动时,一次在单击"添加客户端"时。

这意味着您正在查看此类的两个单独实例,因此您的Client位于错误的实例中。您希望确保查看的是相同的视图模型。

更重要的是,您甚至可能希望通过创建一个额外的,即:CreateClientViewModel,它只负责创建客户端并将该对象返回到ClientViewModel,然后又将其添加到集合中。

希望这有帮助!

根据您的描述,您希望在页面之间导航时传递数据,我建议您可以使用消息传递中心。

主页:

<StackLayout>
<Label Text="Client List" />
<ListView ItemsSource="{Binding Clients}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}" />
<Label Text="{Binding Phone}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Command="{Binding SaveClientCommand}" Text="Add Client" />
</StackLayout>
public partial class Page9 : ContentPage
{
private ClientViewModel _clientmodel;
public ClientViewModel clientmodel
{
get { return _clientmodel; }
set
{
_clientmodel = value;
}
}
public Page9()
{
InitializeComponent();
this.BindingContext = new ClientViewModel(this.Navigation);
}      
}
public class ClientViewModel 
{       
public ObservableCollection<Client> Clients { get; set; }   
public Command SaveClientCommand { get; }
private INavigation _navigation;
public ClientViewModel(INavigation navitation)
{
Clients = new ObservableCollection<Client>();
Clients.Add(new Client() { Name = "client1", Phone = "123" });
_navigation = navitation;
SaveClientCommand = new Command(async() => {
await _navigation.PushAsync(new NewClient());
});
MessagingCenter.Subscribe<string, string[]>("test", "Add", (sender, values) =>
{
Client client = new Client() { Name=values[0],Phone=values[1]};
Clients.Add(client);
});
} 

}

NewClient.xaml:

public partial class NewClient : ContentPage
{
public NewClient()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
string name = entry1.Text;
string phone = entry2.Text;
string[] values = { name,phone};
MessagingCenter.Send<string, string[]>("test", "Add", values);
Navigation.PopAsync();
}
}

顺便说一下,您不需要为 ObservableCollection 调用 PropertyChanged,因为 ObservableCollection 类表示一个动态数据收集,该集合在添加、删除项或刷新整个列表时提供通知。

感谢大家的帮助,我已经解决了我的问题。

我的代码有两个问题。

1. 两个视图模型实例

正如Gerald Versluis所指出的,我有两个ViewModel实例。 我通过在App.xaml页面中创建Application.Resources视图模型的实例来解决此问题。

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBinding.App"
xmlns:ClientViewModel="clr-namespace:DataBinding.ViewModels">
<Application.Resources>
<ClientViewModel:ClientViewModel x:Key="ClientViewModel" />
</Application.Resources>
</Application>

并将每个页面绑定到静态资源(如下所示)

<?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:ViewModels="clr-namespace:DataBinding.ViewModels"
x:Class="DataBinding.Views.NewClient">
<ContentPage.BindingContext>
<StaticResource Key="ClientViewModel"/>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout>
<Label Text="Add New Client" />
<Label Text="Name"/>
<Entry Text="{Binding Name}"/>
<Label Text="Phone"/>
<Entry Text="{Binding Phone}"/>
<Button Text="Save"
Command="{Binding SaveClientCommand}"/>

<!-- Added ListView -->
<ListView ItemsSource="{Binding ClientList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}"/>
<Label Text="{Binding Phone}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

</StackLayout>
</ContentPage.Content>
</ContentPage>

感谢Gerald Versluis的帮助。 在这里查看他的YouTube频道。

2. 缺少视图单元格

我的MainPage.xamlListView中缺少一个ViewCell.这是一个简单的键入疏忽,但抛出"'指定的强制转换无效'错误。非常感谢Alexander Fauland对此线程的回复,该线程帮助我解决了丢失的ViewCell问题。

最新更新