ReportViewer resets parameters after submit - asp.net

I'm showing a remote report in a ReportViewer control. The report loads with a few default parameters. So far everything is ok.
But when i change a few input values and hit View Report then the report simply shows the data with the default values. The parameters that i changed in the input fields are also reset.
All the code i have is this:
apsx
<rsweb:ReportViewer ID="ReportViewer1" runat="server" Font-Names="Verdana"
Font-Size="8pt" Height="642px" ProcessingMode="Remote" Width="100%">
<ServerReport ReportPath="http://server.com/Product/Dashboards/test.rdl"
ReportServerUrl="http://server.com/ReportServer" />
</rsweb:ReportViewer>
The CodeBehind is basically empty. All it has now is an empty Page_Load.
That is all my code.
But it feels like a ViewState issue? But I am not sure where to look.
Anyone any idea why the parameters are resrt when I press on the View Report button?

I solved this by setting the parameters myself in the Code Behind. So when the report is submitted, i then get all the entered data, put that in a ReportParameters collection.
But unfortunately this wasn't as easy and straight forward as one would think. At first you might think this is stored in: YourReport.ServerReport.GetParameters(). But that is not the case!
To get the submitted values from your report you can use the following code:
Get report submitted parameters
public ReportParameter[] GetCurrentParameters(Microsoft.Reporting.WebForms.ReportViewer viewer)
{
Control params1Area = FindParametersArea(viewer);
List<ReportParameter> params1 = new List<ReportParameter>();
FindParameters(params1Area, params1);
return params1.ToArray();
}
private Control FindParametersArea(Microsoft.Reporting.WebForms.ReportViewer viewer)
{
foreach (Control child in viewer.Controls)
{
if (child.GetType().Name == "ParametersArea")
return child;
}
return null;
}
private void FindParameters(Control parent, List<ReportParameter> params1)
{
Type _ParameterControlType = System.Reflection.Assembly.GetAssembly(typeof(Microsoft.Reporting.WebForms.ReportViewer)).GetType("Microsoft.Reporting.WebForms.BaseParameterInputControl");
ReportParameter param;
Microsoft.Reporting.WebForms.ReportParameterInfo paramInfo;
String[] paramValues;
foreach (Control child in parent.Controls)
{
if (_ParameterControlType.IsAssignableFrom(child.GetType()))
{
paramInfo = (Microsoft.Reporting.WebForms.ReportParameterInfo)GetPropertyValue(child, "ReportParameter");
if (paramInfo == null)
continue;
paramValues = (string[])GetPropertyValue(child, "CurrentValue");
if (paramValues != null && paramValues.Length > 0)
{
param = new ReportParameter();
param.Name = paramInfo.Name;
param.Values.AddRange(paramValues);
params1.Add(param);
}
}
FindParameters(child, params1);
}
}
public object GetPropertyValue(object target, string propertyName)
{
return target.GetType().GetProperty(propertyName, System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public).GetValue(target, null);
}
Source: http://forums.asp.net/t/1057747.aspx/1 (Also Visual Basic examples)
You invoke those methods by just using the following line of code. Preferably in a if(IsPostBack) scope within your Page_Load for example.
ReportParameter[] reportParameters = GetCurrentParameters(ReportViewer1);
It is then possible to overwrite the submitted values if you also have custom textfields. You can easily do that like so:
reportParameters[4] = new ReportParameter("year", "2013", true);
You obviously have to know what param is stored at index 4. But you could also make an easy lookup function that searches for the reportParameter with a specific name. So in my case year.
Simple parameter lookup
protected void ChangeParameterValue(String name, String newValue, ref ReportParameter[] parameters)
{
foreach (ReportParameter param in parameters)
{
if (String.Equals(param.Name, name))
{
param.Values[0] = newValue;
break;
}
}
}
You use that like so:
ChangeParameterValue("year", "2013", ref reportParameters);
This way you don't have to worry about at what index a certain parameter is placed.

Related

Property to check whether a row in grid view has been modified

Is there a simple property or method to check whether a row changed or column value has been changed in my grid view. I also want to get the index of modified/changed row
You can add it to the gridview like this
<asp:GridView Name="gridview1" OnRowUpdating="GridViewUpdateEventHandler" />
If I remember correctly there is an abundance of tutorials for gridviews and how to manipulate data.
No, there is no simple property for that. But...
Here is a method for that on MSDN
You'll have to modify it for your data and your control names to verify, but it's all there, straight from the keyboard of Microsoft.
protected bool IsRowModified(GridViewRow r)
{
int currentID;
string currentLastName;
string currentFirstName;
currentID = Convert.ToInt32(GridView1.DataKeys[r.RowIndex].Value);
currentLastName = ((TextBox)r.FindControl("LastNameTextBox")).Text;
currentFirstName = ((TextBox)r.FindControl("FirstNameTextBox")).Text;
System.Data.DataRow row =
originalDataTable.Select(String.Format("EmployeeID = {0}", currentID))[0];
if (!currentLastName.Equals(row["LastName"].ToString())) { return true; }
if (!currentFirstName.Equals(row["FirstName"].ToString())) { return true; }
return false;
}

Sorting a GridView bound to a list of custom generic Objects

I'm trying to figure out how to sort a GridView with multiple columns (String, DateTime, Decimal, etc. data-types) which is bound to a generic list of custom objects.
MyObject.vb:
Public Property Id
Public Property Name
Public Property Date
Public Property Amount
MyObjects.aspx.vb:
gridView.DataSource = GetMyObjects()
gridView.DataBind()
Note: GetMyObjects() returns a List of MyObject
Basically, I need to be able to click on the column headers of the grid to sort and reverse sort, and also be able to store the sort direction in ViewState so the direction persists each time I click on a column header.
It seems like I probably need MyObject to implement IComparable, but I'm not sure quite how to put it all together.
Can anyone suggest a good tutorial for this, or point me in the right direction?
You need to enable sorting (AllowSorting) and handle the event OnSorting.
Note: The sample code uses C#, but the VB version should be similar.
Create your GridView:
<asp:GridView ID="GridView1" runat="server" AllowSorting="True" OnSorting="GridView1_Sorting">
</asp:GridView>
Handle OnSorting:
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
GridView1.DataSource = GetObjects(e.SortDirection, e.SortExpression);
GridView1.DataBind();
}
GetObjects returns a sorted List<MyObject>. You have to create your own sorting logic here, one alternative could be using Dynamic Linq. If you choose that route, GetObjects could be defined like this: (there are better ways, but this is enough to show the theory)
private List<MyObject> GetObjects(SortDirection sd, string se)
{
// Have we generated data before?
if (SimulatedDB == null)
{
// Create a sample DB
SimulatedDB = new List<MyObject>();
var rnd = new Random();
for (int i = 0; i < 20; i++)
{
var node = new MyObject();
node.Id = i;
node.Name = String.Format("Name {0}", i);
node.CreationDate = DateTime.Now.AddDays(rnd.Next(100));
node.Amount = (rnd.Next(1000) * rnd.NextDouble());
SimulatedDB.Add(node);
}
}
// Return sorted list
if (sd == SortDirection.Ascending)
return SimulatedDB.AsQueryable<MyObject>().OrderBy<MyObject>(se).ToList();
else
return SimulatedDB.AsQueryable<MyObject>().OrderByDescending<MyObject>(se).ToList();
}
Hope it helps.

why my view state not getting cleared and on reload it save the value to the databse again?

I am having user control registered on a aspx page.
there is a button on user control resisted on some aspx page that perform some action to store the value of viewste to the database, and below that i have cleared my viewstate value, but if i do right click and reload the page it reinsert the values to the data base, what i am missing or the viewstate do not get cleared, how should i prevent it to resave the same entries to the database.
I am partially writing my code below.
protected void btnFinish_Click(object sender, EventArgs e)
{
if (ViewState["dtQuestions"] != null)
{
foreach (DataRow dr in dtQuestions.Rows)
{
int currQueScore = GetAnswerScore(dr["AnswerType"].ToString().Trim(), dr["ClientAnswerValue"].ToString().Trim());
dr["ClientAnswerScore"] = currQueScore;
myScore += currQueScore;
SurveyClientAnswer objDetail = new SurveyClientAnswer();
objDetail.SurveyClientID = objMaster.SurveyClientID;
objDetail.QuestionID = int.Parse(dr["QuestionID"].ToString());
objDetail.Answer = dr["ClientAnswerValue"].ToString();
objDetail.Score = int.Parse(dr["ClientAnswerScore"].ToString());
DB.SurveyClientAnswers.InsertOnSubmit(objDetail);
DB.SubmitChanges();
}
objMaster.FinalScore = myScore;
DB.SubmitChanges();
ViewState["dtQuestions"] = null;
}
else
{
ModalPopupExtender1.Show();
pnl.Visible = true;
}
}
If you don't want to reinsert the data, simply create a unique constraint on the database to disallow this scenario.
As far as doing it in code, you could possibly only insert the data adding this condition to the if statement:
if(IsPostBack && (ViewState["dtQuestions"] != null)
{
//meaning the user is not simply reloading the page but actually posting back
}
Note that there might be some corner cases where this won't work. Without testing is difficult to know but I strongly believe that this should be handled at the database level instead.

Accessing the object/row being edited in Dynamic Data

I'm modifying the "Edit.aspx" default page template used by ASP.NET Dynamic Data and adding some additional controls. I know that I can find the type of object being edited by looking at DetailsDataSource.GetTable().EntityType, but how can I see the actual object itself? Also, can I change the properties of the object and tell the data context to submit those changes?
Maybe you have found a solution already, however I'd like to share my expresience on this.
It turned out to be a great pita, but I've managed to obtain the editing row. I had to extract the DetailsDataSource WhereParameters and then create a query in runtime.
The code below works for tables with a single primary key. If you have compound keys, I guess, it will require modifications:
Parameter param = null;
foreach(object item in (DetailsDataSource.WhereParameters[0] as DynamicQueryStringParameter).GetWhereParameters(DetailsDataSource)) {
param = (Parameter)item;
break;
}
IQueryable query = DetailsDataSource.GetTable().GetQuery();
ParameterExpression lambdaArgument = Expression.Parameter(query.ElementType, "");
object paramValue = Convert.ChangeType(param.DefaultValue, param.Type);
Expression compareExpr = Expression.Equal(
Expression.Property(lambdaArgument, param.Name),
Expression.Constant(paramValue)
);
Expression lambda = Expression.Lambda(compareExpr, lambdaArgument);
Expression filteredQuery = Expression.Call(typeof(Queryable), "Where", new Type[] { query.ElementType }, query.Expression, lambda);
var WANTED = query.Provider.CreateQuery(filteredQuery).Cast<object>().FirstOrDefault<object>();
If it's a DD object you may be able to use FieldTemplateUserControl.FindFieldTemplate(controlId). Then if you need to you can cast it as an ITextControl to manipulate data.
Otherwise, try using this extension method to find the child control:
public static T FindControl<T>(this Control startingControl, string id) where T : Control
{
T found = startingControl.FindControl(id) as T;
if (found == null)
{
found = FindChildControl<T>(startingControl, id);
}
return found;
}
I found another solution, the other ones did not work.
In my case, I've copied Edit.aspx in /CustomPages/Devices/
Where Devices is the name of the table for which I want this custom behaviour.
Add this in Edit.aspx -> Page_Init()
DetailsDataSource.Selected += entityDataSource_Selected;
Add this in Edit.aspx :
protected void entityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
Device device = e.Results.Cast<Device>().First();
// you have the object/row being edited !
}
Just change Device to your own table name.

Accessing Row Data In Telerik RadGrid (Server Side)

Ive no problems using Javascript to read the rows of a telerik radgrid component im using however I can seem to find anyway to access the row data server side when a postback occurs. Ive spent ages looking for solution but no luck.
Any pointers would be greatly appreciated.
Tony
You might want to look at the DataKeyValues property of the OwnerTableView object, which will let you access a collection of values that represent the fields in a given row. I use it during the EditCommand event handler, since a user of my site is directed to an edit page if they click on the link to edit a row in the grid, and I need to pass along certain info about the given row in the query string.
If this turns out to be what you need, you'll also need to define which fields should be made available through this property. To do that, look at the MasterTableView.DataKeyNames property in the property sheet for the grid. You basically specify a comma-delimited list of field names.
The server-side is the easy part:
GridItemCollection gridRows = TestGrid.Items;
foreach (GridDataItem data in gridRows)
{
ItemClass obj = (ItemClass)data.DataItem;
}
It's the client side part that I don't know! :[
private Int32 GetID()
{
foreach (Telerik.Web.UI.GridDataItem dataItem in radGrid.MasterTableView.Items)
{
if (dataItem.Selected == true)
{
Int32 ID = (Int32)dataItem.GetDataKeyValue("ID");
return ID;
}
}
throw new ArgumentNullException("Id Not found");
}
This is the one that works for me and uses the RadGrid.SelectedItems collection.
protected void LinkButton1_Click(object sender, EventArgs e)
{
List<Guid> OrderIdList = new List<Guid>();
foreach (GridDataItem OrderItem in this.RadGrid1.SelectedItems)
{
OrderIdList.Add(new Guid(OrderItem.GetDataKeyValue("OrderId").ToString()));
}
}
If you correctly created your controls in markup or page init for dynamic controls, then the RadGrid will properly restore state.
You can access the initial values that were loaded from the data source like this example below, provided you told the table view in question to keep the columns around in the data keys.
protected T GetInitialGridData<T>(GridDataItem item, string uniqueColumnName) {
item.ThrowIfNull("item");
uniqueColumnName.ThrowIfNullOrEmpty("uniqueColumnName");
return (T)item.OwnerTableView.DataKeyValues(gridItem.ItemIndex)(columnName);
}
If you are using a dynamic custom template column, and need to get to any values that may now be in their states, you can use:
protected string GetCustomTextBoxValue(GridDataItem item, string controlID) {
item.ThrowIfNull("item");
controlID.ThrowIfNullOrTrimmedEmpty("controlID");
return ((TextBox)item.FindControl(controlID)).Text;
}
private Int32 GetID()
{
foreach (Telerik.Web.UI.GridDataItem dataItem in radGrid.MasterTableView.Items)
{
if (dataItem.Selected == true)
{
// Int32 ID = (Int32)dataItem.GetDataKeyValue("ID");
Int32 ID =Convert.ToInt32(dataItem.GetDataKeyValue("ID"));
return ID;
}
}
}
//this will work

Resources