Xamarin Forms SFDataGrid Binding Issue - xamarin.forms

I'm having problems with binding to a data grid. I've got a dynamic data set, so I can't just create objects. I've tried using both an array of ExpandoObjects and a DataTable, the result is the same. If I explicitly create the dataset, it works but this doesn't do me any good. My xaml is:
<sf:SfDataGrid BackgroundColor="{ DynamicResource DataGridHeaderRowBackgroundColor }" ItemsSource="{Binding TableData, Mode=OneWay}" Columns="{Binding Columns, Mode=OneWay}" AutoGenerateColumns="False"></sf:SfDataGrid>
For example:
int cellIndex = 0;
foreach (TableCell cell in row.Cells.OrderBy(c => c.ColumnIndex))
{
GridTextColumn column = new GridTextColumn
{
HeaderText = cell.CellText
};
if (cell.CellType == TableCellType.Checkbox)
{
column.ColumnSizer = ColumnSizer.SizeToHeader;
}
else
{
column.Width = 200;
}
column.MappingName = cellIndex.ToString();
column.HeaderFontAttribute = FontAttributes.Bold;
column.HeaderTextAlignment = TextAlignment.Center;
column.HeaderFont = "SourceSansPro-Bold.ttf#Source Sans Pro";
column.HeaderCellTextSize = 14;
column.LoadUIView = true;
column.LineBreakMode = LineBreakMode.CharacterWrap;
this.Columns.Add(column);
cellIndex++;
}
Dictionary s = new Dictionary();
s.Add("0", "zero");
s.Add("1", "one");
s.Add("2", "two");
s.Add("4", "three");
s.Add("5", "four");
s.Add("6", "five");
s.Add("7", "six");
s.Add("8", "seven");
s.Add("8", "eight");
tableData.Add(s.ToExpando());
this.TableData = tableData;
Now, for my real data I do this (column stuff is exactly the same). This does not work, I get the attached screenshot.
Dictionary rowData = new Dictionary();
int cellIndex = 0;
foreach (TableCell cell in row.Cells.OrderBy(c => c.ColumnIndex))
{
rowData.Add(cellIndex.ToString(), string.IsNullOrEmpty(cell.CellText) ? "EMPTY" : cell.CellText);
cellIndex++;
}
tableData.Add(rowData.ToExpando());

You have defined LoadUIView for column as true change it false so the text will be rendered for Android platform alone.
For your information.
In Syncfusion DataGrid, text is drawn for better performance in Xamarin.Forms Android only, so that text is rendered. If we load Label for the same scenario by setting LoadUIView as true for all the column, then you will face rendering issue “Cell value doesl not render” in all the platform it is because Xamarin forms have not yet given binding support to the Expando object.
In Xamarin forms ExpandoObject binding is under implementation.
https://github.com/xamarin/Xamarin.Forms/issues/3177
Please refer the following link for more details regarding IOS platform limitation for Dynamic object.
Discussion Link : https://forums.xamarin.com/discussion/53941/expandoobject-crashing-ios
Limitation Link: https://learn.microsoft.com/en-gb/xamarin/ios/internals/limitations
Suggest you to use ObservableCollection or DataTable collection as SfDataGrid Itemsource.until Expando object binding support is provided by xamarin forms framework.
Regards,
Pradeep Kumar B

Related

How do I create something that works like a logging control in Xamarin.Forms

I'm after something like the application output window in Visual Studio, like so:
I'd like to be able to:
bind to an ObservableCollection of strings
select and copy text (as shown in the screenshot above)
At present this is for a Mac app, although iOS may follow later.
I've tried these:
Editor - Problem is it only exposes a Text property that I can bind to and not a collection. Sooner or later, the maximum string length will be reached.
ListView with Label for ViewCell - Problem is text from a Label is not selectable, let alone having multiple lines (bound collection items) selectable.
Using a custom renderer for Mac that makes use of NSTextView and appending to textStorage every time a new item is added, but again, there’s a limit to how much you can add to textStorage.
I'm open to using third-party tools such as Syncfusion, if that makes it easier.
Custom a method to deal with list data to combine them into a newline string :
public string formatstring(NSArray objects)
{
StringBuilder stringBuilder = new StringBuilder();
for(nuint i=0;i< objects.Count; i++)
{
stringBuilder.Append(objects.GetItem<NSString>(i) +"\n");
}
return stringBuilder.ToString();
}
Then used in NSTextView as follow :
string[] items = new string[] {"111111" , "222222" , "333333" , "444444" , "555555" };
NSArray array = NSArray.FromStrings(items);
NSTextView textView = new NSTextView(new CGRect(100,160,200,100));
textView.BackgroundColor = NSColor.Gray;
textView.Value = formatstring(array);
View.AddSubview(textView);
The effect :

Visual Studio Extension: Get the path of the current selected file in the Solution Explorer

I'm trying to create my first extension for visual studio and so far I've been following this tutorial to get me started (http://www.diaryofaninja.com/blog/2014/02/18/who-said-building-visual-studio-extensions-was-hard).
Now I have a custom menu item appearing when I click on a file in the solution explorer.
What I need now for my small project is to get the path of the file selected in the solution explorer but I can't understand how can I do that.
Any help?
---------------------------- EDIT ------------------------------
As matze said, the answer is in the link I posted. I just didn't notice it when I wrote it.
In the meanwhile I also found another possible answer in this thread: How to get the details of the selected item in solution explorer using vs package
where I found this code:
foreach (UIHierarchyItem selItem in selectedItems)
{
ProjectItem prjItem = selItem.Object as ProjectItem;
string filePath = prjItem.Properties.Item("FullPath").Value.ToString();
//System.Windows.Forms.MessageBox.Show(selItem.Name + filePath);
return filePath;
}
So, here are two ways to get the path to the selected file(s) :)
For future reference:
//In your async method load the DTE
var dte2 = await ServiceProvider.GetGlobalServiceAsync(typeof(SDTE)) as DTE2;
var selectedItems = dte2.SelectItems;
if(selectedItems.MultiSelect || selectedItems.Count > 1){ //Use either/or
for(short i = 1; i <= selectedItems.Count; i++){
//Get selected item
var selectedItem = selectedItems[i];
//Get associated project item (selectedItem.ProjectItem
//If selectedItem is a project, then selectedItem.ProjectItem will be null,
//and selectedItem.Project will not be null.
var projectItem = selectedItem.ProjectItem;
//Get project for ProjectItem
var project = projectItem.ContainingProject;
// Or get project object if selectedItem is a project
var sproject = selectedItem.Project;
//Is selectedItem a physical folder?
var isFolder = projectItem.Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder;
//Else, get item's folder
var itemFolder = new FileInfo(projectItem.Properties.Item("FullPath").ToString()).Directory;
//Find config file
var configFiles itemFolder.GetFiles("web.config");
var configfile = configFiles.length > 0 ? configFiles[0] : null;
//Turn config file into ProjectItem object
var configItem = dte2.solution.FindProjectItem(configFile.FullName);
}
}
I hope someone finds this helpful...
The article you mentioned already contains a solution for that.
Look for the menuCommand_BeforeQueryStatus method in the sample code. It uses the IsSingleProjectItemSelection method to obtain an IVsHierarchy object representing the project as well as the id of the selected item. It seems that you can safely cast the hierarchy to IVsProject and use it´s GetMkDocument function to query the item´s fullpath...
IVsHierarchy hierarchy = null;
uint itemid = VSConstants.VSITEMID_NIL;
if (IsSingleProjectItemSelection(out hierarchy, out itemid))
{
IVsProject project;
if ((project = hierarchy as IVsProject) != null)
{
string itemFullPath = null;
project.GetMkDocument(itemid, out itemFullPath);
}
}
I don´t want to copy the entire code from the article into this answer, but it might be of interest how the IsSingleProjectItemSelection function obtains the selected item; so I just add some notes instead which may guide into the right direction... The method uses the GetCurrentSelection method of the global IVsMonitorSelection service to query to the current selected item.

Flex 3: dynamically created checkbox column in datagrid - data population issues and event listener

I have a datagrid control in my mxml file:
Now in my AS file, in the result function when obtaining data from DB, I can create columns dynamically. Let's say I create 1 column (client name):
private function GetDebtors_Result(event:ResultEvent):void
{
var arrayCol:Array = new Array();
var xmlSrc:XML = new XML("<main></main>");
var xmlTmp:XML;
var colClientname:DataGridColumn;
//Build an XML from DB data received (could as well use "event.result" directly to act as dataprovider for the datagrid, but I needed to break it down here)
for each(var o:Object in event.result)
{
xmlTmp = <row>
<CLIENTNAME>{o.CLIENTNAME}</CLIENTNAME>
</row>;
xmlSrc.appendChild(xmlTmp);
}
//Create the column CLIENTNAME
colClientname = new DataGridColumn("CLIENTNAME");
colClientname.headerText = "Client Name";
//Add the newly created column in the "Column" array.
arrayCol.push(colClientname);
//Use the "Column" array to set the columns of the datagrid.
dgSearch.columns = arrayCol;
//Populate the datagrid with the XML data.
dgSearch.dataProvider = xmlSrc.row;
}
This works well.
Now comes the issue: I need to add a second column which will contain checkboxes. They will be selected or deselected depending on the data from database. I'll show how I've done it by updating the same "GetDebtors_Result" function as above (added lines are commented as "// ADDED"):
private function GetDebtors_Result(event:ResultEvent):void
{
var arrayCol:Array = new Array();
var xmlSrc:XML = new XML("<main></main>");
var xmlTmp:XML;
var colClientname:DataGridColumn;
var colSel:DataGridColumn; // **ADDED**
//Build an XML from DB data received (could as well use "event.result" directly to act as dataprovider for the datagrid, but I needed to break it down here)
for each(var o:Object in event.result)
{
xmlTmp = <row>
<CLIENTNAME>{o.CLIENTNAME}</CLIENTNAME>
<SELECTED>{(o.SELECTED == 1)?true:false}</SELECTED> //**ADDED**
</row>;
xmlSrc.appendChild(xmlTmp);
}
//Create the column CLIENTNAME
colClientname = new DataGridColumn("CLIENTNAME");
colClientname.headerText = "Client Name";
//Create the column SELECTED
colSel = new DataGridColumn("SELECTED"); // **ADDED**
colSel.headerText = ""; // **ADDED**
colSel.itemRenderer = new ClassFactory(mx.controls.CheckBox); // **ADDED**
colSel.dataField = "SELECTED"; // **ADDED**
//Add the newly created column in the "Column" array.
arrayCol.push(colClientname);
//Add the "selection" column in the "Column" array.
arrayCol.push(colSel); // **ADDED**
//Use the "Column" array to set the columns of the datagrid.
dgSearch.columns = arrayCol;
//Populate the datagrid with the XML data.
dgSearch.dataProvider = xmlSrc.row;
}
Problem #1: The checkbox column appears, I can check and uncheck the checkboxes, but they are not checked/unchecked respective to DB data when loaded.
Problem #2: How do I associate a function to the checkboxes, for instance one which will update the XML so that I can save the new data to the DB?
Anybody got the solution? Thank you in advance.
Seems to be a very old question that I saw today.
Hopefully you would have found out the solution by now, just in-case if anyone has same problem:
While adding a checkbox to column- just instantiate it 1st:
var chkTempCheck: Checkbox = new CheckBox();
Then set all the properties required:
chkTempCheck.selected = o.dBColumnToDecideCheckUnCheck
here 'o' is the Object you are using from event.result.
This will work for sure!
The initial scenario was: all columns were defined in the mxml file. The checkbox column used itemrenderer and was working properly. I was using the same datagrid in 3 different cases - only thing was that some columns were set visible/invisible depending on the 'views'. The problem was when shifting 'views' and populate the grid and shift 'views' again, the column widths kept increasing exponentially. I excluded the checkbox column and everything worked fine; columns widths were ok. I included the checkbox column back and tried setting the column widths in AS file and the column-increasing-exponentially problem was fixed but the column widths were never the same when populating grid in view A and when populating grid in view B. ...So I ventured out in trying to set the columns in AS file just after obtaining DB data. Hope you can find yourself in those situations. Thanks for helping.

Dynamically change DefaultLeafIcons in AdvancedDataGrid

Overview:
I have an advancedDataGrid that I am using a GroupingCollection on and I want to be able to change the individual DefaultLeafIcons (no children icon) based upon a value I get from the dataProvider. Can anyone shed some light on how this is done.
Details:
In the data that I receive there is an isShared value that is either 1 or 0 if the value is 1 I want to be able to display abc.png if the value is 0 display xyz.png.
I am using Flex 3.6 SDK.
I believe you should implement an iconFunction for the datagrid.
a sample iconFunction implementation would look like the following.
[Embed("abc.png")]
private var abcIcon:Class;
[Embed("xyz.png")]
private var xyzIcon:Class;
private function iconFunc(item:Object):Class {
var iconClass:Class;
var itemType:int = item.isShared; //TypeCast item accordingly.
switch(itemType)
{ case 1: iconClass = abcIcon;
break;
case 0: iconClass = xyzIcon;
break;
}
return iconClass;
}
Remember to link the iconFunc with the datagrid by adding the following attribute.
iconFunction="iconFunc"

Flex Advanced Data Grid w/ hierarchical data: How to access currentTarget fields on dragdrop event?

So this is driving me crazy. I've got an advanced data grid with a dataprovider that's an array collection w/ hierarchical data. Each object (including the children) has an id field. I'm trying to drag and drop data from within the ADG. When this happens, I need to grab the id off the drop target and change the dragged object's parentid field. Here's what I've got:
public function topAccountsGrid_dragDropHandler(event:DragEvent):void{
//In this function, you need to make the move, update the field in salesforce, and refresh the salesforce data...
if(checkActivateAccountManageMode.selected == true) {
var dragObj:Array = event.dragSource.dataForFormat("treeDataGridItems") as Array;
var newParentId:String = event.currentTarget['Id'];
dragObj[0].ParentId = newParentId;
} else {
return;
}
app.wrapper.save(dragObj[0],
new mx.rpc.Responder(
function():void {
refreshData();
},
function():void{_status = "apex error!";}
)
);
}
I can access the data I'm draggin (hence changing parentId) but not the currentTarget. I think the hierarchical data is part of the problem, but I can't find much in the documentation? Any thoughts?
event.currentTarget is not a node, it's the ADG itself. However, it's quite easy to get the information you want, since the ADG stores that data internally (as mx_internal).
I'm using the following code snippets (tested with Flex SDK 4.1) in a dragOver handler, but I guess it will work in a dragDrop handler too.
protected function myGrid_dragDropHandler(event:DragEvent):void
{
// Get the dragged items. This could either be an Array, a Vector or NULL.
var draggedItems:Object = getDraggedItems(event.dragSource);
if (!draggedItems)
return;
// That's our ADG where the event handler is registered.
var dropTarget:AdvancedDataGrid = AdvancedDataGrid(event.currentTarget);
// Get the internal information about the dropTarget from the ADG.
var dropData:Object = mx_internal::dropTarget._dropData;
// In case the dataProvider is hierarchical, get the internal hierarchicalData aka rootModel.
var hierarchicalData:IHierarchicalData = dropTarget.mx_internal::_rootModel;
var targetParent:Object = null;
// If it's a hierarchical data structure and the dropData could be retrieved
// then get the parent node to which the draggedItems are going to be added.
if (hierarchicalData && dropData)
targetParent = dropData.parent;
for each (var draggedItem:Object in draggedItems)
{
// do something with the draggedItem
}
}
protected function getDraggedItems(dragSource:DragSource):Object
{
if (dragSource.hasFormat("treeDataGridItems"))
return dragSource.dataForFormat("treeDataGridItems") as Array;
if (dragSource.hasFormat("items"))
return dragSource.dataForFormat("items") as Array;
if (dragSource.hasFormat("itemsByIndex"))
return dragSource.dataForFormat("itemsByIndex") as Vector.<Object>;
return null;
}
var dropData:Object = mx_internal::dropTarget._dropData;
should be
var dropData:Object = dropTarget.mx_internal::_dropData;
Try this.

Resources