Bing API Query Callback to Observable Collection - c#

Created a Windows Store App using some info found on this post: How do I use the Bing Search API in Windows Phone?
Goal
Textbox - Type any term
Search Button - Searches that term and populates a GridView of pictures retrieved with the Bing API
Problem
I get the pictures, and they are received via my "OnQueryComplete" callback, but I can't figure out what the correct way to populate the collection would be. Since I can't figure out how to await this call, I (just to see if I could get it working, which it does) added a while loop (which you can probably see the issues with). What would be the correct way to do this? How do you handle callbacks for populating the GridView and having it wait until it's finished?
Current ViewModel Code
public bool itemsFinished = false;
private ObservableCollection<SearchResult> _ImageResults;
public ObservableCollection<SearchResult> ImageResults {
get {
if (_ImageResults == null) {
while (!itemsFinished) {
int i = 0;
i++;
}
}
return _ImageResults;
}
set {
_ImageResults = value;
}
}
public SearchResultViewModel() {
GetPictures("dogs");
}
public void GetPictures(string searchTerm) {
// This is the query - or you could get it from args.
string query = searchTerm;
// Create a Bing container.
string rootUri = "https://api.datamarket.azure.com/Bing/Search";
var bingContainer = new Bing.BingSearchContainer(new Uri(rootUri));
// Replace this value with your account key.
var accountKey = "myaccountkey";
// Configure bingContainer to use your credentials.
bingContainer.Credentials = new NetworkCredential(accountKey, accountKey);
// Build the query.
var imageQuery = bingContainer.Image(query, null, null, null, null, null, null);
imageQuery.BeginExecute(OnQueryComplete, imageQuery);
// var imageResults = imageQuery.Execute();
}
private void OnQueryComplete(IAsyncResult result) {
// ImageResults.Clear();
_ImageResults = new ObservableCollection<SearchResult>();
var query = (DataServiceQuery<ImageResult>)result.AsyncState;
var enumerableResults = query.EndExecute(result);
int i = 0;
foreach (var item in enumerableResults) {
SearchResult myResult = new SearchResult();
myResult.Title = item.Title;
myResult.ImageUri = new Uri(item.MediaUrl);
ImageResults.Add(myResult);
i++;
if (i >= 14) {
break;
}
}
itemsFinished = true;
}

Please excuse any syntax errors, I'm without a Visual Studio instance right now.
The problem I see is that you reset your ObservableCollection when you receive content.
Try it as follows:
private ObservableCollection<SearchResult> _ImageResults;
public ObservableCollection<SearchResult> ImageResults {
get
{
return _ImageResults;
}
set {
_ImageResults = value;
}
}
public SearchResultViewModel() {
_ImageResults = new ObservableCollection<SearchResult>(); // Just create it once.
GetPictures("dogs");
}
private void OnQueryComplete(IAsyncResult result) {
_ImageResults.Clear(); // Clear isn't bad, that way you keep your reference to your original collection!
//_ImageResults = new ObservableCollection<SearchResult>(); // We already have one. ObservableCollection works best if you keep on working with the collection you have.
var query = (DataServiceQuery<ImageResult>)result.AsyncState;
var enumerableResults = query.EndExecute(result);
int i = 0;
foreach (var item in enumerableResults) {
SearchResult myResult = new SearchResult();
myResult.Title = item.Title;
myResult.ImageUri = new Uri(item.MediaUrl);
ImageResults.Add(myResult);
i++;
if (i >= 14) {
break;
}
}
}
As far as I see (can't test sadly) this should work, provided you have bound your ObservableCollection the right way in your xaml.

Related

Can't update SalesReceipt in Quickbooks desktop

I'm using QuickBooks Integrator from /nSoftware to integrate with QuickBooks Desktop
I'm trying to update an invoice and I don't get any errors but when I check in QuickBooks I see that nothing changed and it didn't actually get updated.
First I try to lookup the invoice based on the RefNumber and if it found an Invoice then I try to replace the Line Items and then i call the update method like this existingInvoice.Update();
Here's my code sample:
public static List<Invoice> FindInvoice(string refNumber)
{
var invoicesSearch = new Objsearch
{
QueryType = ObjsearchQueryTypes.qtInvoiceSearch,
RuntimeLicense = "MYLICENSEKEY",
QBConnectionString = "MYCONNECTIONSTRINGTOREMOTECONNECTOR",
SearchCriteria = new SearchCriteria
{
RefNumberContains = refNumber
},
};
invoicesSearch.Search();
var qbInvoiceList = invoicesSearch.Results.ToList();
var invoiceObjList = new List<Invoice>();
foreach (var inv in qbInvoiceList)
{
var newInv = new Invoice();
newInv.QBResponseAggregate = inv.Aggregate;
invoiceObjList.Add(newInv);
}
return invoiceObjList.FirstOrDefault();
}
public static void PutInvoice(Invoice invoice)
{
var existingInvoice = FindInvoice(invoice.RefNumber);
if (existingInvoice != null)
{
existingInvoice.LineItems.Clear();
existingInvoice.LineItems.AddRange(invoice.LineItems);
existingInvoice.QBConnectionString = "MYCONNECTIONSTRINGTOREMOTECONNECTOR";
existingInvoice.RuntimeLicense = RuntimeLicense;
existingInvoice.QBXMLVersion = "12.0";
existingInvoice.Update(); //this line
}
}
Okay, so the issue was that I was setting the QBXMLVersion the last thing before updating.
In order for the Update() to process successfully the QBXMLVersion needs to be set the first thing.
Here's an updated working example:
public static void PutInvoice(Invoice invoice)
{
var existingInvoice = FindInvoice(invoice.RefNumber);
if (existingInvoice != null)
{
existingInvoice.QBXMLVersion = "12.0";
existingInvoice.RuntimeLicense = "MyRuntimeLicenseKey";
existingInvoice.QBConnectionString = "MYCONNECTIONSTRINGTOREMOTECONNECTOR";
existingInvoice.LineItems.Clear();
existingInvoice.LineItems.AddRange(invoice.LineItems);
existingInvoice.Update();
}
}

How to add data from Firebase to DataGridView using FireSharp

I just want to retrieve data from a Firebase to DataGridView. The code I have is retrieving data already, however, it's retrieving everything to the same row instead of creating a new one. I'm a beginner in coding, so I really need help with that.
I read online that Firebase doesn't "Count" data, so it'd be needed to create a counter, so each time I add or delete data, an update would be needed. I did it and it's working. I created a method to load the data.
private async Task firebaseData()
{
int i = 0;
FirebaseResponse firebaseResponse = await client.GetAsync("Counter/node");
Counter_class counter = firebaseResponse.ResultAs<Counter_class>();
int foodCount = Convert.ToInt32(counter.food_count);
while (true)
{
if (i == foodCount)
{
break;
}
i++;
try
{
FirebaseResponse response2 = await client.GetAsync("Foods/0" + i);
Foods foods = response2.ResultAs<Foods>();
this.dtGProductsList.Rows[0].Cells[0].Value = foods.menuId;
this.dtGProductsList.Rows[0].Cells[1].Value = foods.name;
this.dtGProductsList.Rows[0].Cells[2].Value = foods.image;
this.dtGProductsList.Rows[0].Cells[3].Value = foods.price;
this.dtGProductsList.Rows[0].Cells[4].Value = foods.discount;
this.dtGProductsList.Rows[0].Cells[5].Value = foods.description;
}
catch
{
}
}
MessageBox.Show("Done");
}
OBS: A DataTable exists already(dataTable), there's a DataGridView too which has columns(ID,Name, Image, Price, Discount, Description), which match the number and order given to the .Cells[x]. When the Form loads, dtGProductsList.DataSource = dataTable; I tried replacing [0] for [i].
I expect the data that is beeing retrieved to be set to a new row and not to the same, and to not skip rows. I'm sorry if it's too simple, but I can't see a way out.
I Faced the same problem and here is mu solution :
Counter_class XClass = new Counter_class();
FirebaseResponse firebaseResponse = await client.GetAsync("Counter/node");
string JsTxt = response.Body;
if (JsTxt == "null")
{
return ;
}
dynamic data = JsonConvert.DeserializeObject<dynamic>(JsTxt);
var list = new List<XClass >();
foreach (var itemDynamic in data)
{
list.Add(JsonConvert.DeserializeObject<XClass >
(((JProperty)itemDynamic).Value.ToString()));
}
// Now you have a list you can loop through to put it at any suitable Visual
//control
foreach ( XClass _Xcls in list)
{
Invoke((MethodInvoker)delegate {
DataGridViewRow row(DataGridViewRow)dg.Rows[0].Clone();
row.Cells[0].Value =_Xdcls...
row.Cells[1].Value =Xdcls...
row.Cells[2].Value =Xdcls...
......
dg.Insert(0, row);
}

How can I pass a function with one parameter to an ICommand?

Here's my ICommand:
public ICommand ConfirmLotSavedCommand {
get
{
return new RelayCommand(ConfirmLotSaved);
}
}
The problem is I have deserialized data that I want to store into database after a user clicks confirm button. If the user does not click on confirm or the lot number already exists, then I don't want to save the deserialized string in db.
I had trouble calling a function with one parameter inside my ConfirmLotSaved() method because of scope.
So I created a set the deserialized lot as a field and put the code to save to db inside of ConfirmLotSaved(). However, the field is null for some strange reason... I'm not sure why.
Here's my attempt:
private LotInformation lot; //field that is supposed to contain all the deserialized info
private void ConfirmLotSaved()
{
using (var db = new DDataContext())
{
bool lotNumDbExists = db.LotInformation.Any(r => r.lot_number == DeserialLotNumber);
if (lotNumDbExists == false)
{
successWindow.Message = "Successfully Saved Lot";
dialogService.ShowDialog(successWindow.Message, successWindow);
LotInformation newLot = new LotInformation();
if (newLot != null)
{
newLot.Id = lot.Id;
newLot.lot_number = lot.lot_number;
newLot.exp_date = lot.exp_date;
LotNumber = Lot.lot_number;
ExpirationDate = Lot.exp_date.ToString();
foreach (Components comp in lot.Components)
{
newLot.Components.Add(comp);
}
ComponentsList = newLot.Components;
foreach (Families fam in lot.Families)
{
newLot.Families.Add(fam);
}
FamiliesList = newLot.Families;
try
{
db.LotInformation.Add(newLot);
db.SaveChanges();
//Grabs the lot_number column from db that is distinct
var lotNum = db.LotInformation.GroupBy(i => i.lot_number).Select(group => group.FirstOrDefault());
//Loops through the lot numbers column in db and converts to list
foreach (var item in lotNum)
{
Console.WriteLine(item.lot_number);
}
LotNumList = lotNum.ToList();
Console.WriteLine("successfully");
}
catch
{
//TODO: Add a Dialog Here
}
}
else if (lotNumDbExists == true)
{
// Inform user that the lot_number already exists
errorWindow.Message = LanguageResources.Resource.Lot_Exists_Already;
dialogService.ShowDialog(LanguageResources.Resource.Error, errorWindow);
logger.writeErrLog(LanguageResources.Resource.Lot_Exists_Already);
return;
}
}
}
}
Deserialization function to see where lot is grabbing data:
public void DeserializedStream(string filePath)
{
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "lot_information";
xRoot.IsNullable = false;
// Create an instance of lotinformation class.
LotInformation lot = new LotInformation();
// Create an instance of stream writer.
TextReader txtReader = new StreamReader(filePath);
// Create and instance of XmlSerializer class.
XmlSerializer xmlSerializer = new XmlSerializer(typeof(LotInformation), xRoot);
// DeSerialize from the StreamReader
lot = (LotInformation)xmlSerializer.Deserialize(txtReader);
// Close the stream reader
txtReader.Close();
LotInformation newList = new LotInformation();
using (var db = new DDataContext())
{
bool isDuplicate = db.LotInformation.Any(r => r.lot_number == lot.lot_number);
if (newList != null && isDuplicate == false)
{
newList.Id = lot.Id;
newList.lot_number = lot.lot_number;
newList.exp_date = lot.exp_date;
DeserialLotNumber = newList.lot_number;
DeserialExpirationDate = newList.exp_date.ToString();
foreach (Component comp in lot.Components)
{
newList.Components.Add(comp);
}
DeserialComponentsList = newList.Components;
foreach (Families fam in lot.Families)
{
newList.Families.Add(fam);
}
DeserialFamiliesList = newList.Families;
}
else if (isDuplicate == true)
{
DeserialAnalytesList = null;
DeserialFamiliesList = null;
// Inform user that the lot_number already exists
errorWindow.Message = LanguageResources.Resource.Lot_Exists_Already;
dialogService.ShowDialog(LanguageResources.Resource.Error, errorWindow);
logger.writeErrLog(LanguageResources.Resource.Lot_Exists_Already);
return;
}
}
}
I figured out what was wrong:
After setting private LotInformation lot; field before constructor, I redeclared locally my mistake:
LotInformation lot = new LotInformation();
Changed it to:
lot = new LotInformation();
and it works.
I suggest you to use RelayCommand's generic edition http://www.kellydun.com/wpf-relaycommand-with-parameter/
It will allow you to pass lot to your command from view, all you need to store lot in current DataContext.

C# Creating a datasource that gets all branches for a specific bank

I am trying to create a binding source to my binding navigator that will be able to show all branches within a specific bank.
The statement that gets the datasource is as follows
branchMasterBindingSource.DataSource = Program.Kernel.Get<IBranchMasterService>().GetAllBranchMasters();
However, this pulls all branches regardless of the banks they belong to.
I need to know how to change this so that it gets AllBranchMasters where a field in the database ("U_bank_code") is equals to a combobox named "cb_bank_code"
Extra code is below:
private void cb_bank_code_SelectedIndexChanged(object sender, EventArgs e)
{
branchMasterBindingSource.DataSource = null;
branchMasterBindingSource.DataSource = Program.Kernel.Get<IBranchMasterService>().GetAllBranchMasters();
//clear textfields after input
lbl_show_bank_name.Text = string.Empty;
txt_branch_code.Text = string.Empty;
txt_branch_name.Text = string.Empty;
txt_swift_sort_code.Text = string.Empty;
txt_address_1.Text = string.Empty;
txt_address_2.Text = string.Empty;
txt_comments.Text = string.Empty;
var bankMasterService = Program.Kernel.Get<IBankMasterService>();
var bankMasters = from bm in bankMasterService.GetAllBankMasters()
where bm.U_Bank_code.Trim().Equals(cb_bank_code.Text.Trim(), StringComparison.CurrentCultureIgnoreCase)
select bm;
if (bankMasters.Any(x => x != null))
{
var bankMaster = bankMasters.First();
lbl_show_bank_name.Text = bankMaster.U_Bank_name;
CbBankCode = bankMaster.U_Bank_code;
}
else
{
//clear textfields after input
lbl_show_bank_name.Text = string.Empty;
}
Im new to C# and dot net and do not know how the syntax to change the statement. Any help appreciated
If I understand you correctly, and make a couple assumptions on the types, the following should work:
branchMasterBindingSource.DataSource = Program.Kernel.Get<IBranchMasterService>().GetAllBranchMasters.Where(x => x.U_Bank_code.Trim().Equals(cb_bank_code.Text.Trim(), StringComparison.CurrentCultureIgnoreCase))
I'm guessing the
Program.Kernel.Get<IBranchMasterService>().GetAllBranchMasters
returns an IEnumerable or perhaps List. There won't be much you can do about that function returning all banks/branches unless you either:
Change GetAllBranchMasters to return an IQueryable - you can then apply the filter as above and add .ToList() to the end to perform the query.
(Recommended) Create a second method that accepts a Bank Code, and returns the branches in accordance with the underlying DAL.
Although you should look at refactoring your data access methods to do the filtering something like this should do the trick for you
private void cb_bank_code_SelectedIndexChanged(object sender, EventArgs e)
{
ClearTextfieldsAfterInput();
branchMasterBindingSource.DataSource = GetSelectedBranchMasters();
var bankMasters = GetSelectedBankMaster();
if (bankMasters.Any(x => x != null))
{
var bankMaster = bankMasters.First();
lbl_show_bank_name.Text = bankMaster.U_Bank_name;
CbBankCode = bankMaster.U_Bank_code;
}
else
{
//clear textfields after input
lbl_show_bank_name.Text = string.Empty;
}
}
private IEnumerable<BankMaster> GetSelectedBankMaster()
{
var selectedBank = cb_bank_code.Text.Trim();
return Program.Kernel.Get<IBankMasterService>()
.GetAllBankMasters()
.Where(bm => bm.U_Bank_code.Trim().Equals(selectedBank, StringComparison.CurrentCultureIgnoreCase))
.ToList();
}
private IEnumerable<BranchMaster> GetSelectedBranchMasters()
{
var selectedBank = cb_bank_code.Text.Trim();
return Program.Kernel.Get<IBranchMasterService>()
.GetAllBranchMasters()
.Where(branch => string.Equals(branch.U_bank_code, selectedBank, StringComparison.CurrentCultureIgnoreCase))
.ToList();
}
private void ClearTextfieldsAfterInput()
{
lbl_show_bank_name.Text = "";
txt_branch_code.Text = "";
txt_branch_name.Text = "";
txt_swift_sort_code.Text = "";
txt_address_1.Text = "";
txt_address_2.Text = "";
txt_comments.Text = "";
}

Web service only let me get 1000 rows at a time but the total is over 30000

I am using some web services provided by Netsuite
https://system.netsuite.com/help/helpcenter/en_US/Output/Help/SuiteFlex/WebServices/STP_searchMore.html#1087957
It only let me get 1000 rows at a time and then I need to perform a second search for the next set of 1000 rows and so on. There's some example code but it only returns the second set of rows, I am not sure on how to get the third, fourth and so on.
My code so far is:
private void getAllCustomers()
{
// Instantiate a search object for customers.
CustomerSearch custSearch = new CustomerSearch();
CustomerSearchBasic custSearchBasic = new CustomerSearchBasic();
// Search the customer status which is a list field (16,13,15)
String statusKeysValue = "16,13,15";
SearchMultiSelectField status = null;
if (statusKeysValue != null && !statusKeysValue.Trim().Equals(""))
{
status = new SearchMultiSelectField();
status.#operator = SearchMultiSelectFieldOperator.anyOf;
status.operatorSpecified = true;
string[] nskeys = statusKeysValue.Split(new Char[] { ',' });
RecordRef[] recordRefs = new RecordRef[statusKeysValue.Length];
for (int i = 0; i < nskeys.Length; i++)
{
RecordRef recordRef = new RecordRef();
recordRef.internalId = nskeys[i];
recordRefs[i] = recordRef;
}
status.searchValue = recordRefs;
custSearchBasic.entityStatus = status;
}
custSearch.basic = custSearchBasic;
// Invoke search() web services operation
SearchResult response = _service.search(custSearch);
// Process response
if (response.status.isSuccess)
{
// Process the records returned in the response
// Here I get the first 1000 records
processGetAllCustomersResponse(response);
// Since pagination controls what is returned, check to see
// if there are anymore pages to retrieve.
SearchResult seachMoreResult = searchMore(response);
if (seachMoreResult != null)
{
// Process response
if (seachMoreResult.status.isSuccess)
{
// Here I get the next 1000 records
processGetAllCustomersResponse(seachMoreResult);
// My problem now is to get the third set of 1000 customers, then the fourth and so on till I got all 34500 something
}
else
{
}
}
}
else
{
}
}
private SearchResult searchMore(SearchResult response)
{
// Keep getting pages until there are no more pages to get
while (response.totalRecords > (response.pageSize * response.pageIndex))
{
return _service.searchMore(response.pageIndex + 1);
}
return null;
}
In processGetAllCustomersResponse I simply insert the rows in another database which works fine (apart from not getting all the rows I want).
I wrote this alternative to the NetSuite-supplied examples. This example retrieves TimeBill's based on their create date.
/// <summary>
/// Return the list of time bills whose last modified date is within
/// the indicated date range.
/// </summary>
/// <param name="from">Required from date</param>
/// <param name="to">Optional to date</param>
/// <returns>List of time bills</returns>
public IEnumerable<TimeBill> GetTimeBills(DateTime from, DateTime to)
{
_log.Debug(String.Format("Enter TimeBill(DateTime from='{0}', DateTime to='{1}')", from, to));
// Build search criteria.
TimeBillSearch search = new TimeBillSearch();
TimeBillSearchBasic searchBasic = new TimeBillSearchBasic();
SearchDateField searchDateField = new SearchDateField();
searchDateField.#operator = SearchDateFieldOperator.within;
searchDateField.operatorSpecified = true;
searchDateField.searchValue = from;
searchDateField.searchValueSpecified = true;
searchDateField.searchValue2 = to;
searchDateField.searchValue2Specified = true;
searchBasic.dateCreated = searchDateField;
search.basic = searchBasic;
return this.Get<TimeBill>(search);
}
/// <summary>
/// Perform a paged search and convert the returned record to the indicated type.
/// </summary>
private IEnumerable<T> Get<T>(SearchRecord searchRecord)
{
_log.Debug("Enter Get<T>(SearchRecord searchRecord)");
// This is returned.
List<T> list = new List<T>();
// The suitetalk service return this.
SearchResult result = null;
using (ISuiteTalkService service = SuiteTalkFactory.Get<SuiteTalkService>())
{
do
{
// .search returns the first page of data.
if (result == null)
{
result = service.search(searchRecord);
}
else // .searchMore returns the next page(s) of data.
{
result = service.searchMoreWithId(result.searchId, result.pageIndex + 1);
}
if (result.status.isSuccess)
{
foreach (Record record in result.recordList)
{
if (record is T)
{
list.Add((T)Convert.ChangeType(record, typeof(T)));
}
}
}
}
while (result.pageIndex < result.totalPages);
}
return list;
}
i have changed SearchMore function ,now it will return a list of all responses , you need to change getAllCustomer function accordingly
EDIT : updated getAllCustomer Also
private void getAllCustomers()
{
// Instantiate a search object for customers.
CustomerSearch custSearch = new CustomerSearch();
CustomerSearchBasic custSearchBasic = new CustomerSearchBasic();
// Search the customer status which is a list field (16,13,15)
String statusKeysValue = "16,13,15";
SearchMultiSelectField status = null;
if (statusKeysValue != null && !statusKeysValue.Trim().Equals(""))
{
status = new SearchMultiSelectField();
status.#operator = SearchMultiSelectFieldOperator.anyOf;
status.operatorSpecified = true;
string[] nskeys = statusKeysValue.Split(new Char[] { ',' });
RecordRef[] recordRefs = new RecordRef[statusKeysValue.Length];
for (int i = 0; i < nskeys.Length; i++)
{
RecordRef recordRef = new RecordRef();
recordRef.internalId = nskeys[i];
recordRefs[i] = recordRef;
}
status.searchValue = recordRefs;
custSearchBasic.entityStatus = status;
}
custSearch.basic = custSearchBasic;
// Invoke search() web services operation
SearchResult response = _service.search(custSearch);
// Process response
if (response.status.isSuccess)
{
// Process the records returned in the response
// Here I get the first 1000 records
processGetAllCustomersResponse(response);
// Since pagination controls what is returned, check to see
// if there are anymore pages to retrieve.
List<SearchResult> seachMoreResult = searchMore(response);
if (seachMoreResult != null)
{
foreach (SearchResult sr in seachMoreResult)
{
if (sr.status.isSuccess)
{
// Here I get the next 1000 records
processGetAllCustomersResponse(sr);
// My problem now is to get the third set of 1000 customers, then the fourth and so on till I got all 34500 something
}
else
{
}
}
// Process response
}
}
else
{
}
}
private IEnumerable<SearchResult> searchMore(SearchResult response)
{
// Keep getting pages until there are no more pages to get
int tempTotalRecords = response.totalRecords;
int pageSize = response.pageSize * response.pageIndex;
SearchResult tempResponse = null;
List<SearchResult> records = new List<SearchResult>();
while (tempTotalRecords > (pageSize))
{
SearchResult tempResponse = _service.searchMore(response.pageIndex + 1);
if (tempResponse.totalRecords > tempResponse.pageSize * tempResponse.pageIndex)
{
tempTotalRecords = tempResponse.totalRecords;
pageSize = tempResponse.pageSize * tempResponse.pageIndex;
records.Add(response);
}
else
records.Add(response);
}
return records;
}

Categories