【发布时间】:2021-07-15 00:05:00
【问题描述】:
更新 - 问题 #1 已解决,问题 #2 仍未解决 你可以在https://www.youtube.com/watch?v=5_6KJ0QJouM观看我的问题的一个非常粗略的演示视频
我正在使用 MVVM 设计模式和 C# 构建一个带有 SQLite 数据库的 Xamarin.Forms 应用程序>
当尝试将记录从 View 保存到数据库时,更新/保存似乎没有保存到 SQLite 数据库或反映在其他 Views 中。
我知道数据库Save 方法确实有效,因为我在应用程序首次加载(在App.xaml.cs 中)时使用DeveloperData.cs 文件创建了一些虚拟数据。
我有两个问题。
(已解决)问题 1 - 数据未保存到数据库
当我从使用MerchandiserEditPageViewModel.cs ViewModel 的MerchandiserEditPage.xaml 调用Save 命令时,似乎没有保存记录。
问题 2 - 反映在其他视图中的更改
将更新的数据保存到数据库后,如何在其他视图中反映该更改?在我保存来自MerchandiserEditPage 的记录后,View 从堆栈“弹出”并且用户返回到MerchandiserProfileView。我希望更新的数据反映在堆栈上的所有其他视图中。但这似乎没有发生? (我使用硬编码数据对此进行了测试,并且出现了同样的问题,因此问题与问题 1 没有直接关系)
我的项目中有很多文件,可以从我的GitHub repository 查看/下载,但我将在这个问题中专注于以下内容。
- MerchandiserEditPage.xaml(查看)
- MerchandiserProfilePage.xaml(查看)
- MerchandiserDatabase.cs(数据库函数)x
- MerchandiserEditPageViewModel.cs x
查看我的GitHub repository 了解完整项目。
MerchandiserDatabase.cs(数据库函数)
using SQLite;
namespace MobileApp.Database
{
public class MerchandiserDatabase
{
private static SQLiteConnection database = DependencyService.Get<IDatabaseConnection>().DbConnection();
private readonly static object collisionLock = new object();
public MerchandiserDatabase()
{
database.CreateTable<Models.Merchandiser>();
}
public static void SaveMerchandiser(Models.Merchandiser merchandiser)
{
lock (collisionLock)
{
if (merchandiser.Id != 0)
{
database.Update(merchandiser);
}
else
{
database.Insert(merchandiser);
}
}
}
}
}
MerchandiserEditPageViewModel.cs (ViewModel) 已更新
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace MobileApp.ViewModels
{
public class MerchandiserEditPageViewModel : BaseViewModel
{
public string PageTitle { get; } = "Edit Merchandiser Profile";
public Command SaveCommand { get; set; }
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();
}
}
private string email;
public string Email
{
get { return email; }
set
{
email = value;
OnPropertyChanged();
}
}
public MerchandiserEditPageViewModel(Models.Merchandiser selectedMerchandiser)
{
Name = selectedMerchandiser.Name;
Phone = selectedMerchandiser.Phone;
Email = selectedMerchandiser.Email;
SaveCommand = new Command( async ()=> {
selectedMerchandiser.Name = this.Name;
selectedMerchandiser.Phone = this.Phone;
selectedMerchandiser.Email = this.Email;
Database.MerchandiserDatabase.SaveMerchandiser(selectedMerchandiser);
await Application.Current.MainPage.Navigation.PopModalAsync();
});
}
}
}
MerchandiserEditPage.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"
x:Class="MobileApp.Views.MerchandiserEditPage">
<ContentPage.Content>
<StackLayout>
<!--Page Heading-->
<StackLayout Spacing="0">
<Label Text="{Binding PageTitle}"
Style="{StaticResource PageTitle}"/>
<BoxView HeightRequest="1" Color="LightGray" />
</StackLayout>
<!-- Merchandiser Profile -->
<StackLayout Margin="10">
<Label Text="Name"/>
<Entry Text="{Binding Name}"/>
<Label Text="Phone"/>
<Entry Text="{Binding Phone}"/>
<Label Text="Email"/>
<Entry Text="{Binding Email}"/>
<StackLayout Orientation="Horizontal"
HorizontalOptions="Center">
<Button Text="Cancel"
Clicked="CancelButton_Clicked"/>
<Button Text="Save"
Command="{Binding SaveCommand}"/>
</StackLayout>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
MerchandiserEditPage.xaml.cs(查看 - 代码隐藏)
public partial class MerchandiserEditPage : ContentPage
{
Models.Merchandiser SelectedMerchandiser { get; set; }
public MerchandiserEditPage (Models.Merchandiser selectedMerchandiser)
{
InitializeComponent ();
SelectedMerchandiser = selectedMerchandiser;
this.BindingContext = new ViewModels.MerchandiserEditPageViewModel(selectedMerchandiser);
}
async private void CancelButton_Clicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
}
MerchandiserProfilePage.xaml(查看 - 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"
x:Class="MobileApp.Views.MerchandiserProfilePage"
NavigationPage.HasNavigationBar="False">
<ContentPage.Content>
<StackLayout>
<!--Page Heading-->
<StackLayout Spacing="0">
<Label Text="{Binding PageTitle}"
Style="{StaticResource PageTitle}"/>
<BoxView HeightRequest="1" Color="LightGray" />
</StackLayout>
<!-- Merchandiser Profile -->
<StackLayout Margin="10">
<Label Text="Name"/>
<Entry Text="{Binding Name}"
IsEnabled="False"/>
<Label Text="Phone"/>
<Entry Text="{Binding Phone}"
IsEnabled="False"/>
<Label Text="Email"/>
<Entry Text="{Binding Email}"
IsEnabled="False"/>
<StackLayout Orientation="Horizontal"
HorizontalOptions="Center">
<Button Text="Back"
Clicked="BackButton_Clicked"/>
<Button Text="Edit"
Clicked="EditButton_Clicked"/>
</StackLayout>
<Button Text="Delete"
Command="{Binding DeleteCommand}"/>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
MerchandiserProfilePage.xaml.cs -(查看 - 代码隐藏)
public partial class MerchandiserProfilePage : ContentPage
{
private Models.Merchandiser SelectedMerchandister { get; set; }
public MerchandiserProfilePage (Models.Merchandiser selectedMerchandiser)
{
InitializeComponent ();
SelectedMerchandister = selectedMerchandiser;
this.BindingContext = new ViewModels.MerchandiserProfilePageViewModel(selectedMerchandiser);
}
async private void BackButton_Clicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
async private void EditButton_Clicked(object sender, EventArgs e)
{
await Navigation.PushModalAsync(new Views.MerchandiserEditPage(SelectedMerchandister));
}
}
MerchandiserProfilePageViewModel.cs (ViewModel)
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace MobileApp.ViewModels
{
public class MerchandiserProfilePageViewModel : BaseViewModel
{
public string PageTitle { get; } = "Merchandiser Profile";
public Command DeleteCommand { get; }
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();
}
}
private string email;
public string Email
{
get { return email; }
set
{
email = value;
OnPropertyChanged();
}
}
public MerchandiserProfilePageViewModel(Models.Merchandiser selectedMerchandiser)
{
Name = selectedMerchandiser.Name;
Phone = selectedMerchandiser.Phone;
Email = selectedMerchandiser.Email;
DeleteCommand = new Command( async()=> {
bool deleteConfirmed = await Application.Current.MainPage.DisplayAlert("Confirm Delete",$"Are you sure you want to delete {selectedMerchandiser.Name} as a Merchandiser?","Yes","No");
if (deleteConfirmed)
{
// TODO: Delete Merchandiser
await Application.Current.MainPage.Navigation.PopModalAsync();
}
});
}
}
}
【问题讨论】:
-
您的虚拟机会创建您正在编辑的对象的新副本,因此对其所做的任何更改都不会反映在绑定到原始副本的其他视图中物体。您可以更改此设置,也可以使用事件或 MessagingCenter 等机制通知他们需要刷新数据副本
-
我尝试将
selectedMerchandiser从MerchandiserEditPageViewModel传递到Save Command,但这没有用。所以我创建了Merchandiser的new实例进行测试,希望这会添加另一条记录(但我忘记在发布之前恢复到原始代码)。这是你说的吗?我不想学习诸如 MessagingCenter 之类的新东西,因为这是明天到期的学校项目,我没有时间学习新东西。您能否提供一些代码来告诉我需要进行哪些更改? -
你的 repo 中的代码在启动时崩溃了,所以我无法告诉你需要更改什么
-
我更新了我的代码以反映更改。我的代码似乎为我执行。你添加了 SQLite 吗?我使用 VS2017 和 Android Nexus 5 Oreo 8.1 API 27 作为我的模拟器。我的目标框架是 .NET2.0。老实说,除了 Xamarin.Forms 和在其他设备上使用我的代码之外,我什么都没有。这个问题对我来说似乎也不是孤立的。许多其他学生也面临同样的问题
-
另外,您设置的是私有变量而不是公共变量
this.email = selectedMerchandiser.Email;而不是Email = selectedMerchandiser.Email;所以OnPropertyChanged()不会触发以通知 UI 任何更改
标签: c# sqlite xamarin xamarin.forms mvvm