How to bind data from SQLite database to picker Xamarin Forms? - xamarin

I got the data from my SQLite Database I want to bind the data i got to my picker.How can I bind the data to picker? Below is the Contacts table and function
Picker ItemsSource="{Binding Retailer}" ItemDisplayBinding="{Binding RetailerName}"
[Table("tblContacts")]
public class ContactsTable
{
[PrimaryKey, MaxLength(100)]
public string ContactID { get; set; }
[MaxLength(80)]
public string FileAs { get; set; }
[MaxLength(50)]
public string FirstName { get; set; }
[MaxLength(30)]
public string MiddleName { get; set; }
[MaxLength(30)]
public string LastName { get; set; }
}
public FieldActivityForm ()
{
InitializeComponent ();
BindingContext = new FieldActivityFormViewModel();
tpTime.Time = DateTime.Now.TimeOfDay;
SetRetailerPicker();
}
public void SetRetailerPicker()
{
var db = DependencyService.Get<ISQLiteDB>();
var conn = db.GetConnection();
var getUser = conn.QueryAsync<ContactsTable>("SELECT FileAs FROM tblContacts");
var resultCount = getUser.Result.Count;
if (resultCount < 1)
{
//MessagingCenter.Send(this, "Http", Retailer);
}
else
{
var result = getUser.Result;
myPicker.ItemsSource = result;
}
}

In your XAML
<Picker x:Name="myPicker" ItemDisplayBinding="{Binding RetailerName}" />
in the code behind, after loading the data
myPicker.ItemsSource = result;
this assumes ContactsTable is an IEnumerable that contains a property RetailerName

Related

How exactly to use and save images in Xamarin(in ListView)?

i want to be able to take a picture with the emulator, have it create and save an item on the database and display properly on my main Item Page, how do I go about doing this?
i tried my best to only show what is important and related to this and therefore have cut a bunch of stuff out(for example my View for adding items isnt present because i THINK the only part relating to this is the button with a command binding to it leading to the viewmodel)
the reason im asking here is because there are no errors showing, the application doesnt start at all like this and im really confused, i appreciate any and all help and thank you in advance.
if you need any additional info about anything related to this please do ask and i will share it as soon as i see your messeage.
my Item.cs
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string LongDescription { get; set; }
public MediaFile Image { get; set; }
public string Quantity { get; set; }
public string TypeOfQuantity { get; set; }
}
my main page Listview (without the unimportant parts in XAML)
<ListView>
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:Item">
<ViewCell Height="220" xct1:ShadowEffect.Radius="5">
<Grid Padding="7">
<Frame CornerRadius="15">
<StackLayout Orientation="Horizontal">
...// bunch of labels and what not//
</StackLayout>
</StackLayout>
</Frame>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
the Item Creating ViewModel (unrelated things cut out)
public string Name { get; set; }
public string ShDesc { get; set; }
public string LgDesc { get; set; }
public string Qty { get; set; }
public MediaFile Image { get; set; }
public string TypeOfQty { get; set; }
public AsyncCommand AddCommand { get; }
public AsyncCommand PicCommand { get; }
public ItemAddViewModel()
{
AddCommand = new AsyncCommand(Add);
PicCommand = new AsyncCommand(Pic);
}
async Task Add()
{
var name = Name;
var description = ShDesc;
var longdescription = LgDesc;
var qty = Qty;
var typeofqty = TypeOfQty;
var image = Image;
await ItemService.AddItem(name, description, longdescription, qty, typeofqty, image);
Name = ShDesc = LgDesc = Qty = TypeOfQty = null;
}
async Task Pic()
{
var photo = await CrossMedia.Current.TakePhotoAsync(
new StoreCameraMediaOptions
{
SaveToAlbum = true
});
Image = photo;
}
}
}
my Services and DB
public static class ItemService
{
static SQLiteAsyncConnection db;
static async Task Init()
{
//creats Database if it doesnt exist
if (db != null)
return;
var databasePath = Path.Combine(FileSystem.AppDataDirectory, "Mydata.db");
db = new SQLiteAsyncConnection(databasePath);
await db.CreateTableAsync<Item>();
}
//adds item to database
public static async Task AddItem(string Name, string Description,string LongDescription, string Quantity, string TypeOfQuantity, MediaFile image)
{
await Init();
var item = new Item
{
Name = Name,
LongDescription = LongDescription,
Description = Description,
Quantity = Quantity,
TypeOfQuantity = TypeOfQuantity,
Image = image
};
await db.InsertAsync(item);
}

How to binding the selected value into the picker and save this edit page?

I have this Edit page where it has an Id passed from the Detail page. Then called web api service to get Categories as well as the Activity. This code below was adapted from the Add page btw.
It has 2 issues:
Managed to get the picker list BUT then not sure how to binding this from selected Activity.
How to save this as the binding name is different in XAML ie. Activity.Name VS Name etc etc. What did I do wrong?
How to solve these?
Code below:
ActivityEditPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage.Content>
<StackLayout Margin="5,5,5,5" VerticalOptions="StartAndExpand">
<Entry Placeholder="Name" Text="{Binding Activity.Name}"></Entry>
<Picker ItemsSource="{Binding Categories}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding Activity.CategoryId}">
</Picker>
<Entry Placeholder="No of minutes" Text="{Binding Activity.NoOfMinutes}"></Entry>
<Editor Placeholder="Description" Text="{Binding Activity.Description}"></Editor>
<Button Text="Save" BackgroundColor="#340E22" FontSize="Small" TextColor="White" CornerRadius="30" HeightRequest="40" Command="{Binding SaveCommand}"></Button>
</StackLayout>
</ContentPage.Content>
Code behind:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace AthlosifyMobileApp.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ActivityEditPage : ContentPage
{
public ActivityEditPage(int id)
{
InitializeComponent();
BindingContext = new ActivityEditViewModel(Navigation, id);
}
}
}
ActivityEditViewModel.cs:
using AthlosifyMobileApp.Helpers;
using AthlosifyMobileApp.Models;
using AthlosifyMobileApp.Services;
using AthlosifyMobileApp.Views;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace AthlosifyMobileApp.ViewModels
{
public class ActivityEditViewModel : BaseViewModel
{
private readonly ApiService apiService = new ApiService();
private int _id;
private string _name;
private string _description;
private int _noOfMinutes;
private int _categoryId;
private string _categoryName;
private Command _saveCommand;
private List<Category> _categories;
private Category _selectedCategory;
private Activity _activity;
public ActivityEditViewModel(INavigation navigation, int Id)
{
this.Navigation = navigation;
Task.Run(async () =>
{
await GetCategories();
Activity = await GetActivity(Id);
});
}
public INavigation Navigation { get; set; }
public Activity Activity
{
get { return _activity; }
set
{
_activity = value;
OnPropertyChanged();
}
}
public int Id
{
get { return _id; }
set
{
_id = value;
OnPropertyChanged();
}
}
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
SaveCommand.ChangeCanExecute();
}
}
public string Description
{
get { return _description; }
set
{
_description = value;
OnPropertyChanged();
}
}
public int NoOfMinutes
{
get { return _noOfMinutes; }
set
{
_noOfMinutes = value;
OnPropertyChanged();
}
}
public int CategoryId
{
get { return _categoryId; }
set
{
_categoryId = value;
OnPropertyChanged();
}
}
public string CategoryName
{
get { return _categoryName; }
set
{
_categoryName = value;
OnPropertyChanged();
}
}
public List<Category> Categories
{
get { return _categories; }
set
{
_categories = value;
OnPropertyChanged("Categories");
}
}
public Category SelectedCategory
{
get
{
return _selectedCategory;
}
set
{
_selectedCategory = value;
OnPropertyChanged();
}
}
public Command SaveCommand
{
get
{
return _saveCommand ?? (_saveCommand = new Command(ExecuteSaveCommand, CanSave));
}
}
async void ExecuteSaveCommand()
{
var newItem = new Activity
{
Id = Id,
OwnerId = Preferences.Get(Constant.Setting_UserId, ""),
Name = Name,
CategoryId = SelectedCategory.Id,
CategoryName = SelectedCategory.Name,
Description = Description,
NoOfMinutes = NoOfMinutes
};
var response = await apiService.UpdateActivity(Id, newItem);
if (!response)
{
await Application.Current.MainPage.DisplayAlert("Error", "Something wrong", "Alright");
}
else
{
await Navigation.PushAsync(new ActivityListPage());
}
}
bool CanSave()
{
return !string.IsNullOrWhiteSpace(Name);
}
public async Task<List<Category>> GetCategories()
{
CategoryResult categoryResult = await apiService.GetCategories();
return Categories = categoryResult.Results;
}
public async Task<Activity> GetActivity(int id)
{
Activity activity = await apiService.GetActivity(id);
return activity;
}
}
}
UPDATED CODE
Category.cs
public class Category
{
public int Id { get; set; }
public string OwnerId { get; set; }
public int ParentId { get; set; }
public string ParentName { get; set; }
public string Name { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime? ModifiedDate { get; set; }
}
Activity.cs:
public class Activity
{
public int Id { get; set; }
public string OwnerId { get; set; }
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int NoOfMinutes { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime? ModifiedDate { get; set; }
}

How to add custom text to Picker's ItemDisplayBinding in Xamarin Forms

I want to add A custom text to my Picker. I have a picker the ItemsSource and ItemDisplayBinding binds from my database How can I add a custom text to my ItemDisplayBinding I want to mix Retailer Code with PresStreet and format to "Retailer Code - Street" My table is below for reference
Picker Title="Select Retailer Code" x:Name="codePicker" SelectedIndexChanged="codePicker_SelectedIndexChanged" ItemsSource="{Binding RetailerCode}" ItemDisplayBinding="{Binding RetailerCode}" StyleClass="fieldForm" IsEnabled="False"
My code below is how I get the data from my database and add the data to my picker
var db = DependencyService.Get<ISQLiteDB>();
var conn = db.GetConnection();
var getCode = conn.QueryAsync<RetailerGroupTable>("SELECT * FROM tblRetailerGroup WHERE ContactID=?", item.ContactID);
var resultCount = getCode.Result.Count;
if (resultCount > 0)
{
var result = getCode.Result;
codePicker.ItemsSource = result;
codePicker.IsEnabled = true;
}
else
{
lstName.IsVisible = false;
codePicker.IsEnabled = false;
}
My retailer group table:
[Table("tblRetailerGroup")]
public class RetailerGroupTable
{
[PrimaryKey, MaxLength(100)]
public string RetailerCode { get; set; }
public int ContactID { get; set; }
[MaxLength(300)]
public string PresStreet { get; set; }
[MaxLength(90)]
public string PresBarangay { get; set; }
[MaxLength(90)]
public string PresDistrict { get; set; }
[MaxLength(90)]
public string PresTown { get; set; }
[MaxLength(90)]
public string PresProvince { get; set; }
[MaxLength(90)]
public string PresCountry { get; set; }
[MaxLength(30)]
public string Telephone1 { get; set; }
[MaxLength(30)]
public string Telephone2 { get; set; }
[MaxLength(20)]
public string Mobile { get; set; }
[MaxLength(50)]
public string Email { get; set; }
[MaxLength(200)]
public string GPSCoordinates { get; set; }
[MaxLength(100)]
public string Coordinator { get; set; }
public DateTime LastSync { get; set; }
public DateTime ServerUpdate { get; set; }
public DateTime MobileUpdate { get; set; }
}
add a read only property to your class RetailerGroupTable
public string DisplayText {
get {
return $"{RetailerCode} - {PresStreet}";
}
}
and then bind to it
<Picker ItemDisplayBinding="{Binding DisplayText}" ... />

HttpClient Xamarin.Forms

I have an application that allows users to log in via facebook. I am trying to save each user to my database using my WebApi. However, I am encountering this exception error: System.NullReferenceException: Object reference not set to an instance of an object. Can anyone see what I am doing incorrectly to cause this. Thanks.
CustomerService class:
public async Task<int> AddCustomer(Customer cust)
{
var data = JsonConvert.SerializeObject(cust);
var content = new StringContent(data, Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Add("X-Giftworx-App", "Posworx");
var response = await client.PostAsync("http/my api address/api/Customer/Insert", content);
var result = JsonConvert.DeserializeObject<int>(response.Content.ReadAsStringAsync().Result);
return result;
}
Customer class:
public class Customer
{
public string Token { get; set; }
public bool Authenticated { get; set; }
public string SecretKey { get; set; }
public int StoreCustomerID { get; set; }
public string Number { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public object Address { get; set; }
public string Email { get; set; }
public string City { get; set; }
public string Region { get; set; }
public string Country { get; set; }
public string MobilePhone { get; set; }
public DateTime DOB { get; set; }
public object Phone { get; set; }
public object DeviceToken { get; set; }
public object Details { get; set; }
public object Gender { get; set; }
public bool IsError { get; set; }
public object ErrorMessage { get; set; }
public bool PhoneVerified { get; set; }
}
FacebookRender
public class FacebookRender : PageRenderer
{
CustomerService customerService;
public FacebookRender()
{
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator(
clientId: "my app client's id",
scope: "",
authorizeUrl: new Uri("https://www.facebook.com/dialog/oauth/"),
redirectUrl: new Uri("https://www.facebook.com/connect/login_success.html")
);
auth.Completed += async (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
await AccountStore.Create().SaveAsync(eventArgs.Account, "FacebookProviderKey");
var accessToken = eventArgs.Account.Properties["access_token"].ToString();
var expiresIn = Convert.ToDouble(eventArgs.Account.Properties["expires_in"]);
var expiryDate = DateTime.Now + TimeSpan.FromSeconds(expiresIn);
var request = new OAuth2Request("GET", new Uri("https://graph.facebook.com/me"), null, eventArgs.Account);
var response = await request.GetResponseAsync();
var obj = JObject.Parse(response.GetResponseText());
var id = obj["id"].ToString().Replace("\"", "");
var name = obj["name"].ToString().Replace("\"", "");
Customer cust = new Customer();
cust.Token = accessToken;
cust.Name = name;
await customerService.AddCustomer(cust);
App.NavigateToProfile(string.Format(name));
}
else
{
App.NavigateToProfile("Invalid Login");
}
};
activity.StartActivity(auth.GetUI(activity));
}
}

Xamarin ImageSource in ListView not updating

I have a ListView that contains images, the images are fetched from a server. The first API call I make gets the data in var people. I load the listview with a placeholder image, then run the 2nd API call to get the images for each item in the listview. I receive a byte[] as the image, and I convert it to an ImageSource. I have a search button at the top of the page that I set binding to TempImage which uses the byte[] as its source, and it changes to the images that are loaded. So the conversion of byte[] to ImageSource is fine. The initial setting of p.PictureImageSource = "name_circle.png" also works correctly. However, setting p.PictureImageSource to the converted byte[] does NOT work. It never changes from the initial "name_circle.png". Any ideas?
var people = peopleModel.Response;
if(people.Count == 0)
{
ShowNoResults = true;
}
else
{
ShowNoResults = false;
Results = peopleModel.Response;
foreach (PersonViewModel p in Results)
{
p.Initials = p.FirstName[0].ToString() + p.LastName[0];
p.PictureImageSource = "name_circle.png";
}
}
//must do 2 seperate loops so the initials load before going on with 2nd search
foreach (PersonViewModel p in Results)
{
IsBusy = false;
var peopleImage = await peopleService.GetPersonImage("p.Email");
if ((peopleImage.Error == null) && (peopleImage.Response != null))
{
p.Picture = peopleImage.Response;
byte[] imageAsBytes = (byte[])peopleImage.Response;
p.PictureImageSource = ImageSource.FromStream(() => new MemoryStream(imageAsBytes));
TempImage = ImageSource.FromStream(() => new MemoryStream(imageAsBytes));
}
}
OnPropertyChanged();
-
public class PersonViewModel : INotifyPropertyChanged
{
public WorkstationViewModel WorkstationDetail { get; set; }
public List<PointViewModel> Points { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get; set; }
public string Initials { get; set; }
public string Email { get; set; }
public string ID { get; set; }
public string Department { get; set; }
public string BuildingName { get; set; }
public string SiteID { get; set; }
public string BuildingID { get; set; }
public string FloorNumber { get; set; }
public string FloorID { get; set; }
public string Workstation { get; set; }
public string Title { get; set; }
public string Phone { get; set; }
public byte[] Picture { get; set; }
public ImageSource PictureImageSource { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
Apineda was correct in thinking the listview wasn't refreshing at all with the new data. I separated the two API calls into two different methods (not sure if this part is entirely necessary). After the completion of the 2nd call, I set the listview's ItemSource to null, then back to the Results value, forcing a refreshing. Now the images show.
searchGestureRecognizer.Tapped += async (s, e) => {
await _viewModel.GetResults();
await _viewModel.GetImagesForResults();
resultsListView.ItemsSource = null;
resultsListView.ItemsSource = _viewModel.Results;
};

Resources