Show a series of Dynamic JSON/Dictionaries in a WPF DataGrid, just like the values from a SQL select query - wpf

I've been trying and testing to get this working: binding a series of dictionaries to a datagrid. In such a way that it is like coming from a database. So not showing only 2 columns or any of the metadata columns such as count and toStrings.
The scenario:
I'm downloading JSON based upon a URL. The JSON values come in various forms, but i can transform them to a dictionary or any other type that has keys and values. Each URL is a single line / a single record, this i want to show the values with the same keys in the datagrid from multiple URL's.
I've tried dozens of possible solutions, such as expando objects, dropping the JObject directly in the Gridview, Working with arrays, single lists etc. None gets close to what i want. What i want is: automatic column detection and displaying the right values for the JSON that is loaded.
For example this json: {"x":"a", "y":"b","z":"c"} should be represented in the GridView like this:
x | y | z
---------------
a b c
When another JSON-returning part of the code (another URL) is loaded, it should look like this:
x | y | z
---------------
a b c
e f g
Current code:
What i have now is:
Dictionary < string, string> MyDictionary = new Dictionary < string, string>();
JObject parsed = JsonConvert.DeserializeObject< JObject>(jSonPart);
foreach (var x in parsed)
{
MyDictionary.Add(x.Key,x.Value.Value<String>());
}
outputJson.Items.Add(MyDictionary);
// list of dictionaries.
_jsonObjects.Add(MyDictionary.ToList());
Here is some assigning i use:
List < List < KeyValuePair < String,String > > > _jsonObjects = new List < List < KeyValuePair<String,String> > > ();
outputJson.ItemsSource = _jsonObjects;

Related

GemBox SpreadSheet and merged cells

To illustrate, create a new Excel file, with merged cell.
e.g. row 2 below has columns A and B merged:
If you run code like this, where worksheet is a GemBox.Spreadsheet.ExcelWorksheet:
string v1 = worksheet.Cells[1, 0].GetFormattedValue(); // cell A2 ?
string v2 = worksheet.Cells[1, 1].GetFormattedValue(); // cell B2 ?
Both v1 and v2 will contain "xyz merged". I'm guessing this is by design for merged cells.
Is there an easy way to obtain "xyz merged" for the 1st merged cell (A2), and return null for all subsequent merged cells in the same merged range?
I saw there is a cell.MergedRange property, which returns not null when a cell is merged, so may be able to use that in conjunction with FirstColumnIndex, LastColumnIndex, FirstRowIndex, LastRowIndex properties, to work out if the cell is the first one in the merged range. Wondering if there might be an easier (or more efficient) way ?
Yes, this is by design, you'll need to use the ExcelCell.MergedRange property to get the desired result.
For example, try something like this:
public static class GemBoxSpreadsheetExtension
{
public static string GetFormattedValue(this ExcelCell cell, bool skipMergedCell)
{
if (!skipMergedCell || cell.MergedRange == null || cell.MergedRange[0] == cell)
return cell.GetFormattedValue();
return null;
}
}
You could use this extension method like this:
string v1 = worksheet.Cells[1, 0].GetFormattedValue(true);
string v2 = worksheet.Cells[1, 1].GetFormattedValue(true);

Loop function to fill Crosselling template

I need to create a file containing information on crosselling for my webshop.
In my example file you'll see the tab "Basic Data", this is the data available to me already. Column A contains certain products, column B shows the assigned (product)categories.
The Tab "Starting Point" shows how the final file will be structured and how the function should come into play. It would need to do the following:
Copy the first product from the Unique product list (D2) to A2 (already done here)
Paste a filterfunction into B2 (already done here)
This filterfunction lists all products that belong to the same category like Product 1 except for Product 1 itself
Apply a numerical position tag in tens in Column C to the whole range of products related to Product 1 (in this case B2:B4), starting from 10 (..20, 30, ff) and optimally randomize it. (already done here)
Drag down A2, respectively paste "Product 1" into all cells below A2 until the end of the result of the filterfunction in Columns B is reached (already done here).
Continue the loop by pasting "Product 2" into A5, pasting the filterfunction into B5 and so on.
In "Desired Result" you can see how the end result should look like in this example. There are only 8 products, but I'd need to be able to do this for hundreds of products, that's why a function is needed.
I hope somebody is able to help me here.
Answer
You can get your desired result using Google Apps Script as I suggested.
How to use it:
Open Apps Script clicking on Tools > Script editor and you will see the script editor. It is based on JavaScript and it allows you to create, access, and modify Google Sheets files with a service called Spreadsheet Service.
Paste the following code and click on Run
Code
function main() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheetResult = ss.getSheetByName('Desired Result')
const sheetBasic = ss.getSheetByName('Basic Data')
// write unique products
const val = "=ARRAYFORMULA(UNIQUE('Basic Data'!A2:A))"
sheetResult.getRange('D2').setValue(val)
// get basic data
const lastColumn = sheetBasic.getRange('A:A').getValues().filter(String).length; // number of products
const cat = sheetBasic.getRange('A2:B'+lastColumn).getValues() // product | category
const productGroup = [] // array to store data
// loop each product
for (var j=0; j<cat.length; j++){
const p1 = cat[j]
var k = 1
for (var i=0; i<cat.length; i++){
if (cat[i][1] == p1[1] && cat[i][0] != p1[0]){
const val = [p1[0],cat[i][0],k*10]
k = k + 1
productGroup.push(val)
}
}
}
var n = productGroup.length+1
sheetResult.getRange('A2:C'+n).setValues(productGroup)
}
Some comments
This solution does not randomize the position value. If you need it I can help you with that, but first I want to check that this solution fits you.
Let me know if you can obtain your desired result. Keep in mind that this solution uses the name of the sheets.
Reference
Google Apps Script
Spreadsheet Service
JavaScript

I am trying to make a json array after getting each records from a grid. I want to add row number of grid as key of each row in json array

I am trying to make a json array after getting each records from a grid in ExtJS 3.4.0. I want to add row number of grid as key of each row in JSON array.
var selected_value = [];
for (var i = 0; i < count; i++)
{
var rec = store.getAt(i);
selected_value[i] = rec.data;
final.push({
"i":selected_value[i],
})
}
What you do there is build an array of objects with each object containing one property called i and that property has the value of the row in it.
I guess you actually just wanted to have an array with the row objects in it, right?
final.push(selected_value[i]);
This will do the job already. No need to specify an object with associative indices.
If you're grabbing all the store's entries already or at least know the range (start and end index) you could just as well skip all the manual item picking and grab a readymade array already:
final = store.getRange();
or
final = store.getRange(from, to);

Store formatting information in an array then apply it to a range

I'm trying to create a script that will automatically format a selection based on the formatting of a table in another sheet. The idea is that a user can define a table style for header, rowOdd and rowEven in the Formats sheet, then easily apply it to a selected table using the script.
I've managed to get it working, but only by applying one type of formatting (background colour).
I based my code for reading the code into an array on this article.
As you will hopefully see from my code below, I am only able to read one formatting property into my array.
What I would like to do is read all formatting properties into the array, then apply them to the range in one go. I'm new to this so sorry if my code is a mess!
function formatTable() {
var activeRange = SpreadsheetApp.getActiveSpreadsheet().getActiveRange(); //range to apply formatting to
var arr = new Array(activeRange.getNumRows());
var tableStyleSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Formats"); //location of source styles
var tableColours = {
header: tableStyleSheet.getRange(1, 1, 1).getBackground(),
rowEven: tableStyleSheet.getRange(2, 1, 1).getBackground(),
rowOdd: tableStyleSheet.getRange(3, 1, 1).getBackground()
}
for (var x = 0; x < activeRange.getNumRows(); x++) {
arr[x] = new Array(activeRange.getNumColumns());
for (var y = 0; y < activeRange.getNumColumns(); y++) {
x == 0 ? arr[x][y] = tableColours.header :
x % 2 < 1 ? arr[x][y] = tableColours.rowOdd : arr[x][y] = tableColours.rowEven;
Logger.log(arr);
}
}
activeRange.setBackgrounds(arr);
}
Thanks!
I might be wrong but based from the list of methods given in Class Range, feature to save or store formatting details currently do not exist yet.
However, you may want to try using the following:
copyFormatToRange(gridId, column, columnEnd, row, rowEnd) or copyFormatToRange(sheet, column, columnEnd, row, rowEnd) wherein it copies the formatting of the range to the given location.
moveTo(target) wherein it cuts and paste (both format and values) from this range to the target range.
Did you know that you can get all of the different formatting elements for a range straight into an array?
E.g.
var backgrounds = sheet.getRange("A1:D50").getBackgrounds();
var fonts = sheet.getRange("A1:D50").getFontFamilies();
var fontcolors = sheet.getRange("A1:D50").getFontColors();
etc.
However, there's no way to get all of the formatting in one call unfortunately, so you have to handle each element separately. Then you can apply all of the formats in one go:
targetRng.setFontColors(fontcolors);
targetRng.setBackgrounds(backgrounds);
and so on.

get_by_id() not returning values

I am writing an application that shows the user a number of elements, where he has to select a few of them to process. When he does so, the application queries the DB for the rest of the data on these elements, and stacks them with their full data on the next page.
I made an HTML form loop with a checkbox next to each element, and then in Python I check for this checkbox's value to get the data.
Even when I'm just trying to query the data, ndb doesn't return anything.
pitemkeys are the ids for the elements to be queried. inpochecks is the checkbox variable.
preqitems is the dict to save the items after getting the data.
The next page queries nothing and is blank.
The comments are my original intended code, which produced lots of errors because of not querying anything.
request_code = self.request.get_all('rcode')
pitemkeys = self.request.get_all('pitemkey')
inpochecks = self.request.get_all('inpo')
preqitems = {}
#idx = 0
#for ix, pitemkey in enumerate(pitemkeys):
# if inpochecks[ix] == 'on':
# preqitems[idx] = Preqitems.get_by_id(pitemkey)
# preqitems[idx].rcode = request_code[ix]
# idx += 1
for ix, pitemkey in enumerate(pitemkeys):
preqitems[ix] = Preqitems.get_by_id(pitemkey)
#preqitems[ix].rcode = request_code[ix]
Update: When trying
preqitems = ndb.get_multi([ndb.Key(Preqitems, k) for k in pitemkeys])
preqitems returns a list full of None values, as if the db couldn't find data for these keys.. I checked the keys and for some reason they are in unicode format, could that be the reason? They look like so.
[u'T-SQ-00301-0002-0001', u'U-T-MT-00334-0007-0002', u'U-T-MT-00334-0008-0001']
Probably you need to do: int(pitemkey) or str(pitemkey), depending if you are using integer or string id

Resources