I am completely new to reporting in visual studio C#..I tried searching for some tutorials for beginners but i was unsuccessful..I just found code examples that didn't really explain the basics...I wrote some code which complies and runs fine but it DOES NOT SHOW ANYTHING in the report viewer control in Visual Studio 2013..My code is as follows:
// This method is in a class named Customers.
// When the user clicks the first column of the datagrid view(I have placed a button
// in the first column of the datagrid) a new form opens (ReportForm) and i pass
// the DataSet called dsReport to its constructor.
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0 )
{
DataSet dsReport = new DataSet();
DataTable tbl = dsReport.Tables.Add();
tbl.Columns.Add("CustomerName", typeof(string));
tbl.Columns.Add("CustomerAddress", typeof(string));
tbl.Columns.Add("MaritalStatus", typeof(string));
tbl.Columns.Add("CustomerType", typeof(string));
tbl.Columns.Add("ImagePath", typeof(string));
foreach (Customer cust in customerList)
{
DataRow dr = dsReport.Tables[0].NewRow();
dr["CustomerName"] = cust.Name;
dr["CustomerAddress"] = cust.Address;
dr["MaritalStatus"] = cust.MaritalStatus;
dr["CustomerType"] = cust.CustomerType;
dr["ImagePath"] = cust.ImagePath;
dsReport.Tables[0].Rows.Add(dr);
}
ReportForm report = new ReportForm(dsReport);
report.Show();
}
}
//Following is the code for the ReportForm Class
//I do not get any results in the report viewer
//I just see the message "The source of the report definition has not been specified"
public ReportForm(DataSet dsReport)
{
InitializeComponent();
this.reportViewer1.LocalReport.DataSources.Clear();
this.reportViewer1.LocalReport.DataSources.Add(myReportSource);
this.reportViewer1.ProcessingMode = ProcessingMode.Local;
this.reportViewer1.LocalReport.Refresh();
this.reportViewer1.RefreshReport();
}
private void ReportForm_Load(object sender, EventArgs e)
{
this.reportViewer1.RefreshReport();
}
/* Please note that I have run the code in the debugger and the dataset is being
populated properly and so is the reportViewer1.LocalReport..Also I HAVE NOT
Added any datasources to the project AND I HAVE NOT ADDED ANY Report files(.rdl) files
to the Project */
Lastly can anyone PLEASE answer the following questions:
Q1. Do i absolutely have to include a datasource to work with the report
viewer tool??
Q2. Do i have to include a .rdl file in the project to display a report??
Q3. Is the report viewer tool and a .rdl file one in the same or are they
different??
The ReportViewer is a control that knows how to render a report. It just handles the drawing and some other background tasks, it isn't the actual report. The actual report is the .rdl file (Report Definition Language). It contains all the instructions for generating the report, but it doesn't contain the actual data. The DataSource contains the data that the report operates on.
So to answer your questions specifically:
yes (unless your report is completely static and doesn't use any data).
no, but you need get the .rdl to the ReportViewer somehow. If you don't want to include it as a file you can embed it as a resource in your application, or even hard code it as a string. The ReportViewer has a method that accepts a Stream also, so anything that can provide a stream can act as the source for the .rdl.
They are different, as I explained at the very start.
Related
Good day everyone,
Firstly I would like to thank anyone in advance who takes the time to look through this lengthy post.
Context: I am building a simple GUI interface using windows forms and c sharp that connects to a MySql database to perform CRUD operations.
Problem: I am trying to implement a method that would take the necessary MySql code elements as arguments and pull a table into a data grid view. I have produced 2 methods - 1 that takes arguments and the other one which is hard coded to pull the data.
After pulling the data I am able to insert/amend any records in the database with a SAVE button method. The issue is that when I use the method that takes the arguments to pull the data into the grid view I am not able to SAVE my changes as I get a null reference error. However when using the hard coded method I don't get any null errors and all works fine. For some reason when the sqlDataand dataTable variables are passed to the SAVE button method AFTER the grid view gets filled with the method based on arguments they end up as null. Any experts that have experience building these applications have any advice please?
Hard coded method for pulling data into grid view:
private void fill_grid_view1(string sequelQueryString)
{
using (MySqlConnection mysqlConn = new MySqlConnection(db_connection))
{
mysqlConn.Open();
sqlData = new MySqlDataAdapter(sequelQueryString, mysqlConn);
sqlCommandBuilder = new MySqlCommandBuilder(sqlData);
dataTable = new DataTable();
sqlData.Fill(dataTable);
dataGridView1.DataSource = dataTable;
}
}
The SAVE button methods:
private void bttnSave_Click(object sender, EventArgs e)
{
save_changes_refresh(sqlData, dataTable);
}
private void save_changes_refresh(MySqlDataAdapter given_data_adapter, DataTable given_data_table)
{
try
{
given_data_adapter.Update(given_data_table);
select_both_user_tweet();
MessageBox.Show("Your changes have been saved successfully!"); //
}
catch (Exception errobj)
{
MessageBox.Show(errobj.Message.ToString());
}
}
The method I want to use to pull data into grid view based on given arguments:
private void fill_given_grid_view (string sequelQueryString, MySqlDataAdapter given_data_adapter, DataTable given_data_table, DataGridView given_grid_view,
MySqlCommandBuilder given_builder)
{
using (MySqlConnection mysqlConn = new MySqlConnection(db_connection))
{
mysqlConn.Open();
given_data_adapter = new MySqlDataAdapter(sequelQueryString, mysqlConn);
given_builder = new MySqlCommandBuilder(given_data_adapter);
given_data_table = new DataTable();
given_data_adapter.Fill(given_data_table);
given_grid_view.DataSource = given_data_table;
}
}
All the new method does is pull data based on arguments so that if I had let's say 5 dataGridView elements I wouldn't need to hard code all five pull methods separately like I did in the first code snippet. And it works but it doesn't let me save any changes as mentioned above because of the sqlData and dataTable variables end up as null when I try to execute the save method.
Method that passes the needed parameters to fill_given_grid_view:
private void view_users_Click(object sender, EventArgs e)
{
fill_given_grid_view("SELECT * FROM new_schema.user", sqlData, dataTable, dataGridView1, sqlCommandBuilder);
}
EDIT: I've read the possible duplicate thread and it is useful however I struggle to understand why essentially using 2 methods that do the same thing one of them drops the sqlData and dataTable variables to null and the hard coded method from the first snippet does not drop the variables and keeps the needed values to pass into the SAVE method.
Based on #Reniuz suggestions the fill_given_grid_view and save_changes_refresh methods had to be rewritten to take in dataGridView and sequelQueryString as arguments. sqlData and dataTable variables are not used anywhere as input to a method. Code examples below:
Method to pull data into a grid view based on input:
private void fill_given_grid_view (string sequelQueryString, DataGridView given_grid_view) /* master method that takes an SQL query and grid view as input
and displays a table accordingly */
{
using (MySqlConnection mysqlConn = new MySqlConnection(db_connection)) // using stored connection params
{
mysqlConn.Open();
sqlData = new MySqlDataAdapter(sequelQueryString, mysqlConn);
sqlCommandBuilder = new MySqlCommandBuilder(sqlData);
dataTable = new DataTable(); // new dataTable created, filled based on given query and set as the DataSource of the grid given as input to the method
sqlData.Fill(dataTable);
given_grid_view.DataSource = dataTable;
}
}
SAVE method rewritten with grid view and sequel string as arguments:
private void save_changes(string sequelQueryString, DataGridView given_grid_view) /* master save method that initializes a new Data Adapter based on given sequel string
that saves any changes inputted into the given grid view */
{
using (MySqlConnection mysqlConn = new MySqlConnection(db_connection))
{
mysqlConn.Open();
sqlData = new MySqlDataAdapter(sequelQueryString, mysqlConn);
sqlCommandBuilder = new MySqlCommandBuilder(sqlData);
var current_data_table = (DataTable)given_grid_view.DataSource; // if any changes occur in given grid view db table is updated when a "SAVE" button is clicked
sqlData.Update(current_data_table);
}
}
In my Form I have this code to open my report on a click of Button:
private void btnGroupOther_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
LayoutControl lc = new LayoutControl();
lc.Dock = DockStyle.Fill;
DateEdit FirstDate = new DateEdit();
DateEdit LastDate = new DateEdit();
lc.AddItem(Resources.firstdate, FirstDate).TextVisible = true;
lc.AddItem(Resources.seconddate, LastDate).TextVisible = true;
lc.Height = 70;
this.Controls.Add(lc);
this.Dock = DockStyle.Top;
if (DevExpress.XtraEditors.XtraDialog.Show(lc, " ", MessageBoxButtons.OKCancel) == DialogResult.OK)
{
RepProductionGroupOther report = new RepProductionGroupOther();
report.DataSource = paint.RepProductionGroupOther(Convert.ToDateTime(FirstDate.EditValue).ToString("MM/dd/yyyy"),
Convert.ToDateTime(LastDate.EditValue).ToString("MM/dd/yyyy"));
report.ShowRibbonPreviewDialog();
}
}
In my header report I have two xrLabel; the first one txtFirstDate and the second one txtLastDate. I want to show the value of FirstDate DateEdit control in txtFirstDate and the value of LastDate DateEdit control in txtLastDate.
How can I do that, the DataSource of the report is sql stored procedure.
It has two Parameters: #FirstDate and #LastDate.
Thanks in advance
I suggest you to go through XtraReport documentation:
Request and Pass Report Parameter Values
private void button1_Click(object sender, EventArgs e) {
// Create a report instance.
XtraReport1 report = new XtraReport1();
// Obtain a parameter and set its value.
report.Parameters["parameter1"].Value = 30;
// Hide the Parameters' UI from end-users (if you did not hide it at design time).
report.Parameters["parameter1"].Visible = false;
// Show the report's print preview depending on your target platform.
// ...
}
Check the "Custom Parameter Editors" section in above documentation
Custom editor implementation for parameters varies depending on your application's platform:
Windows Forms
In Windows Forms applications, you can provide custom parameter editors in the XtraReport.ParametersRequestBeforeShow event handler.
For a code sample, see Provide Custom Editors for Report Parameters.
Below are similar implementation as you are trying to do.. Check these, hope this will help you resolve the issue.
How to pass parameters to devexpress XtraReport from combobox
DevExpress XtraReport Setting a DateTime Parameter to Today
Passing parameters to Xtrareports repx file
I have a small Winforms project. .NetFramework 4.5, CR 13.0.14. In a ReportForm:
public partial class ReportForm : Form
{
private readonly string _batchNumber;
public ReportForm(string batchNumber)
{
_batchNumber = batchNumber;
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
APGreenSheets report = new APGreenSheets();
DataSet data = AccountsPayableController.FillDataSet();
report.SetDataSource(data);
report.SetParameterValue("BatchRef", _batchNumber);
crystalReportViewer1.ReportSource = report;
crystalReportViewer1.RefreshReport();
base.OnLoad(e);
}
}
In my CR report I have a Parameter Field “BatchRef” defined as a string.
My Record Selection Formula is: {AP_HistoryHeader.strBatchRef} = {?BatchRef}
When ReportForm loads (passing in the Batch Number reference) the report still prompts me before it will load. I can type it in manually and that will work. But I have Set the Parameter after I set the DataSource to avoid that. Thanks in advance.
Don Williams at SAP provided me the correct answer after a few other code checks:
Simply remove the line crystalReportViewer1.RefreshReport();
This did the trick. Apparently the refresh part wants to renew the passed Parameter. It turns out, I didn't need it to display the report in the first place.
Thanks to Don!
I am new to Crystal report, application is in ASP.net 3.5 and MySQL 5.1, going to develop report between dates like from date and to date, first page of report is shown good but when i tried to navigate on another page i got error like Missing Parameter Values same error i got in Printing and Export action
Thanks in advance
public partial class BookingStatement : System.Web.UI.Page
{
//DAL is my Data Access Layer Class
//Book is ReportClass
DAL obj = new DAL();
Book bkStmt = new Book();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//crvBooking is Crystal Report Viewer
//reportFill method is to fill Report
reportFill();
crvBooking.EnableViewState = true;
crvBooking.EnableParameterPrompt = false;
}
/* Also try reportFill() out side !IsPostBack but didn't work */
//Check if the parmeters have been shown.
/* if ((ViewState["ParametersShown"] != null) && (ViewState["ParametersShown"].ToString() == "True"))
{
bkStmt.SetParameterValue(0, "20/04/2010");
bkStmt.SetParameterValue(1, "20/04/2010");
}*/
}
protected void crvBooking_navigate(object sender, CrystalDecisions.Web.NavigateEventArgs e)
{
// reportFill();
}
protected void reportFill()
{
//bkStmt.rpt is Report file
//bookingstatment is View
//bkStmt is ReportClass object of Book
string rptPath = "bkStmt.rpt";
string query = "select * from bookingstatment";
crvBooking.RefreshReport();
crvBooking.Height = 600;
crvBooking.Width = 900;
bkStmt.ResourceName = rptPath;
String dtFrm = bkStmt.ParameterFields[0].CurrentValues.ToString();
obj.SetCommandType(CommandType.Text);
obj.CommText = query;
DataTable dtst = obj.GetDataTable();
crvBooking.ParameterFieldInfo.Clear();
ParameterDiscreteValue discretevalue = new ParameterDiscreteValue();
discretevalue.Value = "20/04/2010"; // Assign parameter
ParameterValues values = new ParameterValues();
values.Add(discretevalue);
bkStmt.SetDataSource(dtst);
ViewState["ParametersShown"] = "True";
crvBooking.EnableViewState = true;
bkStmt.DataDefinition.ParameterFields[0].ApplyCurrentValues(values);
bkStmt.DataDefinition.ParameterFields[1].ApplyCurrentValues(values);
crvBooking.ReportSource = bkStmt;
}
}
The problem seems to occur because Crystal Reports does not persist its parameter values in its ViewState when a postback occurs. So when the CrystalReportViewer attempts to load up the ReportClass it used as its ReportSource again, the parameter values are no longer there.
A solution which we've used successfully is to save the ReportClass (i.e. your Crystal Report object) into Session after all its parameter values have been set & then load this into the CrystalReportViewer upon each PostBack in the Page_Init event. An example:
// instantiate the Crystal Report
var report = new DeliveryLabelsSingle();
// set the required parameters
report.DataSourceConnections[0].SetConnection("DBServer", "DatabaseName", "DatabaseUser", "DatabasePassword");
report.SetParameterValue("#Param1", "val1");
report.SetParameterValue("#Param2", "val2");
// set the data source of the viewer
crvLabels.ReportSource = report;
// save the report object in session for postback binding
Session["rptDeliveryLabels"] = report;
Then the Page_Init event for the page looks like the following:
protected void Page_Init(object sender, EventArgs e)
{
if (IsPostBack) {
if (Session["rptDeliveryLabels"] != null) {
// cast the report from object to ReportClass so it can be set as the CrystalReportViewer ReportSource
// (All Crystal Reports inherit from ReportClass, so it serves as an acceptable data type through polymorphism)
crvLabels.ReportSource = (ReportClass)Session["rptDeliveryLabels"];
}
}
}
In this way, we will always set a report object for the viewer, which has already been initialized with the appropriate values.
Something to keep in mind with this approach is that you will potentially fill up your server memory very quickly, especially if you have lots of users generating lots of different reports. So some housekeeping is in order. We've done this through implementing a base class for all our ASP.NET pages that contain a report (and thus this report loading code). In this base class, we set all possible Session variables that are reports to null. Like so:
// class definition for ASP.NET page containing CrystalReportViewer & associated report(s)
public partial class DeliveryLabelPrint : BaseReport
Then the definition for BaseReport is as follows:
public class BaseReport : System.Web.UI.Page
{
protected override void OnLoad(EventArgs e)
{
if (!IsPostBack) {
for (var i = 0; i < Session.Count; i++) {
var sv = Session[i];
// if this session variable contains a Crystal Report, destroy it
if (sv is ReportClass) {
sv = null;
}
}
base.OnLoad(e);
}
}
}
In this way, you ensure that any user only ever has one report in memory at any given time.
If memory is a concern, even with this approach, an alternative could be to store the individual variable values in Session & to then instantiate a new report in Page_Init & repopulate it with the saved values before assigning it to CrystalReportViewer.ReportSource. But in our case, with 40 users pulling 50+ different reports on a daily basis, this implementation of storing of the ReportClass object & the accompanying housekeeping, we haven't run into any memory problems since the application went live 3 years ago. I would still suggest doing appropriate load testing & monitoring before pushing this solution to production, as the results may vary depending on the specific implementation.
When I am writing SQL for a Crystal report, the code for the parameters in SQL is like this:
--Date Range
(
(table.datetime >= '{?Start Date}')
and table.datetime < '{?End Date}')
)
--Location
('{?Facility}'= 'All' OR '{?Facility}' = table.location))
Of course you always have the option of programming the parameters straight into Crystal. This approach is not as efficient but sometimes easier.
I had to use explicit ReportDocument type instead of ReportClass because that raised an invalid cast for some reason, but otherwise, works EXACTLY as advertised AFAICT.
viz.
...
...
if (Session["<some identifier>"] != null)
{
switch (Session["<some identifier>"])
{
case ReportClass rc:
crystalReportViewer1.ReportSource = rc;
break;
case ReportDocument rd:
crystalReportViewer1.ReportSource = rd;
break;
default:
return;
}
}
I'm trying to use the ReportViewer Control in Visual Studio 2008 but I'm having problems with viewing the "Smart Tag Panel". The little triangle which should be in the top right corner is not shown. I think the problem is that I can't select the ReportViewer in the Designer in Visual Studio. How do I fix this?
Otherwise i tried to sholved the problem by filling the ReportViewer with data programatically but i also have some problems here. I get an message, which is shown inside the ReportViewer at rumtime:
A datasouce instance have not been supplied for the data source ...
I'm using this code:
private void LoadEmployeeTimeregistrations(string employeeNumber)
{
_employeeTimeregistrations = new List<TimeregistrationData>();
EntityCollection<TimeregistrationsEntity> employeeTimeregList =
_client.TimeRegistrations().GetTimeregistrations(
KRWindPcClassesLibrary.Properties.Settings.Default.ProjectNumber,
employeeNumber, false, null);
if (employeeTimeregList != null)
{
foreach (var timereg in employeeTimeregList)
{
_employeeTimeregistrations.Add(new TimeregistrationData
{
Day = timereg.Time.ToShortDateString(),
TotalHoursPresentation = 8.ToString()
});
}
}
ReportDataSource reportDataSource = new ReportDataSource("Data", _employeeTimeregistrations);
reportViewer2.LocalReport.DataSources.Clear();
reportViewer2.LocalReport.DataSources.Add(reportDataSource);
reportViewer2.LocalReport.Refresh();
reportViewer2.RefreshReport();
}
See this website:
http://www.gotreportviewer.com/
It should have all of the information that you require regarding setting a datasource (amongst many, many other things) for the ReportViewer for VS 2008.