How can I stop items being duplicated in SQLite database? - xamarin.forms

Here is my code where I add items to SQLite database
public partial class BirdPages : ContentPage
{
private SQLiteAsyncConnection _connection;
public BirdPages(string BirdNames, Button BirdSelect)
{
InitializeComponent();
_connection = DependencyService.Get<ISQLiteDb>().GetConnection();
BirdNameCall.Text = BirdNames;
AddToList = BirdSelect;
}
async private void AddToList_Clicked(object sender, EventArgs e)
{
await _connection.CreateTableAsync<Bmodel>();
string BirdNames = BirdNameCall.Text;
var voel = new Bmodel { Bname = BirdNames};
await _connection.InsertAsync(voel);
await DisplayAlert(BirdNames, "added to list", "Ok");
}
And here is where I get from database to a listview
public class Bmodel
{
[PrimaryKey, AutoIncrement]
public int Id { get; set;}
[MaxLength(255)]
public string Bname { get; set; }
}
public partial class myBirdList : ContentPage
{
private SQLiteAsyncConnection _connection;
private ObservableCollection<Bmodel> _birds;
public myBirdList()
{
InitializeComponent();
_connection = DependencyService.Get<ISQLiteDb>().GetConnection();
}
protected override async void OnAppearing()
{
await _connection.CreateTableAsync<Bmodel>();
var blists = await _connection.Table<Bmodel>().OrderBy(x => x.Bname).ToListAsync();
_birds = new ObservableCollection<Bmodel>(blists);
birdlistview.ItemsSource = _birds;
base.OnAppearing();
}
void MenuItem_Clicked(object sender, System.EventArgs e)
{
var blists = (sender as MenuItem).CommandParameter as Bmodel;
_connection.DeleteAsync(blists);
_birds.Remove(blists);
}
When an item is added twice or more to the database it display's in the listview. I would appreciate help on how to not display the duplicate items or even how to display alert when it is already in the database. I think it has something to do with the PrimaryKey if I am not mistaken. Any help would be great Thanks.

So all I changed was to keep my Public int Id as the Primary Key and change the Bname to [Unique] and where I used InsertAsync I changed it to InsertOrReplaceAsync

Related

xamarin.forms changing property of observablecollection does not update UI

I have an observrable collection in my class that contains checkboxes. I implemented a button to check all checkboxes at once. I tried just cycling through all elements and checking the box via binding:
void selectAll_clicked(System.Object sender, System.EventArgs e)
{
var x = sender as Button;
if (!allSelected)
{
allSelected = true;
x.Text = AppResources.DeselectAll;
foreach (var elem in contactList)
elem.isChecked = true;
}
else
{
allSelected = false;
x.Text = AppResources.SelectAll;
foreach (var elem in contactList)
elem.isChecked = false;
}
}
}
I am sure this effects the list, but the UI isnt updated at all.
How can I make sure the observablecollection "updates" visibly?
I also tried adding propertychanged handler:
private void SetList()
{
listview_contacts.ItemsSource = contactList;
contactList.CollectionChanged += items_CollectionChanged;
}
static void items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
{
foreach (INotifyPropertyChanged item in e.OldItems)
item.PropertyChanged -= item_PropertyChanged;
}
if (e.NewItems != null)
{
foreach (INotifyPropertyChanged item in e.NewItems)
item.PropertyChanged += item_PropertyChanged;
}
}
static void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
}
BUt this just says that the cast isnt valid...
Thank you
I was able to achieve that by altering my type like so:
public class ContactType : INotifyPropertyChanged
{
private string _name;
private bool _isChecked;
public string name
{
get => _name; set
{
_name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(name)));
}
}
public string phone { get; set; }
public string initials { get; set; }
public bool isChecked
{
get => _isChecked; set
{
_isChecked = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(isChecked)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}

How to safe a ObservableCollection within a ObservableCollection in xamarin.forms with Sqlite.net

Last 3 days i tried to save my collection in my database.
I tried it in all sorts of ways... without success.
The last one i tried is to serialize my collection and save it to a byte[] everytime the collection changes.
And on appstart i tried to derserialize it in my collection.
I'm just trying to show the most important thing's.
I can save and reload this class without problems from my database.
[Serializable]
public class MainElement : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public static int count = 0;
[PrimaryKey]
public int Id { get; set; }
public string Name { get; set; }
public byte[] _elements;
private ObservableCollection<SecondElement> elements;
[OneToMany]
public ObservableCollection<SecondElement> Elements
{
get
{
return elements;
}
set
{
elements = value;
this.SerializeElementsFromMainElement();
//_elements = ExtensionAndDb.SerializeElementsFromMainElement(elements);
OnPropertyChanged();
}
}
public MainElement()
{
Id = count++;
Elements = new ObservableCollection<SecondElement>();
this.DeSerializeElementsFromMainElement();
//Elements = ExtensionAndDb.DeSerializeElementsFromMainElement(_elements);
}
public void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
public void DeSerializeElementsFromMainElement()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream stream = new MemoryStream(_elements);
using (stream)
{
Elements = bf.Deserialize(stream) as ObservableCollection<SecondElement>;
}
}
public void SerializeElementsFromMainElement()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
using (stream)
{
bf.Serialize(stream, Elements);
_elements = stream.ToArray();
}
}
}
Every MainElement is stored in the MainList (ObservableCollection).
Everything is fine.
But i cant save or reload the public byte[] _elements; from/to the collection.
I know my code is not good, but if anyone has an idea or can show me how to save the public ObservableCollection<SecondElement> Elements with my class together in Sqlite, i would be really grateful.
I've been trying for 3 days
if you need more code, let me know.
Thank's in advance.
According to your description, you want to serialize and deserialie ObservableCollection, I suggest you ca use Newtonsoft.Json to do this.
Installing Newtonsoft.Json by Nuget package firstly.
For example, I do one esample:
public class person
{
public string username { get; set; }
public int age { get; set; }
}
public ObservableCollection<person> persons { get; set; }
private string list;
public Page13()
{
InitializeComponent();
persons = new ObservableCollection<person>()
{
new person(){username="cherry",age=12},
new person(){username="barry",age=14}
};
}
Btn1.clicked is to serialize data, Btn2.clicked is to deserialize data.
private void Btn1_Clicked(object sender, EventArgs e)
{
list = Newtonsoft.Json.JsonConvert.SerializeObject(persons);
}
private void Btn2_Clicked(object sender, EventArgs e)
{
var myValue = Newtonsoft.Json.JsonConvert.DeserializeObject<ObservableCollection<person>>(list) ;
}
If the Observablecollection changed, you can query this data by Id or other, then update this data.
Here is the article about Update, insert and save data in sqlite, you can take a look:
https://dzone.com/articles/register-and-login-using-sqlite-in-xamarinforms

Xamarin, how can i access a specific column property in sqlite so i can add the values?

I know how to read or show all data inserted in the database but I don't know how to query a specific data. In the my database is in Post.cs it will store date/time and get 2 datas from user.
so like this: enter image description here
Column1(ID), Column2(Date), (column3(rain1), column4(rain2).
1 12/13/2019 21 22
2 12/16/2019 21 22
3 12/16/2019 11 12
I want to do: if (rain1 && rain2) have the same date. I would like to add 2data from rain1 which is 21+11 and save the total to rain1total=32 then rain2total would be 34. I don't know where to start
here is Post.cs
namespace listtoPDF.Model
{
//Post table, user posting drainvolume
//this is the source of Binding
public class Post: INotifyPropertyChanged
{
private double? rain1Vol;
private double? rain2Vol;
//from settingspage to show up in history
string rain1lbl = Settings.Drain1LocationSettings;
string rain2lbl = Settings.Drain2LocationSettings;
//ID primary key that we will autoincrement
//These are columns ID, drain1 to 8 so 9 columns
//These are binding source for Historypage
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public static bool showLabel { get; set; } //public class model
public string rain1Lbl
{
get => rain1lbl;
set => rain1lbl= Settings.Drain1LocationSettings;
}
public string rain2Lbl
{
get => rain2lbl;
set => rain2lbl= Settings.Drain2LocationSettings;
}
public string CDateTime { get; set; }
[MaxLength(3)]
public double? rain1vol
{
get { return rain1Vol; }
set
{
rain1Vol = value;
RaisePropertyChanged("rain1vol");
}
}
[MaxLength(3)]
public double? rain2vol
{
get { return rain2Vol; }
set
{
rain2Vol = value;
RaisePropertyChanged("rain2vol");
}
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
here is the main that will list data entered with date
namespace listtoPDF
{
public partial class MainPage : ContentPage
{
List<Post> posts;
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation);
conn.CreateTable<Post>();
posts = conn.Table<Post>().ToList();
postListView.ItemsSource = posts;
conn.Close();
//right click quickwatch
}
void addbuttonHandle_Clicked(object sender, EventArgs args)
{
Navigation.PushModalAsync(new AddRainsPage());
}
private void GetValues()
{
//Initiate SQLite connection
//Create table with class
//Get the values in table
//close the line
SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation);
conn.CreateTable<Post>();
posts = conn.Table<Post>().ToList();
conn.Close();
}
}
Here is the page where i need query the add a certain column so i can add the data associated to it. So far it's connecting to the sqlite.
namespace listtoPDF
{
public partial class selecteddataPage : ContentPage
{
List<Post> posts;
public selecteddataPage()
{
InitializeComponent();
}
private void GetValues()
{
//Initiate SQLite connection
//Create table with class
//Get the values in table
//close the line
SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation);
conn.CreateTable<Post>();
posts = conn.Table<Post>().ToList();
**if (Post.rain1 values have the same date )
{
totalrain1= then add data that have same date
}
if (Post.rain2 values have the same date )
{
totalrain1= then add data that have same date
}**
conn.Close();
}
}
}

xamarin sqlite SQLiteException: near ")": syntax error add

I am trying to learn xaml and C# used in Xamarin Forms, and now I want to implement SQLite functionality.
I am simply trying to add a value into a SQL table but get the following error:
Unhandled Exception:
SQLite.SQLiteException: near ")": syntax error occurred
My Database connection interface is as follows:
using SQLite;
namespace TestSQLite
{
public interface IDatabaseConnection
{
SQLiteAsyncConnection GetConnection();
}
}
My Android specific Database Connection (iOS is identical) is as follows:
using SQLite;
using System.IO;
using TestSQLite;
using Xamarin.Forms;
[assembly: Dependency(typeof(DatabaseConnection))]
namespace TestSQLite
{
public class DatabaseConnection : IDatabaseConnection
{
public SQLiteAsyncConnection GetConnection()
{
var dbName = "TestDb.db3";
var path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), dbName);
return new SQLiteAsyncConnection(path);
}
}
}
My MainPage (testpage) is as follows:
using SQLite;
using Xamarin.Forms;
namespace TestSQLite
{
public class ControlledDrugs
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Drug { get; set; }
public double Volume { get; set; }
}
public class Users
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
}
public partial class MainPage : ContentPage
{
private SQLiteAsyncConnection _connection;
public MainPage()
{
InitializeComponent();
_connection = DependencyService.Get<IDatabaseConnection>().GetConnection();
}
protected override async void OnAppearing()
{
await _connection.CreateTableAsync<ControlledDrugs>();
await _connection.CreateTableAsync<Users>();
var drugs = await _connection.Table<ControlledDrugs>().ToListAsync();
Drugslistview.ItemsSource = drugs;
var user = await _connection.Table<Users>().ToListAsync();
Userlistview.ItemsSource = user;
base.OnAppearing();
}
async void OnAdd(object sender, System.EventArgs e)
{
var user = UserInput.Text;
//The next step generates the error
await _connection.InsertAsync(user);
}
void OnUpdate(object sender, System.EventArgs e)
{
}
void OnDelete(object sender, System.EventArgs e)
{
}
}
}
As you can see, I have yet to progress to update or delete. Learning by Youtube and Stackoverflow snippets is painfully slow. But this error got me stumped.
Also, have NuGet package sqlite-net-pcl v1.5.166-beta installed Xamarin Visual Studio.
you are attempting to insert a string into the User table instead of a User object
var user = UserInput.Text;
// user is just a string
await _connection.InsertAsync(user);
instead you need to create a User object
var user = new Users { Name = UserInput.Text };
await _connection.InsertAsync(user);

Getting selected value from Picker in Xamarin

I am getting data from a web service and I am loading it in Picker. Now I want to call a new web service to get some data related to selected item. But I am not getting that selected item.
I am using below class model to get data from web service and loading it in Picker.
public class ModelGetEmployeeList
{
public string ServiceStatus { get; set; }
public List<EmployeeList> EmpList { get; set; }
}
public class EmployeeList
{
public string uid { get; set; }
public string fname { get; set; }
public string lname { get; set; }
}
This is how I loaded data in Picker:
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync ();
var Items = JsonConvert.DeserializeObject <ModelGetEmployeeList> (content);
foreach(EmployeeList emp in Items.EmpList)
{
pickerEmployee.Items.Add(emp.uid.ToString()+"-"+emp.fname.ToString()+" "+emp.lname.ToString());
}
}
Now I am implementing SelectedIndexChanged event like this:
public void PickerEmployee_SelectedIndexChanged(object sender, SelectedItemChangedEventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var item = sender as EmployeeList;
var selectedItem = item.uid;
DisplayAlert (selectedItem.ToString (), "OK", "OK");
}
}
But its giving me an error that above method has wrong signature.
You can take sellected value with this:
string selectedEmployee = string.Empty;
selectedEmployee = pickerEmployee.Items[pickerEmployee.SelectedIndex];
According to the Xamarin.Forms Picker documentation SelectedIndexChanged event is expecting delegate which matches EventHandler delegate (EventHandler documentation)
So, you have to change signature of your method :
public void PickerEmployee_SelectedIndexChanged(object sender, EventArgs e)
{
...
}
Your signature is wrong.
Also the following code is wrong:
var item = sender as EmployeeList;
var selectedItem = item.uid;
Please find the corrected version below :
public void PickerEmployee_SelectedIndexChanged(object sender, EventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var selectedItem = PickerEmployee[SelectedIndex];
DisplayAlert (selectedItem, "OK", "OK");
}
}
The Xamarin Forms picker will get you only the string which was added to the list and not the object.
If you need the object either you can use the selectedIdex on your orginal lsit to get the object as :
var selectedEmp = Items.EmpList[SelectedIndex];
Or you can use a Bindable Picker.
public void PickerEmployee_SelectedIndexChanged(object sender, EventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var selectedItem = (EmployeeList)PickerEmployee.SelectedItem;
DisplayAlert (selectedItem.fname, "OK", "OK");
}
}
public void PickerEmployee_SelectedIndexChanged(object sender, SelectedItemChangedEventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var item = sender as Picker;
var selectedItem = item.SelectedItem as EmployeeList;
var uid =selectedItem.uid;
DisplayAlert (uid .ToString (), "OK", "OK");
}
}
The Items collection is a list of strings so you can get the currently selected value using SelectedIndex
var selectedValue = picker.Items [picker.SelectedIndex];
If you are using binding then yes, the exposed property is the SelectedIndex.
For more info click here
//How to get value of picker in Xamarin forms
//We are getting Text and Value from API
//xaml page
<controls:BorderlessPicker
x:Name="Pickdoctype"
ItemDisplayBinding="{Binding text}"
SelectedIndexChanged="Pickdoctype_SelectedIndexChanged"
HorizontalOptions="FillAndExpand"
Title="Enter Document Type"
FontSize="20"
TextColor="Gray">
</controls:BorderlessPicker>
// xaml.cs page
private void Pickdoctype_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
DocumentTypeModel selectedItem = (DocumentTypeModel)Pickdoctype.SelectedItem;
updatePickerValue = selectedItem.value;
}
catch (Exception ex)
{
}
}
// class
public class DocumentTypeModel
{
public string text { get; set; }
public string value { get; set; }
}

Resources