I'm writing an app where I need to perform CRUD operations on a list of people, called "Operators". Each Operator has a unique ID, a name, a phone number, an email address and an avatar.
With the help of @JessieZhang-2116, I am able to select a particular Operator from my SelectOperatorPage, then return this to my OperatorsPage.
From here, though, I wish to be able to Update the details of that Operator by pushing to a new OperatorInfoPage. This page should be able to be used for editing or deleting existing Operators or adding new Operators.
My problem is how to set Bindings so that data can be read from the OperatorInfoPage and the NewOperatorPage, and potentially how to delete the currently selected Operator.
The Pages, their code behinds and the Model and ViewModel classes are presented here...
OperatorModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using SQLite;
namespace HandsFreeNotes.Model
{
// public class OperatorModel
// The line above changed to the line below at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
public class OperatorModel: INotifyPropertyChanged
{
public int OperatorID { get; set; }
// public string OperatorName { get; set; }
// The 1 line above changed to the 6 lines below at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
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; }
// The 4 lines below added at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
public OperatorModel()
{
}
public OperatorModel(int operatorID, string operatorName, string operatorPhone, string operatorEmail, string operatorAvatar)
{
OperatorID = operatorID;
OperatorName = operatorName;
OperatorPhone = operatorPhone;
OperatorEmail = operatorEmail;
OperatorAvatar = operatorAvatar;
}
// All the lines below added at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
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;
}
}
OperatorViewModel.cs
using HandsFreeNotes.Model;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace HandsFreeNotes.ViewModel
{
public class OperatorViewModel : INotifyPropertyChanged
{
private string _HFNName;
public string HFNName
{
get
{
return _HFNName;
}
set
{
_HFNName = value;
RaisePropertyChanged("HFNName");
}
}
public List<OperatorModel> OperatorList;
public OperatorModel SelectedOperator;
public async Task<bool> GetOperators()
{
if (OperatorList == null)
{
OperatorList = new List<OperatorModel>();
OperatorList.Add(new OperatorModel(1, "Grime", "+61419659866", "apps@grime.net", "gs300.png"));
OperatorList.Add(new OperatorModel(2, "Brookey", "+61419659866", "brookey@grime.net", "gmb.jpg"));
OperatorList.Add(new OperatorModel(3, "CC", "+61422192456", "shaunachick@gmail.com", "cc.jpg"));
OperatorList.Add(new OperatorModel(4, "Monte", "+61412595878", "monte@aussieweb.com.au", "monte2a.jpg"));
OperatorList.Add(new OperatorModel(5, "Jeff", "+61409998197", "jeff@content2convert.com.au", "jeff.jpg"));
}
return true;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
}
public bool UpdateOperator(OperatorModel opm)
{
SelectedOperator.OperatorName = opm.OperatorName;
SelectedOperator.OperatorPhone = opm.OperatorPhone;
SelectedOperator.OperatorEmail = opm.OperatorEmail;
SelectedOperator.OperatorAvatar = opm.OperatorAvatar;
return true;
}
}
}
OperatorsPage.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="HandsFreeNotes.View.OperatorsPage">
<ContentPage.Content>
<Grid BackgroundColor="White">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="40"/>
<RowDefinition Height="40"/>
<RowDefinition Height="70"/>
<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="Center"
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="Operator"
FontSize="Large"
TextColor="Black"
FontAttributes="Bold"
Margin =" 0, 0, 0, 0"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="3"
HorizontalOptions="Center"
VerticalOptions="End"
BackgroundColor="Transparent"/>
<StackLayout
Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="3"
Orientation="Horizontal">
<Label
Text="Selected Operator: "
TextColor="Black"
FontSize="Medium"
FontAttributes="Bold"
HorizontalOptions="End"
VerticalOptions="Center"
BackgroundColor="Transparent"
Margin="20, 0, 0, 0"
WidthRequest="200"/>
<Entry
x:Name="SelectedOperatorEntry"
Text="{Binding OperatorName}"
TextColor="Green"
IsReadOnly="True"
Placeholder="No Currently Selected Operator"
PlaceholderColor="LightGray"
FontSize="Medium"
FontAttributes="Italic"
Margin ="0, 0, 0, 0"
HorizontalOptions="Center"
VerticalOptions="Center"
BackgroundColor="Transparent"
WidthRequest="200"/>
</StackLayout>
<ScrollView
Orientation="Vertical"
Grid.Row="4"
Grid.Column="0"
Grid.ColumnSpan="3">
<Grid BackgroundColor="White" >
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="100"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Button
x:Name="SelectOperatorButton"
Text="Select Operator"
FontSize="Medium"
Grid.Row="0"
Grid.Column="1"
TextColor="Black"
FontAttributes="Bold"
BackgroundColor="White"
Margin="0,0,0,0"
HorizontalOptions="Center"
VerticalOptions="Start"
Clicked="SelectOperatorButton_Clicked"/>
<Button
x:Name="UpdateOperatorButton"
Text="Update Selected Operator"
FontSize="Medium"
Grid.Row="1"
Grid.Column="1"
TextColor="Black"
FontAttributes="Bold"
BackgroundColor="White"
Margin="0,0,0,0"
HorizontalOptions="Center"
VerticalOptions="Start"
Clicked="UpdateOperatorButton_Clicked"/>
<Button
x:Name="DeleteOperatorButton"
Text="Delete Selected Operator"
FontSize="Medium"
Grid.Row="2"
Grid.Column="1"
TextColor="Black"
FontAttributes="Bold"
BackgroundColor="White"
Margin="0,0,0,0"
HorizontalOptions="Center"
VerticalOptions="Start"/>
<Button
x:Name="AddOperatorButton"
Text="Add New Operator"
FontSize="Medium"
Grid.Row="3"
Grid.Column="1"
HorizontalOptions="Center"
VerticalOptions="End"
TextColor="Black"
FontAttributes="Bold"
BackgroundColor="White"
Margin="0,0,0,0"
Clicked="AddOperatorButton_Clicked"/>
</Grid>
</ScrollView>
</Grid>
</ContentPage.Content>
</ContentPage>
OperatorsPage.xaml.cs
using HandsFreeNotes.ViewModel;
using HandsFreeNotes.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace HandsFreeNotes.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class OperatorsPage : ContentPage
{
OperatorViewModel ovm;
OperatorModel opm;
// public OperatorsPage(OperatorViewModel _ovm)
// The line above changed to the line below at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
public OperatorsPage()
{
// 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();
// ovm = _ovm;
// opm = ovm.SelectedOperator;
// The 2 lines above changed to the line below at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
opm = new OperatorModel();
BindingContext = opm;
}
private async void BackButton_Clicked(object sender, EventArgs e)
{
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());
// The line above originally commented out at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
}
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 lines below added at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
private void BackCall(object s, OperatorModel model)
{
opm.OperatorName = model.OperatorName;
}
private async void UpdateOperatorButton_Clicked(object sender, EventArgs e)
{
//var operatorInfoPage = new OperatorInfoPage();
//operatorInfoPage.BindingContext = ovm;
//await Navigation.PushModalAsync(operatorInfoPage);
}
}
}
SelectOperatorPage.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="HandsFreeNotes.View.SelectOperatorPage">
<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>
</ContentPage>
SelectOperatorPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using HandsFreeNotes.ViewModel;
using HandsFreeNotes.Model;
namespace HandsFreeNotes.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SelectOperatorPage : ContentPage
{
OperatorViewModel ovm;
// Added the line below at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
public EventHandler<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();
ovm = new OperatorViewModel();
BindingContext = ovm;
}
protected override async void OnAppearing()
{
base.OnAppearing();
await ovm.GetOperators();
OperatorListView.ItemsSource = ovm.OperatorList;
}
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)
{
// Typecast the e.SelectedItem object to an OperatorModel
// ovm.SelectedOperator = (OperatorModel)e.SelectedItem;
// await DisplayAlert("Alert", "Selected Operator: " + ovm.SelectedOperator.OperatorName, "Exit");
// The 2 lines above were changed to the 7 below at the behest of JessieZhang-2116 (Microsoft Q&A) 01/05/2021
OperatorModel operatorModel = (OperatorModel)e.SelectedItem;
ovm.SelectedOperator = operatorModel;
EventHandler<OperatorModel> handler = ReturnValue;
if (handler != null)
{
handler(this, operatorModel);
}
await Navigation.PopModalAsync();
}
}
}
}
OperatorInfoPage.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="HandsFreeNotes.View.OperatorInfoPage">
<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="Update 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="Plain"
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"
Text="{Binding }"
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 (inc. Country - 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="Plain"
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>
</ContentPage>
OperatorInfoPage.xaml.cs
using HandsFreeNotes.Model;
using HandsFreeNotes.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace HandsFreeNotes.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class OperatorInfoPage : ContentPage
{
OperatorViewModel ovm;
OperatorModel opm;
public OperatorInfoPage(OperatorViewModel _ovm)
{
// 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();
ovm = _ovm;
opm = ovm.SelectedOperator;
BindingContext = opm;
}
private async void BackButton_Clicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
private async void OKButton_Clicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
private async void CancelButton_Clicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
}
}


