Hello,
Welcome to our Microsoft Q&A platform!
Based on your code, I created a demo and modified your database HFNDatabase
. The insert and
You can refer to the following code:
- HFNDatabase.cs public class HFNDatabase
{
static SQLiteAsyncConnection database;public static readonly AsyncLazy<HFNDatabase> Instance = new AsyncLazy<HFNDatabase>(async () => { var instance = new HFNDatabase(); CreateTableResult result = await database.CreateTableAsync<Models.OperatorModel>(); return instance; }); public HFNDatabase() { database = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags); } public Task<List<Models.OperatorModel>> GetOperatorsAsync() { return database.Table<Models.OperatorModel>().ToListAsync(); } public Task<int> DeleteItemAsync(Models.OperatorModel item) { return database.DeleteAsync(item); } public Task<int> SaveItemAsync(Models.OperatorModel item) { if (item.OperatorID != 0) { return database.UpdateAsync(item); } else { return database.InsertAsync(item); } } }
Constants.cs
public static class Constants
{
public const string DatabaseFilename = "OperatorsSQLite.db3";
public const SQLite.SQLiteOpenFlags Flags =
// open the database in read/write mode
SQLite.SQLiteOpenFlags.ReadWrite |
// create the database if it doesn't exist
SQLite.SQLiteOpenFlags.Create |
// enable multi-threaded database access
SQLite.SQLiteOpenFlags.SharedCache;
public static string DatabasePath
{
get
{
var basePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
return Path.Combine(basePath, DatabaseFilename);
}
}
}
AsyncLazy.cs
public class AsyncLazy<T> : Lazy<Task<T>>
{
readonly Lazy<Task<T>> instance;
public AsyncLazy(Func<T> factory)
{
instance = new Lazy<Task<T>>(() => Task.Run(factory));
}
public AsyncLazy(Func<Task<T>> factory)
{
instance = new Lazy<Task<T>>(() => Task.Run(factory));
}
public TaskAwaiter<T> GetAwaiter()
{
return instance.Value.GetAwaiter();
}
}
OperatorModel.cs
public class OperatorModel: INotifyPropertyChanged
{
[PrimaryKey, AutoIncrement]
public int OperatorID { get; set; }
string _operatorName;
public string OperatorName
{
set { SetProperty(ref _operatorName, value); }
get { return _operatorName; }
}
public string OperatorPhone { get; set; }
public string OperatorEmail { get; set; }
public string OperatorAvatar { get; set; }
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
- In page
SelectOperatorPage.xaml
, you can use data binding :<ContentPage.Content> <Grid BackgroundColor="White"> <Grid.RowDefinitions> <RowDefinition Height="40"/> <RowDefinition Height="40"/> <RowDefinition Height="80"/> <RowDefinition Height="*"/> <RowDefinition Height="50"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="50"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="50"/> </Grid.ColumnDefinitions> <Button x:Name="BackButton" Text="Back" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" TextColor="Black" FontAttributes="Bold" HeightRequest="40" VerticalOptions="CenterAndExpand" HorizontalOptions="End" Margin="0,0,20,0" Clicked="BackButton_Clicked"/> <Image Source="hfn256" Margin="2" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" HorizontalOptions="Center" BackgroundColor="Transparent"/> <Label Text="Select Operator..." FontSize="Large" TextColor="Black" FontAttributes="Bold" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" HorizontalOptions="Center" VerticalOptions="Start" Margin="20" BackgroundColor="Transparent"/> <ListView x:Name="OperatorListView" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" RowHeight="140" ItemSelected="OperatorListView_ItemSelected"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <ContentView> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="100"/> <ColumnDefinition Width="200"/> </Grid.ColumnDefinitions> <Image Source="{Binding OperatorAvatar}" Grid.Row="0" Grid.Column="0" HeightRequest="200" WidthRequest="100"/> <Label Text="{Binding OperatorName}" FontAttributes="Bold" HorizontalOptions="Start" VerticalOptions="Center" Grid.Row ="0" Grid.Column="1"/> <Label Text="{Binding OperatorEmail}" FontAttributes="Italic" FontSize="Micro" Grid.Row="0" Grid.Column="2" HeightRequest="30" HorizontalOptions="Start" VerticalOptions="Center"/> <Label Text="{Binding OperatorPhone}" FontAttributes="Italic" FontSize="Small" Grid.Row="0" Grid.Column="2" HeightRequest="30" HorizontalOptions="Start" VerticalOptions="End"/> </Grid> </ContentView> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </Grid> </ContentPage.Content>
SelectOperatorPage.xaml.cs
public partial class SelectOperatorPage : ContentPage
{
OperatorViewModel ovm;
public EventHandler<Models.OperatorModel> ReturnValue;
public SelectOperatorPage()
{
// add a bit of padding to cater to the "notch" on the iPhone.
if (Device.RuntimePlatform == Device.iOS)
{
Padding = new Thickness(0, 40, 0, 0);
}
InitializeComponent();
}
protected override async void OnAppearing()
{
base.OnAppearing();
//await ovm.GetOperators();
//OperatorListView.ItemsSource = OperatorViewModel.OperatorList;
HFNDatabase database = await HFNDatabase.Instance;
OperatorListView.ItemsSource = await database.GetOperatorsAsync();
}
private async void BackButton_Clicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
private async void OperatorListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem != null)
{
Models.OperatorModel operatorModel = (Models.OperatorModel)e.SelectedItem;
//ovm.SelectedOperator = operatorModel;
EventHandler<Models.OperatorModel> handler = ReturnValue;
if (handler != null)
{
handler(this, operatorModel);
}
await Navigation.PopModalAsync();
}
}
}
- In NewOperatorPage.xaml.cs,we can create a new Operator by code
await database.SaveItemAsync(todoItem);
[XamlCompilation(XamlCompilationOptions.Compile)] public partial class NewOperatorPage : ContentPage { public NewOperatorPage() { // add a bit of padding to cater to the "notch" on the iPhone. if (Device.RuntimePlatform == Device.iOS) { Padding = new Thickness(0, 40, 0, 0); } InitializeComponent(); } private async void BackButton_Clicked(object sender, EventArgs e) { await Navigation.PopModalAsync(); } private async void OKButton_Clicked(object sender, EventArgs e) { //var name = NameEntry.Text; //var Phone = PhoneEntry.Text; //var Email = EmailEntry.Text; //var Avatar = AvatarEntry.Text; //OperatorViewModel.OperatorList.Add(new OperatorModel(OperatorViewModel.OperatorList.Count, name, Phone, Email, Avatar)); //await Navigation.PopModalAsync(); var todoItem = (Models.OperatorModel)BindingContext; HFNDatabase database = await HFNDatabase.Instance; await database.SaveItemAsync(todoItem); await Navigation.PopModalAsync(); } private async void CancelButton_Clicked(object sender, EventArgs e) { await Navigation.PopModalAsync(); } }
In NewOperatorPage.xaml
, we can also use data binding for the several Entry
.
<ContentPage.Content>
<Grid BackgroundColor="White">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="40"/>
<RowDefinition Height="30"/>
<RowDefinition Height="10"/>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Button
x:Name="BackButton"
Text="Back"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="3"
TextColor="Black"
FontAttributes="Bold"
HeightRequest="40"
VerticalOptions="CenterAndExpand"
HorizontalOptions="End"
Margin="0,0,20,0"
Clicked="BackButton_Clicked"/>
<Image
Source="hfn256"
Margin="2"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="3"
HorizontalOptions="Center"
BackgroundColor="Transparent"/>
<Label
Text="Add Operator"
FontSize="Large"
TextColor="Black"
FontAttributes="Bold"
Padding =" 0, 0, 0, 0"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="3"
HorizontalOptions="Center"
VerticalOptions="End"
BackgroundColor="Transparent"/>
<ScrollView Orientation="Vertical"
Grid.Row="4" Grid.Column="0"
Grid.ColumnSpan="3">
<Grid BackgroundColor="White" >
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="100"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label
x:Name="NameLabel"
Text="Name: "
TextColor="Black"
FontSize="Medium"
FontAttributes="Bold"
Grid.Row="0"
Margin="40, 0, 0, 0"
HorizontalOptions="Start"
VerticalOptions="Center"/>
<Entry
x:Name="NameEntry"
Text="{Binding OperatorName}"
Placeholder="Enter a name / callsign"
PlaceholderColor="LightGray"
TextColor="DarkBlue"
FontSize="Medium"
Keyboard="Text"
Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="0, 0, 30, 0"/>
<Label
x:Name="PhoneLabel"
Text="Phone: +"
TextColor="Black"
FontSize="Medium"
FontAttributes="Bold"
Grid.Row="1"
Grid.Column="0"
Margin="40, 0, 0, 0"
HorizontalOptions="Start"
VerticalOptions="Center"/>
<!-- <Entry
x:Name="PhoneCountryEntry"
Placeholder="Country"
PlaceholderColor="LightGray"
TextColor="DarkBlue"
FontSize="Medium"
Keyboard="Numeric"
Grid.Row="1"
Grid.Column="1"
Margin="0, 0, 0, 0"/> -->
<Entry
x:Name="PhoneEntry"
Text="{Binding OperatorPhone}"
Placeholder="Phone (no spaces)"
PlaceholderColor="LightGray"
TextColor="DarkBlue"
FontSize="Medium"
Keyboard="Numeric"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="0, 0, 30, 0"/>
<Label
x:Name="EmailLabel"
Text="Email: "
TextColor="Black"
FontSize="Medium"
FontAttributes="Bold"
Grid.Row="2"
Margin="40, 0, 0, 0"
HorizontalOptions="Start"
VerticalOptions="Center"/>
<Entry
x:Name="EmailEntry"
Text="{Binding OperatorEmail}"
Placeholder="Enter Email..."
PlaceholderColor="LightGray"
TextColor="DarkBlue"
FontSize="Medium"
Keyboard="Email"
Grid.Row="2"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="0, 0, 30, 0"/>
<Label
x:Name="AvatarLabel"
Text="Avatar: "
TextColor="Black"
FontSize="Medium"
FontAttributes="Bold"
Grid.Row="3"
Margin="40, 0, 0, 0"
HorizontalOptions="Start"
VerticalOptions="Center"/>
<Entry
x:Name="AvatarEntry"
Text="{Binding OperatorAvatar}"
Placeholder="Enter Avatar URL..."
PlaceholderColor="LightGray"
TextColor="DarkBlue"
FontSize="Medium"
Keyboard="Url"
Grid.Row="3"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="0, 0, 30, 0"/>
<Button
x:Name="OKButton"
Text="OK"
TextColor="Black"
FontAttributes="Bold"
HorizontalOptions="Start"
VerticalOptions="Center"
WidthRequest="100"
HeightRequest="40"
Margin="0, 20, 0, 0"
Grid.Row="4"
Grid.Column="1"
Clicked="OKButton_Clicked"/>
<Button
x:Name="CancelButton"
Text="Cancel"
TextColor="Black"
FontAttributes="Bold"
HorizontalOptions="End"
VerticalOptions="Center"
WidthRequest="100"
HeightRequest="40"
Margin="0, 20, 40, 0"
Grid.Row="4"
Grid.Column="2"
Clicked="CancelButton_Clicked"/>
</Grid>
</ScrollView>
</Grid>
</ContentPage.Content>
- In
OperatorsPage.xaml.cs
, I changed functionAddOperatorButton_Clicked
to the following code. In this page, you can also use data binding forSelectedOperatorEntry
Entry .private async void AddOperatorButton_Clicked(object sender, EventArgs e) { await Navigation.PushModalAsync(new NewOperatorPage { BindingContext = new OperatorModel() }); }
The whole code of OperatorsPage .xaml.cs
public partial class OperatorsPage : ContentPage
{
// OperatorViewModel ovm;
OperatorModel opm;
public EventHandler<OperatorModel> ReturnValue;
public OperatorsPage(OperatorModel SelectModel)
{
if (Device.RuntimePlatform == Device.iOS) { Padding = new Thickness(0, 40, 0, 0); }
InitializeComponent();
//if (SelectModel != null)
//{
// opm = SelectModel;
//}
//else
//{
// opm = new OperatorModel();
//}
opm = new OperatorModel();
BindingContext = opm;
}
private async void BackButton_Clicked(object sender, EventArgs e)
{
// The if statements below added at the behest of JessieZhang-2116 (Microsoft Q&A) 13/05/2021
if (SelectModel != null)
{
EventHandler<OperatorModel> handler = ReturnValue;
if (handler != null)
{
handler(this, opm);
}
}
await Navigation.PopModalAsync();
// The line above originally commented out at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
}
private async void AddOperatorButton_Clicked(object sender, EventArgs e)
{
await Navigation.PushModalAsync(new NewOperatorPage {
BindingContext = new OperatorModel()
});
}
private async void SelectOperatorButton_Clicked(object sender, EventArgs e)
{
// The lines below added at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
SelectOperatorPage page = new SelectOperatorPage();
page.ReturnValue += delegate (object s, OperatorModel operatorModel)
{
BackCall(s, operatorModel);
};
await Navigation.PushModalAsync(page);
}
// The line below added at the behest of LeonLu-MSFT (Microsoft Q&A) 06/05/2021
OperatorModel SelectModel;
// The lines below added at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
private void BackCall(object s, OperatorModel model)
{
SelectModel = model;
opm.OperatorName = model.OperatorName;
}
// The lines included below in the DeleteOperatorButton_Clicked added at the behest of LeonLu-MSFT (Microsoft Q&A) 06/05/2021
private async void DeleteOperatorButton_Clicked(object sender, EventArgs e)
{
if (SelectModel != null)
{
bool answer = await DisplayAlert("Warning!", "Do you really want to delete Operator " + SelectModel.OperatorName, "Yes", "No");
if (answer == true)
{
OperatorViewModel.OperatorList.Remove(SelectModel);
SelectModel = null;
SelectedOperatorEntry.Text = "";
}
}
else
{
await DisplayAlert("Info", "Please select an Operator to delete", "OK");
}
}
// The lines below in UpdateOperatorButton_Clicked added at the behest of LeonLu-MSFT (Microsoft Q&A) 11/05/2021
private async void UpdateOperatorButton_Clicked(object sender, EventArgs e)
{
if (SelectModel != null)
{
var operatorInfoPage = new OperatorInfoPage(SelectModel);
operatorInfoPage.ReturnValue += delegate (object s, OperatorModel operatorModel)
{
BackCall(s, operatorModel);
};
await Navigation.PushModalAsync(operatorInfoPage);
}
else
{
await DisplayAlert("Info", "Please select an Operator", "OK");
}
}
}
Note:
I just modified some of your code which is relative to the fuction of GetOperatorsAsync
and SaveItemAsync
in database HFNDatabase
. It works on my side.
You can change above code according to your requirement.
Best Regards,
Jessie Zhang
---
If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.