How to fix .Exception: 'Custom pin not found for specific pins - c#

Please help me with this issue.
I was making a custom renderer in xamarin using this article:
Xamarin Form Custom Renderer
Everything worked fine until I made the pin information into a JSON file.
So basically now the LAT, LNG, label, name and URL were stored in a JSON file instead of a C# file.
For testing, I had made 3 temporary pins. But only 1 of them shows the custom rendered window. When I click the other 2 pins an exception occurs as custom pin not found. But the custom pin is found for the last pin but not the 1st and 2nd pin which confuses me.
My code:
JSON file:
[
{"Label" :"Country1",
"Address":"A multine paragraph",
"Lat":"-12",
"Lng":"14",
"Name":"Xamarin",
"Url": "http://xamarin.com/about/"
},
{ "Label" :"Country2",
"Address":"Multiline paragraph",
"Lat":"-25",
"Lng":"45",
"Name":"Xamarin",
"Url": "http://xamarin.com/about/"
},
{ "Label" :"Country3",
"Address":"Multiline paragraph",
"Lat":"-5",
"Lng":"45",
"Name":"Xamarin",
"Url": "http://xamarin.com/about/"
}
]
MapPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Newtonsoft.Json;
using System.IO;
using Xamarin.Forms.Xaml;
using System.Reflection;
namespace Orbage
{
public partial class MapPage : ContentPage
{
public MapPage()
{
CustomMap customMap = new CustomMap
{
MapType = MapType.Hybrid
};
Content = customMap;
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(MapPage)).Assembly;
Stream stream = assembly.GetManifestResourceStream("Orbage.Mydata.json");
string json = "";
using (var reader = new System.IO.StreamReader(stream))
{
json = reader.ReadToEnd();
}
var places = JsonConvert.DeserializeObject<List<Mydata>>(json);
List<CustomPin> custompinList = new List<CustomPin>();
foreach (var place in places)
{
CustomPin pin = new CustomPin
{
Type = PinType.Place,
Position = new Position(Double.Parse(place.Lat), Double.Parse(place.Lng)),
Label = place.Label,
Address = place.Address,
Name = place.Name,
Url = place.Url
};
customMap.Pins.Add(pin);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
customMap.CustomPins = custompinList;
}
}
}
public class Mydata
{
public string Label { get; set; }
public string Address { get; set; }
public string Lat { get; set; }
public string Lng { get; set; }
public string Name { get; set; }
public string Url { get; set; }
}
}
CustomPin:
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms.Maps;
namespace Orbage
{
public class CustomPin : Pin
{
public string Name { get; set; }
public string Url { get; set; }
public string Adress { get; set; }
public string Lat { get; set; }
public string Lng { get; set; }
}
}
CustomMap:
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms.Maps;
namespace Orbage
{
public class CustomMap : Map
{
public List<CustomPin> CustomPins { get; set; }
}
}
CustomMapRenderer.cs:
using System;
using System.Collections.Generic;
using Android.Content;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Widget;
using ----;
using ----.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.Android;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace ----.Droid
{
public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter
{
List<CustomPin> customPins;
public CustomMapRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
customPins = formsMap.CustomPins;
}
}
protected override void OnMapReady(GoogleMap map)
{
base.OnMapReady(map);
NativeMap.InfoWindowClick += OnInfoWindowClick;
NativeMap.SetInfoWindowAdapter(this);
}
protected override MarkerOptions CreateMarker(Pin pin)
{
var marker = new MarkerOptions();
marker.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
marker.SetTitle(pin.Label);
marker.SetSnippet(pin.Address);
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));
return marker;
}
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPin(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (!string.IsNullOrWhiteSpace(customPin.Url))
{
var url = Android.Net.Uri.Parse(customPin.Url);
var intent = new Intent(Intent.ActionView, url);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}
public Android.Views.View GetInfoContents(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = GetCustomPin(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (customPin.Name.Equals("Xamarin"))
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}
public Android.Views.View GetInfoWindow(Marker marker)
{
return null;
}
CustomPin GetCustomPin(Marker annotation)
{
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Position == position)
{
return pin;
}
}
return null;
}
}
}
Thanks for seeing this and I hope this get's answered and someone with the same error gets it fixed.
:)
I tried debugging and here is a image of what somewhat might help:

foreach (var place in places)
{
CustomPin pin = new CustomPin
{
Type = PinType.Place,
Position = new Position(Double.Parse(place.Lat), Double.Parse(place.Lng)),
Label = place.Label,
Address = place.Address,
Name = place.Name,
Url = place.Url
};
customMap.CustomPins = new List<CustomPin> { pin }; //this will cause your customMap.CustomPins always has only the last custompin.
customMap.Pins.Add(pin);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
}
The issue is here,you add the customMap.CustomPins inside the loop,so it always has only the third CustomPin.
Try to move it out of the foreach:
List<CustomPin> custompinList = new List<CustomPin>();
foreach (var place in places)
{
CustomPin pin = new CustomPin
{
Type = PinType.Place,
Position = new Position(Double.Parse(place.Lat), Double.Parse(place.Lng)),
Label = place.Label,
Address = place.Address,
Name = place.Name,
Url = place.Url
};
custompinList.Add(pin);
customMap.Pins.Add(pin);
customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
}
customMap.CustomPins = custompinList;
Update the effect like below:

Related

Specified cast is not valid - Xamarin Forms

So I am trying to navigate to a content page that is supposed to have all the movie details from the movie the user selects in the collection view but every time I select a movie in my collection view the error "Specified cast is not valid", which occurs at the Navigation.PushAsync(new MovieDetails((MovieData)e.CurrentSelection)); line, pops up.
I'm very new to C# and using Xamarin forms so I'm not sure if this is the right way to be doing things.
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using Listly.Models;
using Xamarin.Forms;
namespace Listly
{
public partial class SearchPage : ContentPage
{
public ObservableCollection<MovieData> allMovies = new ObservableCollection<MovieData>();
public int NumClicked { get; set; }
public bool BtnClicked = false;
public string Poster_Path_End { get; set; }
public MovieList newList = new MovieList();
public SearchPage()
{
InitializeComponent();
contentPage.BackgroundColor = Color.FromHex("1D1D1D");
searchBtn.BackgroundColor = Color.FromHex("28D7B5");
searchBtn.TextColor = Color.FromHex("1D1D1D");
searchBar.PlaceholderColor = Color.FromHex("A0A0A0");
searchBar.TextColor = Color.Black;
collectionView.SelectionMode = SelectionMode.Single;
collectionView.ItemsSource = allMovies;
collectionView.SelectionChanged += CollectionView_SelectionChanged;
searchBtn.Clicked += SearchBtn_Clicked;
}
private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.CurrentSelection != null)
{
Navigation.PushAsync(new MovieDetails((MovieData)e.CurrentSelection));
}
}
private async void SearchBtn_Clicked(object sender, EventArgs e)
{
if (BtnClicked == false)
{
BtnClicked = true;
NumClicked += 1;
DataManager dataManager = new DataManager(searchBar.Text);
dataManager.GetMovie(searchBar.Text);
newList = await dataManager.GetMovie(searchBar.Text);
foreach (var movie in newList.searchList)
{
if (movie.Title == null)
{
bool answer = await DisplayAlert("Movie Not Found", "The movie searched was not found. Please try again.", "Okay", "Cancel");
searchBar.Text = "";
searchBar.Placeholder = "Enter Movie Name";
break;
}
allMovies.Add(movie);
}
}
else if (BtnClicked == true)
{
if (NumClicked == 1 || NumClicked > 1)
{
allMovies.Clear();
DataManager dataManager = new DataManager(searchBar.Text);
newList = await dataManager.GetMovie(searchBar.Text);
foreach (var movie in newList.searchList)
{
if (movie.Title == null)
{
bool answer = await DisplayAlert("Movie Not Found", "The movie searched was not found. Please try again.", "Okay", "Cancel");
break;
}
allMovies.Add(movie);
}
}
}
collectionView.ItemsSource = allMovies;
}
protected override void OnAppearing()
{
base.OnAppearing();
collectionView.ItemsSource = allMovies;
}
}
}
Here's the MovieDetails page
using System;
using System.Collections.Generic;
using Listly.Models;
using Xamarin.Forms;
namespace Listly
{
public partial class MovieDetails : ContentPage
{
public MovieData details = new MovieData();
public MovieData selectedMovie = new MovieData();
public string Poster_Path_End { get; set; }
public MovieDetails(MovieData selectedMovie)
{
InitializeComponent();
details = selectedMovie;
details.Title = selectedMovie.Title;
details.Overview = selectedMovie.Overview;
}
}
}
As Jason said,
CurrentSelection – the list of items that are selected, after the
selection change.
So you could set SelectionMode to Single,then use SelectedItem.
or do like this:
MovieData movie = e.CurrentSelection.FirstOrDefault() as MovieData ;
Navigation.PushAsync(new MovieDetails(movie);
the more you could look at CollectionView Selection.

ASP.Net ElasticSearch

Hello so I am trying to code a simple web view, with asp.net and NEST library, that will take my ElasticSearch database, and show it in textview on button click.
This is the code that I input when my button is clicked,
would you please look at it and tell me am I on a good path or something is not good.
using Elasticsearch.Net;
using Nest;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ElasticsearchWeb
{
public class shekspir
{
public string type { get; set; }
public int line_id { get; set; }
public string play_name { get; set; }
public int speech_number { get; set; }
public float line_number { get; set; }
public string speaker { get; set; }
public string text_entry { get; set; }
}
public partial class Default : System.Web.UI.Page
{
public static Uri GetElasticHost()
{
var host = "http://localhost:9200";
return new Uri(host);
}
public static ElasticClient GetElasticClient(ConnectionSettings settings = null)
{
if (settings == null)
{
var node = GetElasticHost();
var pool = new SingleNodeConnectionPool(node);
settings = new ConnectionSettings(pool);
}
settings.DisableDirectStreaming(true);
var client = new ElasticClient(settings);
return client;
}
public static List<shekspir> GetAllShekspir(int ID)
{
var workОfShakespeare = GetElasticClient();
ISearchResponse<shekspir> result = null;
result = workОfShakespeare.Search<shekspir>(x => x
.Index("shekspir")
.Query(q => q
.MatchAll())
.Size(100)
);
List<shekspir> list = new List<shekspir>();
foreach (var r in result.Hits)
{
shekspir a = r.Source;
list.Add(a);
}
return list;
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
List<shekspir> list = GetAllShekspir (1);
foreach (shekspir u in list)
{
litInfo.Text += u.play_name + ": " + u.text_entry + "<br>";
}
}
}
}
List<shekspir> list = new List<shekspir>();
foreach (var r in result.Hits)
{
shekspir a = r.Source;
list.Add(a);
}
If you just want the returned documents above can be replaced by
var list= result.Documents

Way to build tree from list of path strings

I have the following list of ContentData objects (see below the class structure):
Name = "Path1\\Path2\\Path3\\File0", Size = 110
Name = "Path1\\Path2\\Path4\\File1", Size = 112
Name = "Path1\\Path2\\Path4\\File2", Size = 22222
Name = "Path1\\Path5\\File3", Size = 2312313
Name = "Path6", Size = 0
I want to build a tree which should look like:
Path1
-> Path2
-> Path3
-> File0
-> Path4
-> File1
-> File2
-> Path5
-> File3
Path6
I tried:
public static IEnumerable<TreeDataModel> GetTree(this IEnumerable<ContentData> dataList, Func<ContentData, string> nameSelector, string root = null)
{
var enumerable = root != null ? dataList.Where(data => nameSelector(data).Equals(root)) : dataList;
foreach (var data in enumerable)
{
var split = data.Name.Split('\\');
if (split.Length > 1)
{
yield return new TreeDataModel(split[0], "", dataList.GetTree(nameSelector, string.Join("\\", split.Skip(1))));
}
else
{
yield return new TreeDataModel(split[0], "", null);
}
}
}
and ContentData contains
public string Name { get; set; }
public long Size { get; set; }
and TreeDataModel
public sealed class TreeDataModel
{
public TreeDataModel(string title, string path, IEnumerable<TreeDataModel> children)
{
Title = title;
Path = path;
Children = children;
}
public string Title { get; }
public string Path { get; }
public IEnumerable<TreeDataModel> Children { get; }
}
I'm stucked at extension and I don't know how to achieve the results.
Means that the results I got now is that appears multiple times same first part before \
Try code like below :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication54
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
List<ContentData> data = new List<ContentData>() {
new ContentData("Path1\\Path2\\Path3\\File0", 110),
new ContentData("Path1\\Path2\\Path4\\File1", 112),
new ContentData("Path1\\Path2\\Path4\\File2", 22222),
new ContentData("Path1\\Path5\\File3", 2312313),
new ContentData("Path6", 0)
};
CreateTreeRecursive(data, null, 0);
treeView1.ExpandAll();
}
public void CreateTreeRecursive(List<ContentData> data, TreeNode node, int index)
{
var groupData = data.Where(x => x.splitName.Length > index).GroupBy(x => x.splitName[index]).ToList();
foreach (var group in groupData)
{
TreeNode newNode = new TreeNode(group.Key);
if (node == null)
{
treeView1.Nodes.Add(newNode);
}
else
{
node.Nodes.Add(newNode);
}
CreateTreeRecursive(group.ToList(), newNode, index + 1);
}
}
}
public class ContentData
{
public string Name { get; set; }
public string[] splitName { get; set; }
public int Size { get; set; }
public ContentData(string name, int size)
{
Name = name;
Size = size;
splitName = name.Split(new char[] {'\\'}).ToArray();
}
}
}

How to read JSON Object Array with Xamarin Android Newtonsoft.Json

Hello guys I have an app that I'm trying to get a Json Array response and put it into a TextView, but it has 5 Counts and I don't know how to use a for to read each field of the JsonArray here is the code:
using System;
using Android.App;
using Android.Widget;
using Android.OS;
using RestSharp;
using Newtonsoft.Json;
using Android.Util;
using App4.Resources;
using Newtonsoft.Json.Linq;
using Org.Json;
using System.Net;
using System.IO;
using System.Collections.Generic;
namespace App4
{
[Activity(Label = "App4", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
EditText edtcpf;
Button btnConsumer;
TextView txtcpf;
RestRequest cpf { get; set; }
public RestClient consumer { get; set; }
IRestResponse mensagemConsumer;
TextView txtsobrenome;
RestClient orderId { get; set; }
RestRequest requestorderId { get; set; }
IRestResponse answerorder { get; set; }
TextView txtnome;
TextView txtorder;
TextView txtmensagem;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
btnConsumer = FindViewById<Button>(Resource.Id.btnConsumer);
edtcpf = FindViewById<EditText>(Resource.Id.edtcpf);
txtcpf = FindViewById<TextView>(Resource.Id.txtcpf);
txtsobrenome = FindViewById<TextView>(Resource.Id.txtresposta);
txtnome = FindViewById<TextView>(Resource.Id.txtNome);
txtorder = FindViewById<TextView>(Resource.Id.txtorder);
txtmensagem = FindViewById<TextView>(Resource.Id.txtMensagem);
btnConsumer.Click += BtnConsumer_Click;
}
private void BtnConsumer_Click(object sender, EventArgs e)
{
try
{
// API Consumer CPF
consumer = new RestClient("https://qa.api-latam.whirlpool.com/v1.0/consumers");
cpf = new RestRequest("/" + edtcpf.Text, Method.GET);
cpf.AddHeader("Content-Type", "application/json; charset=utf-8");
cpf.AddHeader("Authorization", "Bearer 70197e6c-d81b-384c-bb32-d69e8c10b101");
mensagemConsumer = consumer.Execute(cpf);
Pessoa pessoa = JsonConvert.DeserializeObject<Pessoa>(mensagemConsumer.Content);
txtnome.Text = "Nome: " +pessoa.firstName;
txtsobrenome.Text = "Sobrenome: "+ pessoa.lastName;
// API Consumer Appliances
orderId = new RestClient("https://qa.api-latam.whirlpool.com/v1.0/consumers/");
requestorderId = new RestRequest("/"+ edtcpf.Text+ "/service-orders", Method.GET);
requestorderId.AddHeader("Content-Type", "application/json; charset=utf-8");
requestorderId.AddHeader("Authorization", "Bearer 70197e6c-d81b-384c-bb32-d69e8c10b101");
answerorder = orderId.Execute(requestorderId);
var requestToken = JsonConvert.DeserializeObject<RootObject>(answerorder.Content);
var parse = JObject.Parse(answerorder.Content);
var QtdeItens = parse.Count;
var end = "";
/*foreach (Dictionary<string, Order2> kvp in Order)
{
txtorder.Text = "Id: " + kvp.Value.orderId;
}*/
}
catch (Exception)
{
throw;
}
}
}
}
I created a class on http://json2csharp.com/ and here is the class that I'm using to get the values. The JSON answer depoends on the Id number that the person set, so it can be diferent every time I did this test using the ID 181.299.668-32
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Newtonsoft.Json;
public class Order2
{
public object orderId { get; set; }
public string orderStatusCode { get; set; }
public string orderStatusDescription { get; set; }
public int serviceProviderId { get; set; }
public string orderOpeningDate { get; set; }
public string orderSchedulingDate { get; set; }
public string orderSchedulingPeriod { get; set; }
public object orderSettlementDate { get; set; }
public object orderCancellationDate { get; set; }
}
public class Order
{
public Order2 order { get; set; }
}
public class RootObject
{
public List<Order> orders { get; set; }
}
So the answer that the json returns is :
{"orders":[{"order":{"orderId":7004093603,"orderStatusCode":"CANC","orderStatusDescription":"Cancelado","serviceProviderId":3649,"orderOpeningDate":"2015-07-07","orderSchedulingDate":"2015-07-18","orderSchedulingPeriod":"M","orderSettlementDate":null,"orderCancellationDate":null}},{"order":{"orderId":7004153791,"orderStatusCode":"AGEN","orderStatusDescription":"Agendado","serviceProviderId":3524,"orderOpeningDate":"2016-08-31","orderSchedulingDate":"2016-09-01","orderSchedulingPeriod":"M","orderSettlementDate":null,"orderCancellationDate":null}},{"order":{"orderId":7004156972,"orderStatusCode":"ABRT","orderStatusDescription":"Aberto","serviceProviderId":30820,"orderOpeningDate":"2017-04-13","orderSchedulingDate":null,"orderSchedulingPeriod":null,"orderSettlementDate":null,"orderCancellationDate":null}},{"order":{"orderId":7002178478,"orderStatusCode":"CANC","orderStatusDescription":"Cancelado","serviceProviderId":3555,"orderOpeningDate":"2014-02-22","orderSchedulingDate":"2014-02-24","orderSchedulingPeriod":"M","orderSettlementDate":null,"orderCancellationDate":null}},{"order":{"orderId":7002118317,"orderStatusCode":"CANC","orderStatusDescription":"Cancelado","serviceProviderId":3555,"orderOpeningDate":"2014-02-10","orderSchedulingDate":"2014-02-15","orderSchedulingPeriod":"M","orderSettlementDate":null,"orderCancellationDate":null}}]}
And JsonViewer said that it has 5 counts, so how can I do a for or foreach to read the orderId, orderStatus code, orderStatusDescription and orderOpeningDate because dependiing on the Id it has from 0 to 10 counts
[EDIT]
Using the method:
foreach (var order in requestToken.orders)
{
object vader = order.order.orderId;
string darth = Convert.ToString(vader);
txtorder.Text = darth;
txtorder.Text = order.order.orderStatusDescription;
txtorder.Text = order.order.orderStatusCode.;
}
It returned one orderId :) . My doubt is: it's calling the orderId of the count 0 automatically how can I call the others orderIds? Is it like this?
foreach (var order in requestToken.orders)
{
//for (var i = 0; i < requestToken.orders.Count; i++)
//{
object vader = order.order.orderId[1], [2], etc;
string darth = Convert.ToString(vader);
txtorder.Text = darth;
txtorder.Text = order.order.orderStatusDescription;
txtorder.Text = order.order.orderStatusCode.;
//}
Thank you guys for helping me
You need to Deserialize JSON string
var data = JsonConvert.DeserializeObject<RootObject>(jsonString);
Then run foreach loop
foreach(var orders in data)
{
var Id = orders.order.orderId;
///and so on...
}
You can access the values like this:
var test = JsonConvert.DeserializeObject<Rootobject>(json);
var orderIds = new List<long>();
foreach (var order in test.orders)
{
var vader = order.order.orderId;
orderIds.Add(vader);
}
Note that the orderIds are overwritten to the vader variable in each iteration of the loop. If you want to keep them, you need a collection (a list named orderIds in my example) and in each iteration you add to that collection. Finally all the orderIds will be in orderIds.

read column names from sqlite table windows 8 app

I am using SQLite for a data entry windows 8 app I am working on. I can create the db, insert data, retrieve a column count, and read data, but cannot get the column names.
The underlying framework is from this post.
I read about the PRAGMA table_info(table_name); command but I cannot seem to send and read back this query properly. I have been googling for 3 days!
MainPage.xaml.cs:
using SQLite;
using SqlLiteTest.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Windows.Storage;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace SqlLiteTest
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
txtPath.Text = ApplicationData.Current.LocalFolder.Path;
}
private async void createDB(object sender, RoutedEventArgs e)
{
// access local folder
var qvLocalFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
try
{
//Create a blank carrier file
StorageFile qvLocalFileCarrier = await qvLocalFolder.CreateFileAsync("qvdbLocal.db", CreationCollisionOption.FailIfExists);
//Write the blank carrier file
await FileIO.WriteTextAsync(qvLocalFileCarrier, "");
}
catch { }
// connect
var path = Windows.Storage.ApplicationData.Current.LocalFolder.Path + #"\qvdbLocal.db";
var db = new SQLiteAsyncConnection(path);
// create table
await db.CreateTableAsync<qvdb>();
// insert data
var insertRecords = new List<qvdb>()
{
new qvdb
{
qvdbRecord = 1,
qvdbNotes = "Notes1",
qvdb001 = "Variable 1.1",
qvdb002 = "Variable 2.1"
},
new qvdb
{
qvdbRecord = 1,
qvdbNotes = "Notes1",
qvdb001 = "Variable 1.1",
qvdb002 = "Variable 2.1"
},
new qvdb
{
qvdbRecord = 1,
qvdbNotes = "Notes1",
qvdb001 = "Variable 1.1",
qvdb002 = "Variable 2.1"
},
};
await db.InsertAllAsync(insertRecords);
// read count
var allUsers = await db.QueryAsync<qvdb>("SELECT * FROM qvdb");
var count = allUsers.Any() ? allUsers.Count : 0;
Debug.WriteLine(count);
}
private async void updateDB(object sender, RoutedEventArgs e)
{
var path = Windows.Storage.ApplicationData.Current.LocalFolder.Path + #"\qvdbLocal.db";
var db = new SQLiteAsyncConnection(path);
var tempCell = db.QueryAsync<qvdb>("UPDATE qvdb SET qvdbNotes ='!##$%$%^^&*()+)(*&^%$##!{:L<>?' WHERE qvdbRecord = 10");
await db.UpdateAsync(tempCell);
}
private async void readDB(object sender, RoutedEventArgs e)
{
var path = Windows.Storage.ApplicationData.Current.LocalFolder.Path + #"\qvdbLocal.db";
var db = new SQLiteAsyncConnection(path);
var query = db.Table<qvdb>();
var result = await query.ToListAsync();
foreach (var item in result)
{
MessageDialog dialog = new MessageDialog(string.Format("{0} {1} {2}", item.qvdbRecord, item.qvdbNotes, item.qvdb001));
await dialog.ShowAsync();
}
}
private void readColNames(object sender, RoutedEventArgs e)
{
}
}
}
qvdb.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SQLite;
namespace SqlLiteTest.Model
{
public class qvdb
{
[PrimaryKey, AutoIncrement]
public int qvdbRecord { get; set; }
[MaxLength(3000)]
public string qvdbNotes { get; set; }
[MaxLength(1000)]
public string qvdb001 { get; set; }
[MaxLength(1000)]
public string qvdb002 { get; set; }
}
}
Thanks CL for the info. I added the class but still do not know how to access them. Some more code...
// this works
// read record count
var allRecords = await db.QueryAsync<qvdb>("SELECT * FROM qvdb");
var countRecords = allRecords.Any() ? allRecords.Count : 0;
this.textboxLog.Text = this.textboxLog.Text + Environment.NewLine + "There are " + countRecords + " records.";
// ??
// read column names
var allColumns = await db.QueryAsync<qvdb>("PRAGMA table_info(qvdb)");
foreach (var item in allColumns) {
//read name
this.textboxLog.Text = this.textboxLog.Text + Environment.NewLine + "columbn names";
}
The records returned by PRAGMA table_info look like this:
public class table_info_record
{
public int cid { get; set; }
public string name { get; set; }
public string type { get; set; }
public int notnull { get; set; }
public string dflt_value { get; set; }
public int pk { get; set; }
}
Use it like this:
db.QueryAsync<table_info_record>("PRAGMA table_info(...)");
o end the loop on CL's advice, this code successfully reads the column names:
// read column names
var query = await db.QueryAsync<table_info_record>("PRAGMA table_info(MY_TABLE_NAME_HERE)");
foreach (var item in query)
{
Debug.WriteLine(string.Format("{0}", item.name) + " is a column.");
}

Categories