I am trying to display sorting data in gridview from XML.
Operation of sorting is successful, but now how can I display all sorted data in gridview.
XML File:
<?xml version="1.0" encoding="utf-8"?>
<ProjectList>
<Business>
<ID>1</ID>
<Name>Rajan</Name>
<Mobile>123456</Mobile>
<Emailaddress>rajan#yahoo.co.in</Emailaddress>
<Date>24/01/2014</Date>
<Project>ttpl</Project>
</Business>
<Business>
<ID>12</ID>
<Name>nitant patel</Name>
<Mobile>123456</Mobile>
<Emailaddress>nitant#yahoo.co.in</Emailaddress>
<Date>27/01/2014</Date>
<Project>ttpl</Project>
</Business>
<Business>
<ID>10</ID>
<Name>Rajan10</Name>
<Mobile>123456</Mobile>
<Emailaddress>rajan#yahoo.co.in</Emailaddress>
<Date>24/01/2014</Date>
<Project>ttpl</Project>
</Business>
</ProjectList>
C# code:
XElement ProjectList = XElement.Load("Project.xml");
IEnumerable<XElement> ordered =
ProjectList.Elements().OrderBy(Business => int.Parse(Business.Element("ID").Value));
foreach (XElement element in ordered)
{
Console.Out.WriteLine(element.ToString());
}
gvdata.DataSource = ordered.ToList();
gvdata.DataBind(); //GIVE ME ERROR
ERROR is : The data source does not support server-side data paging.
I believe the issue is that the default Gridview may be trying to page the data...or at least, set it up for paging.
Try adding the 'AllowPaging="false"' attribute to your GridView tag, like so:
<asp:GridView ID="cantankerousgv" runat="server" AllowPaging="false">
//other GV stuff...
</asp:GridView>
Default behavior is often at the root of these kinds of issues.
Related
I'm creating a mx:tree with Flex 4 and the tree is being populated with an XMLList file, the file is updated from a database and what I'm trying to accomplish is to refresh the tree so that a different icon is shown depending on the state of completion of a course.
The problem is that the tree is not being updated but the XMLList file is, so I would really appreciate some help.
By the way, I don't know about Flex.
Here's the code:
public static var treeData:XMLList = new XMLList(MyString);
<mx:Tree id="myTree" width="40%" height="100%" labelField="#label" fontSize="14" focusColor="#ff5003"
render="renderTree()"
iconFunction="tree_iconFunc"
showRoot="false"
dataProvider="{treeData}"
change="treeChanged(event)"
depthColors="{myDepthColors}"
color="#006596" borderColor="#03B4EC"
click="SoundExample(String(selectedNode.#lesson)), habilitar()"
alternatingItemColors="{myAlternatingRowColors}"
/>
public function renderTree():void {
trace("Entró a renderTree");
initAppB();
if (refreshData){
myTree.invalidateList();
refreshData = false;
myTree.openItems = Globals.treeData;
myTree.validateNow();
}
}
Instead XMLList you could use bindable collection like ArrayCollection.
With it you don't need to invalidate tree manually. It will be updated automatically when ArrayCollection changes.
Also I'm not sure what do you mean by "the tree is being populated with an XMLList file, the file is updated from a database". Could you clarify?
To update a tree you have to update treeData:XMLList. If you want to replace it another value try the following:
[Bindable] //Notice this metadata
public var treeData:XMLList = new XMLList(MyString);
public function updateTreeData():void {
var text:String = ...; //loading text
treeData = new XMLList(text);
}
i have the following xml doc:
<?xml version="1.0" encoding="utf-8" ?>
<dropdowns>
<dropdown name="DropDownLoc">
<menu text="Select" value="-1" />
<menu text="North" value="1200" />
<menu text="South" value="1400" />
</dropdown>
<dropdown nome="DropDownEsp">
<menu text="Select" value="-1" />
<menu text="Est" value="7" />
<menu text="Ovest" value="9" />
</dropdown>
</dropdowns>
I want to read this xml and fill two dropdowns with a method given the dropdownlist name (like "DropDownEsp")
I want to accomplish this with linq, who can help me please ?
Below is code which would help you read XML and create a list of items (ListItem):
// or use XDocument.Parse("xml string") to parse string
XDocument xdoc = XDocument.Load(#"c:\testxml.xml");
var dropLists = xdoc.Descendants("dropdown")
.Select(d => d.Descendants("menu").Select(m =>
new /* new ListItem(text, value) */
{
Text = m.Attribute("text"),
Value = m.Attribute("value")
}))
.ToList();
Try adding items into controls yourself.
If you have an empty <asp:DropDownList ID="DynamicDropDown" runat="server" /> control on your .aspx page, you can data bind it a the results of a LINQ query like this:
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
// Assuming your XML file is in the App_Data folder in the root of your website
string path = Server.MapPath("~/App_Data/DropDowns.xml");
// Let's say we want to use the options from the second <dropdown>-tag in your XML
string whichDropDown = "DropDownEsp";
// This is the LINQ query to find those options from the XML
// and turn them into ListItem objects
var query =
from dropDown in XDocument.Load(path).Descendants("dropdown")
where dropDown.Attribute("name").Value == whichDropDown
from name in dropDown.Descendants("name")
let text = name.Attribute("text").value
let value = name.Attribute("value").value
select new ListItem(text, value);
// Now we data bind the query result to the control
DynamicDropDown.DataSource = query;
DynamicDropDown.DataBind();
}
}
In the LINQ query we first select only the <dropdown> element with the right name (based on the whichDropDown variable). Then we select all the <name> elements, and from each one we put the attributes in the text and value values. Then we use these values to create a new ListItem (one is created for each <name> element).
This result can then be used to data bind the <asp:DropDownList> control.
In my Flex app I am using a repeater to show a report on my database data. On this report the user can "drill-down" on the data to show more detail. In order to make this easier on the eye I have a header label and then a datagrid within the repeater.
Whilst this works perfectly, because the dataprovider for the datagrid comes from an array in the repeaters dataprovider, it is causing the following warning:
Data binding will not be able to detect assignments to "report"
The warning is for this line:
<mx:DataGrid id="dgReport" dataProvider="{rptReport.currentItem.report}" rowCount="{rptReport.currentItem.report.length}">
Below is my code, if anyone has any suggestions for how I can get rid of the warning/do this properly they will be most welcome!
<mx:Script>
<![CDATA[
[Bindable] private var reportProvider;
private function report_Handler(event:ResultEvent):void {
// Temp variables
var currentHeader:String = "";
var previousHeader:String = "";
// Retrieve PHP array
var reportPHP:Array = ArrayUtil.toArray(event.result);
// Create Flex array
var reportFlex:Array = [];
var reportFlex_dataGrid:Array = [];
// Loop through PHP array
for(var i:int = 0; i < reportPHP.length; i++) {
// Retrieve current header
currentHeader = reportPHP[i].header;
// Clear array
if (currentHeader != previousHeader) {
reportFlex_dataGrid = [];
}
reportFlex_dataGrid.push({column1:reportPHP[i].column1, column2:reportPHP[i].column2, column3:reportPHP[i].column3});
}
// Add to repeater array
if (currentHeader != previousHeader) {
// Add to array
reportFlex.push({header:reportPHP[i].header, report:reportFlex_dataGrid});
}
// Store previous headers
previousHeader = reportPHP[i].header;
// Add to combobox data provider
reportProvider = new ArrayCollection(reportFlex);
}
]]>
</mx:Script>
<mx:Repeater id="rptReport" dataProvider="{reportProvider}">
<mx:VBox>
<mx:Spacer height="5"/>
<mx:Label id="lblHeader" text="{rptReport.currentItem.header}"/>
<mx:DataGrid id="dgReport" dataProvider="{rptReport.currentItem.report}" rowCount="{rptReport.currentItem.report.length}">
<mx:columns>
<mx:DataGridColumn headerText="Column1" dataField="column1"/>
<mx:DataGridColumn headerText="Column2" dataField="column2"/>
<mx:DataGridColumn headerText="Column3" dataField="column3"/>
</mx:columns>
</mx:DataGrid>
</mx:VBox>
</mx:Repeater>
Data binding will not be able to detect assignments to "report"
Your dataProvider is rptReport.currentItem.report. Of this, rptReport, being an mxml element, is Bindable. The currentItem property of the Repeater component is also declared to be Bindable. The report property of the current item is not bindable - current item itself is just an object. Through this warning Flex is saying that if you alter the report of an already assigned object to something else, it won't be automatically reflected in the data grid.
In most cases you can safely ignore this type of warnings.
When you say x="{a.b.c.d}" in mxml, the guarantee is that flex will detect changes made to any of the four items in the chain (a, b, c and d) and update the value of x. In other words, x will change when a or a.b or b.c or c.d is changed. For this to work, Flex expects that all those four are declared bindable. If it finds any of these items to be not bindable, it will throw a warning. A property is bindable if it was declared using mxml or if it was declared with the [Bindable] metadata tag in ActionScript.
In most cases, one would be interested only in the changes to a or a.b. In your example, changes happen only when HTTPService is resend, in which case the dataProvider itself will change.
Dude, a little off-topic, but having a grid in a repeater sounds really busy. If you want to have a drill-down, pop it up or put it in a pane that's only visible in that mode.
Visually, the repeater is a pattern which the user can internalize. A grid inside that pattern is a lot harder to deal with. Scrolling the grid vs. scrolling the repeater will likely be frustrating, let alone Tab navigation.
Logistically, you are creating a lot of in-memory UI. I would worry about performance.
Consider using a List with a custom Item renderer instead of a repeater. I still would not put a grid in there, but it's worth the effort.
Cheers
How to remove validation programmatically from flex component
This is my method
public static function validateRequired(txt:TextInput, errorMessage:String="This field is required"):Boolean
{
var v:Validator = new Validator();
v.listener = txt;
var result:ValidationResultEvent = v.validate(txt.text);
var returnResult:Boolean = (result.type == ValidationResultEvent.VALID);
//Alert.show("validation result is " + returnResult);
if (!returnResult) {
v.requiredFieldError = errorMessage;
}
return returnResult;
}
But, as each time i am creating new validator, so pop-up contains multiple messages like
This field is required.
This field is required.
How to remove error messages attached with component?
I had the same problem, I understood that i had to clear the last validation before the next one.
private function resetValidationWarnings():void {
for each (var validator:Validator in arrValidators) {
validator.dispatchEvent(new ValidationResultEvent(ValidationResultEvent.VALID));
}
}
this is a kinda POG but it got the job done!
hope it helps !
The Validator.enabled property lets you enable and disable a validator. When the value of the enabled property is true, the validator is enabled; when the value is false, the validator is disabled. When a validator is disabled, it dispatches no events, and the validate() method returns null.
For example, you can set the enabled property by using data binding, as the following code shows:
<?xml version="1.0"?>
<!-- validators\EnableVal.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:ZipCodeValidator id="zcVal"
source="{inputA}"
property="text"
required="true"
enabled="{enableV.selected}"/>
<mx:TextInput id="inputA"/>
<mx:TextInput/>
<mx:CheckBox id="enableV"
label="Validate input?"/>
</mx:Application>
I also encountered similar problem. In my case, the root cause is I created the validator object every time the validation is called (just as you did). As a result, the UIComponent see it as different validator object (see UIComponent.errorObjectArray) and stored the error message again. The solution is to have a global or static validator and it solves the duplicate error message for me.
This is related to other question. But never mind it. I've fixed part of it.
I have a DataGrid, its data provider is a ArrayCollection, and i want it to parse all itens in it (Object Type) to a String.
For that I've done a "for each" loop, it manages to get the Object and its values, but if i have more that one object it only gets the last object, don't know why.
First i will show how these items are added to the ArrayCollection, that way you will understand the rest much easily.
In the Main Application i have the ArrayCollection:
<mx:ArrayCollection id="collection">
Then in other Component there is a Add Item Menu, and when you add a item:
private function fazerEncomenda():void
{
var novoitem:Object;
novoitem = new Object();
novoitem.id = "consumivel"+getProdInfo.lastResult.consumivel.id;
novoitem.tinteiroid = getProdInfo.lastResult.consumivel.id;
novoitem.label = getProdInfo.lastResult.consumivel.nome;
novoitem.ref = getProdInfo.lastResult.consumivel.refmarca;
novoitem.marca = getProdInfo.lastResult.consumivel.marca;
novoitem.genero = genero.text;
novoitem.quantidade = quantidade.text;
Application.application.collection.addItem(novoitem);
}
Then in another component the DataGrid as its dataProvider Binded to the ArrayCollection
<mx:DataGrid id="compras" x="0" y="0" width="556" dataProvider="{Application.application.collection}" editable="false">
<mx:columns>
<mx:DataGridColumn headerText="ID" dataField="tinteiroid" visible="false"/>
<mx:DataGridColumn headerText="Nome" dataField="label" width="120" />
<mx:DataGridColumn headerText="Ref" dataField="ref" width="100"/>
<mx:DataGridColumn headerText="Marca" dataField="marca" width="100"/>
<mx:DataGridColumn headerText="Género" dataField="genero" width="155"/>
<mx:DataGridColumn headerText="Quantidade" dataField="quantidade" width="81"/>
</mx:columns>
</mx:DataGrid>
And when a Button is pressed the function to get all Objects and its values to an String.
And in this function its where it only gets the last item, in the ArrayCollection.
for each (novoitem in compras.dataProvider)
{
finish += "TinteiroID:"+novoitem.tinteiroid+"#TinteiroLABEL:"+novoitem.label+"#TinteiroREF:"+novoitem.ref+"#TinteiroMARCA:"+novoitem.marca+"#TinteiroGENERO:"+novoitem.genero+"#TinteiroQUANTIDADE:"+novoitem.quantidade+"#FIMPROD#";
trace(finish);
}
And of course the Vars used in the function:
private var finish:String;
private var novoitem:Object
As you see in the finish var i used += so it adds it self and the next object. Instead he adds null. And only one null event if there was 3 items before.
Don't know whats the problem with this loop.
Please Help. I'm loosing my mind here.
PS: Sorry for any bad English, its been 3 hours in this. And no progress.
EDIT: Missing Vars Declaration Added
An easier way to do all this (admittedly not with the labels you specified) is to just use ActionScript's built in ObjectUtil.toString method.
You would write something like this:
import mx.utils.ObjectUtil;
public function dumpObj():void {
myTextField.text = ObjectUtil.toString(obj);
}
This should pretty much print out every property of every multiple / nested object you have.
HOWEVER - you should make a fundamental change to your component if you want it to be reusable. You need a getter/setter for your collection. In the component, add this code:
[Bindable]
private var _myCollection:ArrayCollection;
public function set myCollection (data:ArrayCollection) : void {
_myCollection = data;
}
public function get myCollection () : ArrayCollection {
return _myCollection;
}
There are several other ways to do this - look it up if you need something different.
In your datagrid, use the private ArrayCollection variable like this:
<mx:DataGrid id="compras" x="0" y="0" width="556" dataProvider="{_myCollection}" editable="false">
<mx:columns>
<mx:DataGridColumn headerText="ID" dataField="tinteiroid" visible="false"/>
...
In the main application, you can populate your component like this:
<kgtm:myComponent x="0" y="20" myCollection="{queryDataAC}"
And you name your ArrayCollection like this:
<mx:ArrayCollection id="queryDataAC">
in your top level Application code, you define the kgtm namespace, so you can use your custom component, like so:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:kgtm="com.kgtm.*"
Then put your component in the folder corresponding to this namespace definition.
This all leads to the final object print utility - which you define on the component, as it is the only thing that should know about how to print out it's data.
Define a public function, and get it to print out the private ArrayCollection data, using ObjectUtil or your own method.
public var getLastQueryOutput () : String {
private var output:String = "";
private var len:int = _myCollection.length;
for (var i:int = 0; i <len; i++) {
output = output +
"TinteiroID:"+_myCollection[i].tinteiroid+
"#TinteiroLABEL:"+_myCollection[i].label+
"#TinteiroREF:"+_myCollection[i].ref+
"#TinteiroMARCA:"+_myCollection[i].marca+
"#TinteiroGENERO:"+_myCollection[i].genero+
"#TinteiroQUANTIDADE:"+_myCollection[i].quantidade+
"#FIMPROD#";
}
trace(output);
}
Hopefully this will help. If you name the object correctly as you are putting it into the ArrayCollection, you can again just use ObjectUtil as I stated at the top.
Casp - Check out more of my (and my colleagues) blog entries here
Have you tried ".source" property of your array collection? I'm not sure if for-each loops work on ArrayCollection objects.
e.g.,
for each(novoitem in compras.dataProvider.source) { ... }
have you tried to just use a regular for loop
for (var i:int = 0; i < compras.dataProvider.length; i++) {
novoitem= compras.dataProvider[i];
trace(novoitem); // will output to the console during debugging.
...
}
in any case you shouldn't be looping on the dataProvider you sould be looping on the Application.application.collection
Guys i really want to thank you.
Thanks to your effort Glenn and AndrewB i did it. Once again thanks.
Now i will post the code so that someone with a similar problem can get some help.
Here goes the code to get the Objects and the Itens for each object inside a ArrayCollection.
[Bindable]
private var finish:String = "";
private var novoitem:Object
for (var i:int = 0; i <Application.application.collection.length; i++)
{
novoitem = compras.dataProvider[i];
finish = finish + "TinteiroID:"+novoitem.tinteiroid+"#TinteiroLABEL:"+novoitem.label+"#TinteiroREF:"+novoitem.ref+"#TinteiroMARCA:"+novoitem.marca+"#TinteiroGENERO:"+novoitem.genero+"#TinteiroQUANTIDADE:"+novoitem.quantidade+"#FIMPROD#";
trace(finish);
}
Thanks once again. I wanted to place both your awnsers as correct, but they aren't completely. So I've combined both to this code. And here it is.
I will be signing this answer as correct, but the credit its all yours. I wouldn't have it done if it weren't with you help.
EDIT
This is the code I've used however take a look at the code that "CaspNZ" as posted. Its probably a better and lighter approach in performance.