Ulrich Palmer
10.19.2011
Hi Kris,
Thank you for contacting us. We confirm that this behavior is by design. The subreport's source cannot be set to the same report instance to prevent a deadlock situation.
You will need to create a separate XtraReport class (f.ex. MySubreport1, MySubreport2) to resolve this issue.
Thanks,
Alex
Hello Alex,
Creating two identical subreports that call each other is ultimately what I had to do but is a very ugly solution as I will now have to maintain two reports that serve the exact same purpose.
Yes, I understand that deadlocks are an inherent risk when using recursion. Despite this, recursion is a fundamental programming technique that every decent programmer uses. Every half decent programmer will know how to prevent a deadlock situation. You telling me that I can't use recursion with your tools is akin to a knife salesman selling dull knives because people using them could get cut.
So is this behaviour really by design or is there some other reason for this? If 'preventing deadlock situations' is the only reason for preventing recursion in subreports I urge you to remove this restriction as recursive reports are going to be a big part of our application's reports. Two identical subreports is not an acceptable solution.
If you are not the right person to make these kind of decisions I would appreciate it if you forwarded this message to someone who is.
Thanks,
Kris
Elliot,
Did you even read the whole thread? The solution, albeit a very ugly one, has already been found. My problem now is that we will need recursive subreports in the future and maintaining two separate and identical subreports to fake recursion is not an acceptable solution.
My problem is that recursion in subreports is a functionality that seems to be disabled for a very pointless reason. My question again is: Is recursion in subreports really only disabled for the reasons mentioned above (to prevent gridlock)? Or are there any other reasons for not allowing this that I might not be aware of? If not then I again urge you to remove this restriction as recursive subreports is the only way certain data structures can be represented in a report.
Guys, please don't bother replying if you haven't read and understood the entire thread. I don't want to repeat myself a third time.
Thanks,
kris
Hi Kris,
Actually, we do understand your question and indeed usually to build the tree is necessary to use recursion. Nothing complex. Here is the standard way how to browse the tree using recursion:
[C#]public void ProcessTree(TreeNode node) { for(int i = 0; i < node.GetNodeCount(); i++) ProcessTree(node.Nodes[i]); }
This code is very simple, however, using it I can show you that implementing it in the reports is very strange. For example, first, any SubReport's ReportSource should have the DataSource to display relevant data. In my code, this is the TreeNode object passed to the ProcessTree method. If you just set the SubReport's ReportSource to point to itself, this won't work. So, my question is: how are you planning to set the DataSource for the report in this case? Please note, this cannot be done on our level as data provided by the customer can be different. So, it is definitely necessary to create an interface or require a customer to support a certain interface so that our engine can work with it properly and determine the number of child nodes and build the report.
Finally, one of the most important factor is memory. Every report (especially if it is large) occupies a lot of memory. This scenario with many nested subreports will allocate a lot of memory and thus it is better to create a single report which holds all required elements inside.
So, to conclude my long post: we can implement this functionality in the report's engine. But, most likely, this won't be popular due to obvious limitations which are impossible to workaround.
Thanks,
Plato
Hello Plato,
Thanks for taking the time to read this thread and understanding my problem.
Let me address your question. "If you just set the SubReport's ReportSource to point to itself, this won't work. So, my question is: how are you planning to set the DataSource for the report in this case?"
I have a flat XML structure (example at the bottom of this post) where each node contains an ID and the ID of it's parent node. This means that I can pass the exact same XML datasource to the nested report and use parameters to figure at which node I currently am. This is how the subreport's BeforePrint method should look like in the TestSubReport class:
private void xrSubreport1_BeforePrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
xrSubreport1.ReportSource = new TestSubReport();
((TestSubReport)((XRSubreport)sender).ReportSource).ID.Value = Convert.ToInt32(GetCurrentColumnValue("ID"));
((TestSubReport)((XRSubreport)sender).ReportSource).XmlDataPath = this.XmlDataPath;
}
As you can see the subreport contains the parameter ID to which I assign the ID of the current column. Now all I have to do is add a filter that compares the passed parameter in ID from the subreport with the ParentID of the elements in the nested subreport. The filter expression looks like this: [ParentID] = ?ID
This way I will always get the correct nodes to show in the current subreport.
As you can see from the XML below, the top nodes of the tree have a ParentID of 0. So all I have to do in my main report is call the subreport and give the parameter of ID a value of 0. In the code of the main report this is how the BeforePrint method of the subreport should look like:
private void xrSubreport1_BeforePrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
((TestSubReport)((XRSubreport)sender).ReportSource).ID.Value = 0;
((TestSubReport)((XRSubreport)sender).ReportSource).XmlDataPath = this.XmlDataPath;
}
I know this works because I've basically done the same thing by having two exactly identical subreports that reference each other. The subreports are called TestSubReport1 andTestSubReport2 and the BeforePrint functions set the reportsource to the other report exactly like Alex said in his first reply to this post.
TestSubReport1 class file:
private void xrSubreport1_BeforePrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
xrSubreport1.ReportSource = new TestSubReport2();
((TestSubReport2)((XRSubreport)sender).ReportSource).ID.Value = Convert.ToInt32(GetCurrentColumnValue("ID"));
((TestSubReport2)((XRSubreport)sender).ReportSource).XmlDataPath = this.XmlDataPath;
}
TestSubReport2 class file:
private void xrSubreport1_BeforePrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
xrSubreport1.ReportSource = new TestSubReport1();
((TestSubReport1)((XRSubreport)sender).ReportSource).ID.Value = Convert.ToInt32(GetCurrentColumnValue("ID"));
((TestSubReport1)((XRSubreport)sender).ReportSource).XmlDataPath = this.XmlDataPath;
}
The above solution works perfectly. I have ommited the code that prevents an infinite loop to keep the example simple. I also did not run into any memory problems even after generating a report with a huge tree. The obvious problem I now have with this solution is that it is very ugly since I have to maintain two different reports that do the exact same thing.
I hope I've now made it clear that it is technically possible to have recursion in subreports and that your arbitrary restriction on this is pointless. Allowing this without having to do the ugly workaround above would make your reporting platform so much more flexible and will open up a lot of new possibilities.
Please consider removing this restriction.
Thanks,
Kris
<Node>
<Name>Beschaffung</Name>
<ID>16350</ID>
<ParentID>0</ParentID>
</Node>
<Node>
<Name>Bestellung</Name>
<ID>16353</ID>
<ParentID>16350</ParentID>
</Node>
<Node>
<Name>sub 1</Name>
<ID>18178</ID>
<ParentID>16353</ParentID>
</Node>
<Node>
<Name>sub sub 1</Name>
<ID>18182</ID>
<ParentID>18178</ParentID>
</Node>
<Node>
<Name>sub 2</Name>
<ID>18188</ID>
<ParentID>16353</ParentID>
</Node>
<Node>
<Name>Wareneingang</Name>
<ID>16355</ID>
<ParentID>16350</ParentID>
</Node>
<Node>
<Name>Rechnungsverarbeitung</Name>
<ID>16357</ID>
<ParentID>16350</ParentID>
</Node>
<Node>
<Name>Zahlungsausgang</Name>
<ID>16359</ID>
<ParentID>16350</ParentID>
</Node>
<Node>
<Name>Lieferantenstammdaten</Name>
<ID>16361</ID>
<ParentID>16350</ParentID>
</Node>
<Node>
<Name>Produktion</Name>
<ID>16363</ID>
<ParentID>0</ParentID>
</Node>
<Node>
<Name>Lagereingang</Name>
<ID>16365</ID>
<ParentID>16363</ParentID>
</Node>
<Node>
<Name>Lagerabgang</Name>
<ID>16367</ID>
<ParentID>16363</ParentID>
</Node>
Hi Kris,
This bug was fixed in the XtraReprots suite version v2011 vol1.9. So, you are welcome to request a fix. For more details about this service, please read Julian's blog at http://community.devexpress.com/blogs/ctodx/archive/2008/07/10/getting-your-fix-the-devexpress-way.aspx
Thanks,
Elliot
Is your intention to post an answer to your own question?
- If so, then proceed.
- If you simply wanted to post additional information, ask for further clarification, or to just say "Thanks!", please click Leave a Comment.
- If you wish to edit your original question, please use the Edit button in the Toolbox at the top right corner of that entry.
Facebook
Twitter
Google+