StrataFrame Forum

Trying to bind to an XtraReport

http://forum.strataframe.net/Topic3420.aspx

By Ivan George Borges - 10/9/2006

Hya.

I am trying to bind an XtraReport label to a BO field.

Does our BO implements the IList, ITypedList or IBindingList interface? That's what the XtraReport asks me in the help file.

I get an error after I set the report DataSource to the BO :

Private Sub RelEmpresasToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RelEmpresasToolStripMenuItem.Click

Dim Report As New rptEmpresas()

Dim loEmpresas As New ProFilmeNET_BOL.boEmpresas()

loEmpresas.FillDataTable("Select * from Empresas")

Report.DataSource = loEmpresas

Report.lblNome.DataBindings.Add("Text", loEmpresas, "emp_Descr")

Report.ShowPreviewDialog()

End Sub

Any word of advice to direct me in the right direction will be appreciated.

Thanks in advance.

By Trent L. Taylor - 10/9/2006

That is what the BusinessBindingSource control does for you.  If you drop (or create a variable) on you form, you can the set the BusinessObject property to any business object.  This basically wraps the BO and provides the IBindingList interface as well.
By Ivan George Borges - 10/10/2006

Thanks Trent.

I'm in a client right now, I will try it later.

By Ivan George Borges - 10/10/2006

I know it sounds stupid. But I'm extremely happy I put a simple report to work!

Thanks a lot Trent.

By StrataFrame Team - 10/10/2006

Glad you got it working, Ivan Smile
By Paul Chase - 10/13/2006

Ivan,

I was able to trick the Xtra Report into allowing you to drop a BusBinding Source and Bus object onto it. first create a base class report that implements IContainer. I still need to figure a few things out to make it better but below is what I have so far and seems to work. The Preview won't work but you can bind all the fields etc. But to be honest i am wondering if I even wnat to use BO's for the reports as it seems like most reports i have are base on query's with joins. But here is what I did maybe it will be helpful

Public Class XtraReportBase

Implements MicroFour.StrataFrame.UI.Windows.Forms.IContainerControl 'Add This Line

Public Sub New()

' This call is required by the Windows Form Designer.

InitializeComponent()

' Add any initialization after the InitializeComponent() call.

End Sub

Public Sub AddBusinessObject(ByVal BusinessObject As MicroFour.StrataFrame.Business.BusinessLayerBase) Implements MicroFour.StrataFrame.UI.Windows.Forms.IContainerControl.AddBusinessObject

End Sub

Public Sub AddObjectToInitOnLoad(ByVal ObjectToInit As MicroFour.StrataFrame.UI.IInitOnFormLoad) Implements MicroFour.StrataFrame.UI.Windows.Forms.IContainerControl.AddObjectToInitOnLoad

End Sub

Public Sub AddObjectToPreInitOnLoad(ByVal ObjectToPreInit As MicroFour.StrataFrame.UI.IPreInitOnFormLoad) Implements MicroFour.StrataFrame.UI.Windows.Forms.IContainerControl.AddObjectToPreInitOnLoad

End Sub

Public Sub RemoveBusinessObject(ByVal BusinessObject As MicroFour.StrataFrame.Business.BusinessLayerBase) Implements MicroFour.StrataFrame.UI.Windows.Forms.IContainerControl.RemoveBusinessObject

End Sub

End Class

Now go into the designer.vb file of the base report and change

Friend WithEvents Detail As DevExpress.XtraReports.UI.DetailBand

Friend WithEvents PageHeader As DevExpress.XtraReports.UI.PageHeaderBand

Friend WithEvents PageFooter As DevExpress.XtraReports.UI.PageFooterBand

to

Protected WithEvents Detail As DevExpress.XtraReports.UI.DetailBand

Protected WithEvents PageHeader As DevExpress.XtraReports.UI.PageHeaderBand

Protected WithEvents PageFooter As DevExpress.XtraReports.UI.PageFooterBand

 

Next create a new class that looks like below

Public Class InheritedReport

Inherits ReportBase.XtraReportBase ' The base class from above

Public Sub New()

InitializeComponent()

End Sub

Private Sub InitializeComponent()

End Sub

End Class

Rebuild and you should be able to get into the designer of your new subclassd report

Drop a business binding source and bus object on the form set the data source of the report to be the business binding source. The type editor of the business binding source will not work so you need to set it manually in the init component. Maybe this can figured out

Public Class InheritedReport

Inherits ReportBase.XtraReportBase

Friend WithEvents XrLabel1 As DevExpress.XtraReports.UI.XRLabel

Friend WithEvents BusinessBindingSource1 As MicroFour.StrataFrame.Business.BusinessBindingSource

Friend WithEvents BusinessObject11 As TEstBO.BusinessObject1

Private components As System.ComponentModel.IContainer

Public Sub New(Lcname as String)

InitializeComponent()

I also added the fill method here ? works

Me.BusinessObject11.FillByName(LcName)

End Sub

Private Sub InitializeComponent()

Me.components = New System.ComponentModel.Container

Me.XrLabel1 = New DevExpress.XtraReports.UI.XRLabel

Me.BusinessBindingSource1 = New MicroFour.StrataFrame.Business.BusinessBindingSource(Me.components)

Me.BusinessObject11 = New TEstBO.BusinessObject1(Me.components)

CType(Me, System.ComponentModel.ISupportInitialize).BeginInit()

'

'Detail

'

Me.Detail.Controls.AddRange(New DevExpress.XtraReports.UI.XRControl() {Me.XrLabel1})

'

'XrLabel1

'

Me.XrLabel1.Location = New System.Drawing.Point(33, 8)

Me.XrLabel1.Name = "XrLabel1"

Me.XrLabel1.Padding = New DevExpress.XtraPrinting.PaddingInfo(2, 2, 0, 0, 100.0!)

Me.XrLabel1.Size = New System.Drawing.Size(100, 25)

Me.XrLabel1.Text = "XrLabel1"

'

'BusinessBindingSource1

'

Me.BusinessBindingSource1.ParentForm = Nothing

'Manually add Line Below

Me.BusinessBindingSource1.BusinessObject = Me.BusinessObject11

'

'BusinessObject11

'

Me.BusinessObject11.ParentContainer = Me

Me.BusinessObject11.SynchronizingObject = Nothing

CType(Me, System.ComponentModel.ISupportInitialize).EndInit()

End Sub

End Class

 

Now to call the report...

Dim rpt As New TestAppReports.InheritedReport("TEST")

rpt.ShowPreview()

 

 

 

 

By Ivan George Borges - 10/13/2006

Hi Paul.

Thanks for your help!

I will study your code.

I have created an XtraReport abstract class, and in the inherited ones I've being writing code to bind the controls at runtime.

I've been able to run the reports using the BOs, but I've been creating them at runtime. I'm not binding the report controls at design time. So, I use the BOs to populate the information I need, then add them to a DataSet, working with the results there. So far, I haven't created very complex reports, yesterday I managed to make a Master-Detail report to work using the BOs in this way. But you are right, I wonder what the best practice will be when a more complex situation arrives. As usual, I think I will let Trent, Ben and Steve worry for me. BigGrin

I bet they are gonna jump in and say something.Wink

By Paul Chase - 10/13/2006

Ivan,

I have been struggling with the concept of how I want to deal with Reports and Data Access for the last few days and I can't seem to decide how best to implement it.

I guess it would be nicer to have all the data access come from a bus object library. But at the same time with joined queries for reporting it makes it a bit trickier. I guess you would have to create a view and base a bo off the view.

At the same time it is simple enough to create the typed DS right in the report. but you need watch connection strings etc.

I guess it really doesnt matter.

By Trent L. Taylor - 10/13/2006

Well if it were me I would not venture too far from the business objects.  You can create any type of JOIN query from within a BO to return any fields that you want.  You can create a view, as you mentioned, to pull back all of the fields you want in a flat format.  If you need to create custom fields or a BO that supports a special DDT layout and then your FillDataTable(...) method pulls data using the inner join, you can.  When you start dealing with typed data sets you are heading for frustrations the first time you want to make a change.  There are a lot of different ways to "skin the cat" so to speak...but you also want to make sure that you are not painting yourself into a corner down the road.

Any of these options, including the typed data set, will work.  But when you start pulling connection strings and talking directly to the data you are breaking encapsulation so if some day you want to change your back end...including the Middle Tier Enterprise Server, your reports will break.  If you work inside the confines of the business object you can change your backend database or connect to the Enterprise Server interchangeably without having to change this code.

Note: Any custom connection you make outside of the logic of the framework will prevent the data access layer from being interchangable without having dramatic side-effects within your application...this includes the Middle Tier Enterprise Server that will be released by the end of the year.

By Ivan George Borges - 10/13/2006

Hi guys.

Trent L. Taylor (10/13/2006)
Well if it were me I would not venture too far from the business objects. 

This is exactly what I keep in mind. I realize there's a whole attention built inside the BOs, and for a start I want to take advantage of not having to worry about it. And then, there's the back end, and the Middle Tier. I will stick to the BOs.

You can create any type of JOIN query from within a BO to return any fields that you want.  You can create a view, as you mentioned, to pull back all of the fields you want in a flat format.  If you need to create custom fields or a BO that supports a special DDT layout and then your FillDataTable(...) method pulls data using the inner join, you can.

This is where I need to get proficiency at. But seeing you say it is possible, is already a good incentive.

So, Paul, I think we will be safer under the wings of the BOs. Guess we just have to find our way in it.

By Paul Chase - 10/13/2006

Thanks Trent that helps somewhat and answers alot of the issues I have been knocking around. I defiinatly would rather use the BO's but was not sure on the joined query's .

One of the issues I have is that I HATE doing reports.. When I first started in IT that is all I did for many years.

I want to be able to set up the query and any grouping on the report and have one of the girls do the tedious pretty work. This does require that the fields be bound to something at design time.

I will probably have specific questions on how to set up a bo to support a joined query and provide the strongly typed fileds required to make design time report binding possible. I just havent had a chance to try it so don't know. 

Paul


 

By StrataFrame Team - 10/13/2006

Well, Paul, when you get those specific questions, send them to us and we'll certainly try to get them answered.
By Paul Chase - 10/13/2006

Trent,

Below is query that I had just had to create for our accounting department. I have no idea how I would be able to use business objects to create a design time datasource for a report based on this query. I have to create a stored proc(parameters) or query a view of the joined data, or I use the sql data adapter method on the report and generate the table which I don't like.

For reporting you do not need to be able to insert update or delete which is the reason that business objects are what they are. However with a report you do not need that funtionality.

Would it be possible to create another type of object? A stripped down business object call it a report object that is strongly typed based upon the fields returned from the select query? This would provide for a read only view of data that could be bound in reports grids etc.

Maybe i am missing something but I just cannot seem to get my head around this so please be patient if I am in left field somewhere but the light is just not coming on Smile

SELECT ECOApplyTo.CUSTNMBR as [Customer Id], RM00101.CUSTNAME as [Customer Name],

RM00201.CLASDSCR as [Office], RM20101.CHEKNMBR as [Check Number], ECOApplyTo.DATE1 as [Applied Date],ECOApplyTo.APFRDCNM as [Audit Trail],

ECOApplyTo.ActualApplyToAmount, ECOApplyTo.APTODCDT as [Invoice Date], RM00101.CUSTCLAS,

RM20101.ORTRXAMT as [Original Invoice Amount],ECOApplyTo.APPTOAMT as [Amount Applied],

CAST(ECOApplyTo.DATE1 - ECOApplyTo.APTODCDT AS int) AS Age, ALM_RM20201X.DOCNUMBR as [Invoice Number], ALM_RM20201X.CURTRXAM as [Current Invoice Balance],

(case when CAST(ECOApplyTo.DATE1 - ECOApplyTo.APTODCDT AS int) > 50 then ActualApplyToAmount else 0 end) as inEligable ,

(case when CAST(ECOApplyTo.DATE1 - ECOApplyTo.APTODCDT AS int) < 51 then ActualApplyToAmount else 0 end) as Eligable ,

DateAdd(day, -1 * datepart(dw, Date1), Date1 ) as week

FROM RM00101 INNER JOIN

ECOApplyTo ON RM00101.CUSTNMBR = ECOApplyTo.CUSTNMBR INNER JOIN

RM00201 ON RM00101.CUSTCLAS = RM00201.CLASSID INNER JOIN

RM20101 ON ECOApplyTo.APFRDCNM = RM20101.DOCNUMBR INNER JOIN

ALM_RM20201X ON ECOAPPLYTO.APTODCNM = ALM_RM20201X.DOCNUMBR

WHERE RM20101.RMDTYPAL = 9 and date1>= @FromDate and date1 <=@ThruDate

and Substring(CUSTCLAS,1,3) = @OfficeID

order by CLASDSCR,week,[Customer Id]

 

By StrataFrame Team - 10/13/2006

You can done one of a few things, Paul:

1) Create a fake table in some temp database in SQL Server that has the same structure as the results of your join and build the business object off of that.  Then, you will automatically have your strong-typed fields becuase the BOMapper will be able to "see" the object that has the structure that you want.

2) Create a fake table in some temp profile in the DDT that has the same structure as the results of your join... same thing as the one above...

Once you build the business object through the BOMapper, it becomes a strong-typed design-time data source for your report.  So, no matter what the crazy structure of your report, you can always create a business object that matches the structure by creating "dummy" structure sources in either the DDT or SQL Server.

By Ivan George Borges - 10/13/2006

Sorry for the stupid question Ben.

I got the idea for the dummy table in the DDT, a fake Database there, and then map the BO.

Then, after instanciating the BO, I would just create a fill method with Paul's sql statement and be happy forever?

By StrataFrame Team - 10/13/2006

Hehe, no questions are stupid, that's for sure... and yes, you have it right.
By Ivan George Borges - 10/13/2006

Hey, Paul.

I did the changes you mentioned before to get the BO dropped into the designer. It worked fine!!!

But have you tried the "Preview" ?  I get an error message like this:

Serialization Error

81:  The type or namespace name 'tboTeste' does not exist in the namespace 'ProFilmeNET_BOL' (are you missing an assembly reference?)


 

By Paul Chase - 10/13/2006

Yeah I havent figured out how to make that work.. Dont hit HTML it will crash visual studioSmile
By Ivan George Borges - 10/14/2006

too late ...BigGrin
By Paul Chase - 10/16/2006

Ben,

I understand what you are saying about using a temp table to allow me to generate the fields for strong typing to be able to use the report designer at designtime. That should work ok but I would like to create a seperate report object type that would use the strataframe DAL but be generated using the schema returned from a select statement. This should give me the strong typing I would like as well as allow me some flexibility in having it able to work with Xtra Reports.   

I guess I am just trying to make the reporting process seem a bit more straight foward and maybe I am complicating it more than it needs to be but for some reason reporting in .net seems to be a pain in the neck. Anyways if worse come to worse I know that I can do as you suggested and it will work.

Paul

By Tim Dol - 10/16/2006

Hi Ivan,

I'm also having problems dropping a BO onto the report designer so I can pick and choose the fields I want. I was able to drop the BusinessBindingSource but got an error trying to assign a BO. 

How did you get this working?

Thanks,
Tim

By Paul Chase - 10/16/2006

Tim you need to manually assign the bus object to the binding source in the code behind of the report.