Monotouch.Dialog Generate from db and retain values - ios

I'm have a settings view where I'm using MT.D to build out my UI. I just got it to read elements from a database to populate the elements in a section.
What I don't know how to do is access each elements properties or values. I want to style the element with a different background color for each item based on it's value in the database. I also want to be able to get the selected value so that I can update it in the db. Here's the rendering of the code that does the UI stuff with MT.D. I can get the values to show up and slide out like their supposed to... but, styling or adding delegates to them to handle clicks I'm lost.
List<StyledStringElement> clientTypes = SettingsController.GetClientTypes ();
public SettingsiPhoneView () : base (new RootElement("Home"), true)
{
Root = new RootElement("Settings") {
new Section ("Types") {
new RootElement ("Types") {
new Section ("Client Types") {
from ct in clientTypes
select (Element) ct
}
},
new StringElement ("Other Types")
}

Here's how I handled it below. Basically you have to create the element in a foreach loop and then populate the delegate with whatever you want to do there. Like so:
public static List<StyledStringElement> GetClientTypesAsElement ()
{
List<ClientType> clientTypes = new List<ClientType> ();
List<StyledStringElement> ctStringElements = new List<StyledStringElement> ();
using (var db = new SQLite.SQLiteConnection(Database.db)) {
var query = db.Table<ClientType> ().Where (ct => ct.IsActive == true && ct.Description != "Default");
foreach (ClientType ct in query)
clientTypes.Add (ct);
}
foreach (ClientType ct in clientTypes) {
// Build RGB values from the hex stored in the db (Hex example : #0E40BF)
UIColor bgColor = UIColor.Clear.FromHexString(ct.Color, 1.0f);
var localRef = ct;
StyledStringElement element = new StyledStringElement(ct.Type, delegate {
ClientTypeView.EditClientTypeView(localRef.Type, localRef.ClientTypeId);
});
element.BackgroundColor = bgColor;
ctStringElements.Add (element);
}
return ctStringElements;
}

Related

How to select an item from a List in flutter

I have list from a model like this
amount:"12000"
dateTime:"19/07/2018"
detail:"Soto"
hashCode:853818549
id:1
name:"Theodorus"
I want to just select amount and add it to another list of string, but I'm always getting this error A value of type 'String' can't be assigned to a variable of type 'List<String>'. , I thinks its because im not doing it right, here is my code below
void setupList() async {
DebtDatabase db = DebtDatabase();
listCache = await db.getMyDebt();
setState(() {
filtered = listCache;
});
List<String> amount = new List<String>();
listCache.map((value) {
amount = value.amount; } );
//print(amount);
}
can anyone help me, so I can get list of ammount from this model list and then sum all the ammount?
The map function returns an iterable and you can then transform it into a list.
You should try something like this:
void setupList() async {
DebtDatabase db = DebtDatabase();
listCache = await db.getMyDebt();
setState(() {
filtered = listCache;
});
List<String> amount = listCache.map((value) => value.amount).toList();
//print(amount);
}

Observing an object containing a list of observables?

I am using the observe package.
Consider this example:
class Product extends Object with ChangeNotifier {
double _price = 0.0;
#reflectable double get price => _price;
#reflectable void set price(double value) {
if (value == null) throw new ArgumentError();
_price = notifyPropertyChange(#price, price, value);
}
}
class Order extends Object with ChangeNotifier {
final ObservableList<Product> products = new ObservableList<Product>();
double get total {
double sum = 0.0;
for (var item in products) {
sum += item.price;
}
return sum;
}
}
// Synchronizes the view total with the order total.
// Or rather, I'd like it to do that.
var order = new Order();
order.changes.listen((records) {
view.total = order.total;
});
How would I rewrite this example to make it work?
I would like to be notified of any changes to the object's state, even if they happen to the list or the items of the list.
Do I have to manage change subscriptions to all items and the list itself? Inside or outside of the Order class? Through which property would I notify the change? It seems messy either way.
The elements in the ObservableList do not propagate the notification to the list that contains them. They can't because they have no reference to the list.
Also the list does not forward the notifications to the class it is referenced by.
Not really satisfying but the best I could come up with.
import 'dart:async' as async;
import 'package:observe/observe.dart';
class Product extends Object with ChangeNotifier {
double _price = 0.0;
#reflectable double get price => _price;
#reflectable void set price(double value) {
if (value == null) throw new ArgumentError();
_price = notifyPropertyChange(#price, price, value);
}
#override
String toString() => 'Product - price: $price';
}
class Order extends Object with ChangeNotifier {
final ObservableList<Product> products = new ObservableList<Product>();
// keep listeners to be able to cancel them
final List<async.StreamSubscription> subscriptions = [];
Order() {
products.changes.listen((cr) {
// only react to length changes (isEmpty, isNotempty changes are redundant)
var lengthChanges = cr.where((c) => c.name == #length);
if(lengthChanges.isNotEmpty) {
lengthChanges.forEach((lc) =>
notifyChange(lc));
// we can't know if only additions/removals were done therefore we
// cancel all existing listeners and set up new ones for all items
// after each length change
_updateProductsListeners();
}
});
// initial setup
_updateProductsListeners();
}
// cancel all product change listeners and create new ones
void _updateProductsListeners() {
print('updateListeners');
subscriptions.forEach((s) => s.cancel());
subscriptions.clear();
products.forEach((p)
=> subscriptions.add(p.changes.listen((crs) =>
crs.forEach((cr) =>
notifyPropertyChange(cr.name, cr.oldValue, cr.newValue)))));
}
double get total {
double sum = 0.0;
for (var item in products) {
sum += item.price;
}
return sum;
}
}
void main() {
// Synchronizes the view total with the order total.
// Or rather, I'd like it to do that.
var order = new Order();
order.changes.listen((records) {
//view.total = order.total;
records.forEach(print);
});
// a PathObserver example but it doesn't seem to be more convenient
var op = new PathObserver(order, 'products[3].price')..open((c) =>
print(c));
var prods = [new Product()..price = 1.0, new Product()..price = 2.0, new Product()..price = 3.0, new Product()..price= 4.0];
var prods2 = [new Product()..price = 5.0, new Product()..price = 6.0];
order.products.addAll(prods);
// use Future to allow change notification propagate between changes
new async.Future(() =>
order.products..addAll(prods2)..removeWhere((p) => p.price < 3.0))
.then((_) => new async.Future(() => order.products[3].price = 7.0));
new async.Future.delayed(new Duration(seconds: 1), () => print('done'));
}
I suggest to use something like an event bus for this where the objects that want/should to notify about something just send and event and objects that are interested in something listen for that without any knowledge of where the other object exists.
For example https://pub.dartlang.org/packages/event_bus
Another solution is to use the ListPathObserver. The class is deprecated but you can copy his code and reuse it. With that class you can listen for specific changes in the contained items. The field to watch is specified by path.

jqgrid + EF + MVC: How to export in excel? Which method you suggest?

I am using jqgrid (standard) with EF 4 + MVC3. I'd like to implement excel export. Which method you would suggest me?
To generate excel, I'd like to use this library by Dr Stephen Walther, which has three types of output and allows to define headers too. Please tell me if you find it valid for my purpose.
I ask this question because I am still approaching to implement excel export and I found several techniques. Some suggest making a csv export, others indicate that it should return a JSON output and it is not clear to me whether this capability is present in the free version of jqgrid. In any case, I would like to pass the data to Walther's object.
About the jqgrid code, I found this interesting answer by Oleg, but I do not understand if could be applied to my needs.
Unfortunately, by now I only found parts of solutions for excel export with EF MVC, but no solution or complete examples...
About the MVC logic, I am going to implement and develop this code as kindly suggested by #Tommy.
Please sorry if the question could be silly, I am just a (enthusiast) beginner.
Thanks for your precious help!
Best Regards
As I wrote before (see here and here for example) the best way to export grid data to XML is the usage of Open XML SDK 2.0.
The post of Dr Stephen Walther shows how to create HTML file which can be read by Excel. It's not Excel file and have to be still converted to Excel format. The usage of CSV has even more problems. Depend on the content in the source table the automatic conversion to Excel data types can be absolutely wrong. In one project which I developed for a customer the grid contained information about software products: product name, version, and so on. The software version looks sometime as the date (1.3.1963 for example) and such cells will be wrong converted (in German one use '.' as the separator in the date). As the result one had really hard problems. The usage of CSV with texts having commas inside will be also frequently wrong imported. Even when one quotes the cells having commas (,) and escaped the texts having quotas the import still be wrong especially in the first column. I don't want to explain here the whole history of all attempts and errors, but after all I decide to give up with the usage of CSV and HTML and started to use Open XML SDK 2.0 which allows to create real Excel files with extension XLSX. The way seems me perfect because one don't need any Office
components installed on the server, no additional licenses.
The only restriction is that one should be able to use DocumentFormat.OpenXml.dll, so your server program should run on any Windows operation system. As it's well known, XLSX file is ZIP file which contains some XML files inside. If you still don't know that I recommend you to rename the XLSX file to ZIP file and extract it. The Open XML SDK 2.0 is the library which works with XLSX file like with XML files. So no additional Office components are required.
One can find a lot of information how to use Open XML SDK 2.0 (see here, here and here). Many helpful code examples one cam find directly on the MSDN (see here). Nevertheless the practical usage of Open XML SDK 2.0 is not so easy at least at the first time. So I created a demo from the parts of the code which I used myself.
You can download the demo project from here. The demo is an extension of the demos from the answer and this one.
To export data I use the DataForExcel helper class. It has constructor in the form
DataForExcel(string[] headers, DataType[] colunmTypes, List<string[]> data,
string sheetName)
or in a little simplified form
DataForExcel(string[] headers, List<string[]> data, string sheetName)
and the only public method
CreateXlsxAndFillData(Stream stream)
The usage of the class to create Excel file can be like the following
var excelData = new DataForExcel (
// column Header
new[]{"Col1", "Col2", "Col3"},
new[]{DataForExcel.DataType.String, DataForExcel.DataType.Integer,
DataForExcel.DataType.String},
new List<string[]> {
new[] {"a", "1", "c1"},
new[] {"a", "2", "c2"}
},
"Test Grid");
Stream stream = new FileStream ("Test.xlsx", FileMode.Create);
excelData.CreateXlsxAndFillData (stream);
stream.Close();
The usage in the demo from ASP.NET MVC is the following
static readonly string[] HeadersQuestions = {
"Id", "Votes", "Title"
};
static readonly DataForExcel.DataType[] ColunmTypesQuestions = {
DataForExcel.DataType.Integer,
DataForExcel.DataType.Integer,
DataForExcel.DataType.String
};
public ActionResult ExportAllQuestionsToExcel () {
var context = new HaackOverflowEntities ();
var questions = context.Questions;
questions.MergeOption = MergeOption.NoTracking; // we don't want to update the data
// to be able to use ToString() below which is NOT exist in the LINQ to Entity
// we should include in query only the properies which we will use below
var query = questions.ToList ();
if (query.Count == 0)
return new EmptyResult ();
var data = new List<string[]> (query.Count);
data.AddRange (query.Select (item => new[] {
item.Id.ToString(CultureInfo.InvariantCulture),
item.Votes.ToString(CultureInfo.InvariantCulture),
item.Title
}));
return new ExcelResult (HeadersQuestions, ColunmTypesQuestions, data,
"Questions.xlsx", "Questions");
}
where ExcelResult are defined as
public class ExcelResult : ActionResult {
private readonly DataForExcel _data;
private readonly string _fileName;
public ExcelResult (string[] headers, List<string[]> data, string fileName, string sheetName) {
_data = new DataForExcel (headers, data, sheetName);
_fileName = fileName;
}
public ExcelResult (string[] headers, DataForExcel.DataType[] colunmTypes, List<string[]> data, string fileName, string sheetName) {
_data = new DataForExcel (headers, colunmTypes, data, sheetName);
_fileName = fileName;
}
public override void ExecuteResult (ControllerContext context) {
var response = context.HttpContext.Response;
response.ClearContent();
response.ClearHeaders();
response.Cache.SetMaxAge (new TimeSpan (0));
using (var stream = new MemoryStream()) {
_data.CreateXlsxAndFillData (stream);
//Return it to the client - strFile has been updated, so return it.
response.AddHeader ("content-disposition", "attachment; filename=" + _fileName);
// see http://filext.com/faq/office_mime_types.php
response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
response.ContentEncoding = Encoding.UTF8;
stream.WriteTo (response.OutputStream);
}
response.Flush();
response.Close();
}
}
To make the code full I have to include the code of the class DataForExcel:
public class DataForExcel {
public enum DataType {
String,
Integer
}
private readonly string[] _headers;
private readonly DataType[] _colunmTypes;
private readonly List<string[]> _data;
private readonly string _sheetName = "Grid1";
private readonly SortedSet<string> _os = new SortedSet<string> ();
private string[] _sharedStrings;
private static string ConvertIntToColumnHeader(int index) {
var sb = new StringBuilder ();
while (index > 0) {
if (index <= 'Z' - 'A') // index=0 -> 'A', 25 -> 'Z'
break;
sb.Append (ConvertIntToColumnHeader (index / ('Z' - 'A' + 1) - 1));
index = index % ('Z' - 'A' + 1);
}
sb.Append ((char)('A' + index));
return sb.ToString ();
}
private static Row CreateRow(UInt32 index, IList<string> data) {
var r = new Row { RowIndex = index };
for (var i = 0; i < data.Count; i++)
r.Append (new OpenXmlElement[] { CreateTextCell (ConvertIntToColumnHeader (i), index, data[i]) });
return r;
}
private Row CreateRowWithSharedStrings(UInt32 index, IList<string> data) {
var r = new Row { RowIndex = index };
for (var i = 0; i < data.Count; i++)
r.Append (new OpenXmlElement[] { CreateSharedTextCell (ConvertIntToColumnHeader (i), index, data[i]) });
return r;
}
private Row CreateRowWithSharedStrings(UInt32 index, IList<string> data, IList<DataType> colunmTypes) {
var r = new Row { RowIndex = index };
for (var i = 0; i < data.Count; i++)
if (colunmTypes != null && i < colunmTypes.Count && colunmTypes[i] == DataType.Integer)
r.Append (new OpenXmlElement[] { CreateNumberCell (ConvertIntToColumnHeader (i), index, data[i]) });
else
r.Append (new OpenXmlElement[] { CreateSharedTextCell (ConvertIntToColumnHeader (i), index, data[i]) });
return r;
}
private static Cell CreateTextCell(string header, UInt32 index, string text) {
// create Cell with InlineString as a child, which has Text as a child
return new Cell (new InlineString (new Text { Text = text })) {
// Cell properties
DataType = CellValues.InlineString,
CellReference = header + index
};
}
private Cell CreateSharedTextCell(string header, UInt32 index, string text) {
for (var i=0; i<_sharedStrings.Length; i++) {
if (String.Compare (_sharedStrings[i], text, StringComparison.Ordinal) == 0) {
return new Cell (new CellValue { Text = i.ToString (CultureInfo.InvariantCulture) }) {
// Cell properties
DataType = CellValues.SharedString,
CellReference = header + index
};
}
}
// create Cell with InlineString as a child, which has Text as a child
throw new InstanceNotFoundException();
}
private static Cell CreateNumberCell(string header, UInt32 index, string numberAsString) {
// create Cell with CellValue as a child, which has Text as a child
return new Cell (new CellValue { Text = numberAsString }) {
// Cell properties
CellReference = header + index
};
}
private void FillSharedStringTable(IEnumerable<string> data) {
foreach (var item in data)
_os.Add (item);
}
private void FillSharedStringTable(IList<string> data, IList<DataType> colunmTypes) {
for (var i = 0; i < data.Count; i++)
if (colunmTypes == null || i >= colunmTypes.Count || colunmTypes[i] == DataType.String)
_os.Add (data[i]);
}
public DataForExcel(string[] headers, List<string[]> data, string sheetName) {
_headers = headers;
_data = data;
_sheetName = sheetName;
}
public DataForExcel(string[] headers, DataType[] colunmTypes, List<string[]> data, string sheetName) {
_headers = headers;
_colunmTypes = colunmTypes;
_data = data;
_sheetName = sheetName;
}
private void FillSpreadsheetDocument(SpreadsheetDocument spreadsheetDocument) {
// create and fill SheetData
var sheetData = new SheetData ();
// first row is the header
sheetData.AppendChild (CreateRow (1, _headers));
//const UInt32 iAutoFilter = 2;
// skip next row (number 2) for the AutoFilter
//var i = iAutoFilter + 1;
UInt32 i = 2;
// first of all collect all different strings in OrderedSet<string> _os
foreach (var dataRow in _data)
if (_colunmTypes != null)
FillSharedStringTable (dataRow, _colunmTypes);
else
FillSharedStringTable (dataRow);
_sharedStrings = _os.ToArray ();
foreach (var dataRow in _data)
sheetData.AppendChild (_colunmTypes != null
? CreateRowWithSharedStrings (i++, dataRow, _colunmTypes)
: CreateRowWithSharedStrings (i++, dataRow));
var sst = new SharedStringTable ();
foreach (var text in _os)
sst.AppendChild (new SharedStringItem (new Text (text)));
// add empty workbook and worksheet to the SpreadsheetDocument
var workbookPart = spreadsheetDocument.AddWorkbookPart ();
var worksheetPart = workbookPart.AddNewPart<WorksheetPart> ();
var shareStringPart = workbookPart.AddNewPart<SharedStringTablePart> ();
shareStringPart.SharedStringTable = sst;
shareStringPart.SharedStringTable.Save ();
// add sheet data to Worksheet
worksheetPart.Worksheet = new Worksheet (sheetData);
worksheetPart.Worksheet.Save ();
// fill workbook with the Worksheet
spreadsheetDocument.WorkbookPart.Workbook = new Workbook (
new FileVersion { ApplicationName = "Microsoft Office Excel" },
new Sheets (
new Sheet {
Name = _sheetName,
SheetId = (UInt32Value)1U,
// generate the id for sheet
Id = workbookPart.GetIdOfPart (worksheetPart)
}
)
);
spreadsheetDocument.WorkbookPart.Workbook.Save ();
spreadsheetDocument.Close ();
}
public void CreateXlsxAndFillData(Stream stream) {
// Create workbook document
using (var spreadsheetDocument = SpreadsheetDocument.Create (stream, SpreadsheetDocumentType.Workbook)) {
FillSpreadsheetDocument (spreadsheetDocument);
}
}
}
The above code create new XLSX file directly. You can extend the code to support more data types as String and Integer which I used in the code.
In more professional version of your application you can create some XLSX templates for exporting different tables. In the code you can place the data in the cells instead, so modify the spreadsheet instead of creating. In the way you can create perfect formatted XLSX files. The examples from the MSDN (see here) will help you to implement the way when it will be required.
UPDATED: The answer contains updated code which allows generate Excel documented with more cell formatting.
I looked at Stephen's post and it's old as hell, which btw doesn't make it wrong.
If you don't need custom formatting, headers and styles, then I think use CSV as it's very simple.
More importantly, don't think that excel export from MVC site that internally uses EF for data access is harder than, say, Ruby on Rails site that uses ActiveRecord. For me it's independent concerns, export shouldn't new anything about underlying technologies (at least not directly), just the structure of your data, that's all.
Search for codeplex libraries that allows to do Excel reading/writing and export, there are plenty of them these days, many really good solutions that's regularly maintained and tested by thousand of developers all over the globe. If I were you I won't use Stephen solution because it looks like he occasionally typed it in a notepad and then pasted to the post - no unit tests, no extensibility points + it's in VB so it even harder to understand, but may be that's just me.
Hope this help and good luck

Dynamic Controls not Displaying

I am creating controls on some input XML.
The controls are then added to the different PlaceHolder Control which is places in a table. Here is the code for reference
private void RenderFactorControls(string xml)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
foreach (XmlNode xmlNode in xmlDoc.DocumentElement.ChildNodes)
{
CheckBox factorCheckBox = new CheckBox();
factorCheckBox.ID = "chkBox"+xmlNode.Attributes["id"].Value;
factorCheckBox.Text = xmlNode.Attributes["id"].Value;
this.pholderControls1.Controls.Add(factorCheckBox);
this.pholderControls2.Controls.Add(factorCheckBox);
this.pholderControls3.Controls.Add(factorCheckBox);
this.pholderControls4.Controls.Add(factorCheckBox);
this.pholderControls5.Controls.Add(factorCheckBox);
}
}
Only the last place holder shows the controls.
private void RenderFactorControls(string xml)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
foreach (XmlNode xmlNode in xmlDoc.DocumentElement.ChildNodes)
{
string id = "chkBox"+xmlNode.Attributes["id"].Value;
string text = xmlNode.Attributes["id"].Value;
this.pholderControls1.Controls.Add(new CheckBox() { ID = id, Text = text });
this.pholderControls2.Controls.Add(new CheckBox() { ID = id, Text = text });
this.pholderControls3.Controls.Add(new CheckBox() { ID = id, Text = text });
this.pholderControls4.Controls.Add(new CheckBox() { ID = id, Text = text });
this.pholderControls5.Controls.Add(new CheckBox() { ID = id, Text = text });
}
}
You created only One CheckBox and are trying to add it to multiple placeholders. Adding a control to a container removes it from its previous parent. Try creating 5 different checkboxes.

General solution to updating fields for table in Entity Framework 4.0

I want to create a method which can takes the properties I possibly may update and leaving those not interested untouched.
Here is what I did:
public static void updateTable(int id, string field1, string field2, string field3){
using(var context = new Entities()){
var obj = context.Table.Where(x=>x.id == id).FirstOrDefault();
if(obj != null){
obj.field1 = field1;
...
obj.SaveChanges();
}
}
}
But in this pattern, I need to pass all 4 parameters into the method even I just want to update only one field. Is there any generic solution to update only the fields I passed in?
I came up something like this:
public static void updateTable(int id, object data_json){
using(var context = new Entities()){
var obj = context.Table.Where(x=>x.id == id).FirstOrDefault();
if(obj != null){
if(data_json['field1']!=null) //something like this
obj.field1 = data_json['field1'];
...
obj.SaveChanges();
}
}
}
But this can't handle the case that I do want to set a field to be null. Or is there any better solution?
If you don't care about updating relationships, you can use ApplyCurrentValues, which only updates the scalar properties.
E.g:
public static void updateTable(int id, object data_json){
using(var context = new Entities()) {
var obj = context.Table.Where(x=>x.id == id).FirstOrDefault();
context.ApplyCurrentValues("Table", data_json);
}
}
It assumes an entity with the same key is already attached in the graph. In this case, the query for var obj will ensure the object is in the graph, then it's contents are overridden with the scalar properties on the supplied object.
You might need an explicit cast on data_json to ensure it is of the same type contained in the entity set.
Using an ExpandoObject would allow you to send in only the properties you want to set, and would allow you to specify null values as well.
For example:
public static void updateTable(int id, dynamic data){
using(var context = new Entities()){
var obj = context.Table.Where(x=>x.id == id).FirstOrDefault();
if(obj != null){
if (((IDictionary<string, object>)data).ContainsKey("field1"))
obj.field1 = data.field1;
...
obj.SaveChanges();
}
}
}
and you could call it like this:
dynamic data = new ExpandoObject();
data.field1 = 123;
data.field2 = null;
data.field5 = "abc";
MyClass.updateTable(1, data);
Everything can be solved with a moment of reflection. This function solves the problem:
public void UpdateTable(int id, object values)
{
using (var entities = new MyEntities())
{
var valuesType = values.GetType();
var element = entities.MyTable.Where(t => t.ID == id).First();
//We are iterating through all properties of updated element and checking
//if there is value provided for there properties in values parameter
foreach (var property in element.GetType().GetProperties())
{
var valuesProperty = valuesType.GetProperty(property.Name);
//If values contain this property
if (valuesProperty != null)
{
//taking value out of values parameter
var value = valuesProperty.GetValue(values, null);
//setting it in our element to update
property.SetValue(element, value, null);
}
}
entities.SaveChanges();
}
}
Usage:
UpdateTable(125, new { FieldA = 1, FieldB = "ABCD" });
You can even make this method more universal by adding generic table type parameter.

Resources