myGridView.DataSource = LinqDataSource works but only for select. I have edit and delete columns and when I try to use them I get errors about events not getting caught. Specifically I've seen OnRowDeleting, but I'm sure there are others that need to be wired up.
myGridView.OnRowDeleting = ??
I can't seem to find anything on the LinqDataSource that looks like what I need :(
edit: here is some some sample code illustrating what I'm doing.
protected virtual void OnRowDeleted(Object sender, GridViewDeletedEventArgs e)
{
// it means the last row was deleted
if (fieldGridView.Rows.Count == 1)
{
fieldGridView.DataSourceID = null;
fieldGridView.DataSource = new[] { new FormField { Required = false } };
fieldGridView.AutoGenerateDeleteButton = false;
fieldGridView.AutoGenerateEditButton = false;
}
}
protected void InsertButton_Click(object sender, CommandEventArgs e)
{
// pull data out of footer row and insert it into the DB
if (fieldGridView.DataSource == null || fieldGridView.DataSource.GetType() != LinqDataSource1.GetType())
{
fieldGridView.DataSource = LinqDataSource1;
fieldGridView.AutoGenerateDeleteButton = true;
fieldGridView.AutoGenerateEditButton = true;
}
}
Also note that I've statically set the OnRowDeleting event in the markup and the error went away. However, the Linq data source is not getting set back properly. The code is updating it, it's just sticking for whatever reason, so what's happening is that when I re-enable the delete column the data source ends up still being the temp data source I assigned to it (which is just a list), so when I hit delete it was blowing up. Since I've now statically defined the callback, it gets called, but no delete happens because the data source isn't being switched back to the linq data source properly.
so in essence, my issue is that when I dynamically set the data source to the list on the last delete, the change is sticking, but when I dynamically set the data source to the linq data source on the first insert, the change is not sticking. The strangest part of it is that other changes I'm making do stick, just not the data source. I'm enabling the autogenerated edit and delete columns and that change is being reflected immediately.
On your linq datasource, did you remember to explicitly set the enable flags for delete and insert?
<asp:LinqDataSource ID="MyLinqDataSource" EnableDelete="true" EnableUpdate="true" EnableInsert="true" runat="server" ....
Ultimately I was not able to fix this specific issue, but I did find a workaround for my larger issue.
In essence what I've done is to create two gridviews with different data sources, created a custom delete button for each row, and then swap the grids out accordingly. Not exactly a great solution, but it suffices for what I'm doing.
As for why my original solution of swapping the datasources doesn't work, I don't know. Most of the projects I've been on have used non-MS tools for tabulated data so I'm not even sure where to look. However, if anyone has any good ideas as to why I've encountered this behavior, I'm all ears.
Related
I have a got Gridview, that gets its data by:
internal void updateGrid()
{
List<String> data = dt.getAlldata(UserID(), ListID());
gridViewer.DataSource = data;
gridViewer.DataBind();
}
After a button click the database is updated and the new data is shown. Everything works fine.
Now I have to replace the string with an Usercontrol:
internal void updateGrid()
{
List<String> data = dt.getAlldata(UserID(), ListID());
gridViewer.DataSource = data;
gridViewer.DataBind();
for (int i = 0; i < gridViewer..Rows.Count; i++)
{
UCControl dum = (UCControl)LoadControl("~/UCControl.ascx");
dum.SetData(gridViewer.Rows[i].Cells[0].Text, false);
gridViewer.Rows[i].Cells[0].Controls.Clear();
gridViewer.Rows[i].Cells[0].Controls.Add(dum);
}
}
After first Page_Load(), everything is shown correctly. But when I click my buttons, the Usercontrols do not repaint. The data is set correctly inside, but it does not update.
Because this Control reacts by javascript on UserInputs on the client side, every Usercontrol has got his own Id that is set by
this.ID = "UCControl" + data[0];
data[0] is unique, but known during the whole process.
Can somebody tell me why the UserControl does not repaint? Or better: How do I tell the Usercontrols to update?
From your code I would say that once the data is bound then you can't go in immediately after and start to change it. You would need to hook into one of the databinding events.
If you were using a list viem ItemDataBound would be a good candidate to hook into. But the GridView has a more limited set of events and doesn't offer that level of control - so you are a bit stuck on that score.
In my experience using dynamic controls in asp.net (LoadControl) is just a bit fraught. I think a better option would be to publicly expose a property in your user control and bind to that.
This question gives a good description of how to achieve this
asp.net user controls binds inside gridview
Hope that helps
I have encountered a problem and I didn't manage to find any soultions yet. Let me simplify things a bit.
I have 2 forms, the first contains an ASP ListBox with multi select mode enabled. I submit the form and in the other form I use just for testing purposes this snippet of code:
protected void Page_Load(object sender, EventArgs e)
{
foreach (string formKey in Request.Form.AllKeys)
{
if (formKey != null)
{
if (formKey.Equals("ctl00$MainContent$ListBox1"))
Label1.Text = Request.Form[formKey];
}
}
}
The problems is that the values that come from the listbox (the values that i selected in the previous form) are separated by "," for ex. "test1,test2,test3". How can i change this separator to "$" for example? I need to change it because the actual values may contain "," and i don't manualy feed them to the listbox.
I can't use any other mode of transfering this values between the form because the entire application uses this model. The values that i get are then sent to a workflow where there will be manipulated and in the workflow i need to know where each listbox item starts and ends so it must be an unique separator.
Any help is apreciated! Thank you very much
Thank you MatteKarla but unfortunately this does not solve my problem. Yes, this is a good way of transfering the values from one form to another.
However i must use the method I described above with Request form keys because the listbox is one of many others "parameters" that are generated at runtime and have their values sent to a workflow method that takes this values. And i can't afford to change that in my application.
My problem is that coma (",") separator is used by default with a multiselect listbox.
I thought that there maybe is a method to change that separator from coma to another char because the coma can also be included in the value itself and this will create confusion.
As i said if i select three values test1, test2 and test3, the result with my method will be a string looking like "test1,test2,test3". However a "test1$test2$test3" would be much better.
But I'm affraid that changing this default separator is not possbile. I must think at a method to overcome this problem like replacing before feeding the listbox all the intended coma from the values with some other char not to create confusion. But this is not a great way of doing it.
On your first page/form (First.aspx.cs) create a public property with the listbox:
public ListBox PostedListBox { get { return ListBox1; } }
Set the postback-url for the button to Second.aspx
Second page in the aspx-file after the #Page-directive add:
<%# PreviousPageType VirtualPath="~/First.aspx" %>
Then in Form_Load on Second.aspx.cs you can extract the values:
if (PreviousPage != null)
{
ListBox postedListbox = PreviousPage.PostedListBox;
foreach (var index in postedListbox.GetSelectedIndices())
{
var itemText = postedListbox.Items[index].Text;
}
}
Or you could just try to locate the control by using:
if (PreviousPage != null)
{
var control = PreviousPage.FindControl("ListBox1") as ListBox;
}
Third Edit:
You could use GetValues:
Request.Form.GetValues("ctl00$MainContent$ListBox1");
returns a string array containing each of the selected items.
I pass the row index value into next page when gridview button clicked using this code
if(e.CommandName=="select")
{
int Id = int.Parse(e.CommandArgument.ToString());
//Label1.Text = Id.ToString();
Response.Redirect("~/manclothes1.aspx?Id=" + e.CommandArgument.ToString());
}
but i don't know what code i write in next page to display row data
please can anyone help me
In ASP.NET you don't actually pass code to a new page. Instead you modify the controls on the current page and the ASP.NET framework re-renders the page for you. Instead of the Response.Redirect line you want something like
DataGrid1.EditItemIndex = Id;
In the page_load of manclothes1.aspx you can try
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["Id"] != null)
{
var id = Request.QueryString["Id"];
// do something with id variable
...
}
}
You'll probably want to reference whatever code on the current page populates the gridview with data in the first place. Essentially, where the code on the current page gets many rows to populate a gridview, the code on the manclothes1.aspx page will get one row. If it's data from a database, the query will likely be very much the same but with an additional WHERE clause to filter by (I'm assuming) an ID value, which is probably a primary key (or the primary key, if we're talking about only one table).
To put this into context, what the call to Response.Redirect() is doing is telling the client (browser) to issue an entirely new request (a GET request, that is) for an entirely new resource (manclothes.aspx with a query string parameter). So understand that "the next page" knows nothing of the gridview on the current page. Nor should it, really. The request should be handled entirely separate from the current page.
We are running a reporting web application that allows the user to select a few fields and a crystal report is generated based off of the fields selected. The SQL that is generated for the most complex report will return the data in < 5 seconds, however it takes the report and average of 3 minutes to run, sometimes longer causing a time out. We are running VS2010. The reports are basically set up out of the box with no real manipulations or computations being done, just displaying the data in a nice format. Is there anything we can try to speed it up, pre-loading a dummy report to load the dlls, some hack to make crystal run faster, anything?
EDIT: Code Added to show the databinding
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string strFile = Server.MapPath(#"AwardStatus.rpt");
CrystalReportSource1.Report.FileName = strFile;
DataTable main = Main();
CrystalReportSource1.ReportDocument.SetDataSource(main);
CrystalReportViewer1.HasCrystalLogo = false;
CrystalReportSource1.ReportDocument.ExportToHttpResponse(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat, Response, false, "pmperformance");
}
}
private DataTable Main()
{
Guid guidOffice = Office;
CMS.Model.ReportsTableAdapters.ViewACTableAdapter rptAdapter = new CMS.Model.ReportsTableAdapters.ViewACTableAdapter();
Reports.ViewAwardedContractsDataTable main = new Reports.ViewAwardedContractsDataTable();
if (Office == new Guid())
{
IEnumerable<DataRow> data = rptAdapter.GetData().Where(d => UserPermissions.HasAccessToOrg(d.guidFromId, AuthenticatedUser.PersonID)).Select(d => d);
foreach (var row in data)
{
main.ImportRow(row);
}
}
else if (guidOffice != new Guid())
{
main = rptAdapter.GetDataByOffice(guidOffice);
}
else
{
main = new Reports.ViewACDataTable();
}
return main;
}
private Guid Office
{
get
{
string strOffice = Request.QueryString["Office"];
Guid guidOffice = BaseControl.ParseGuid(strOffice);
if (!UserPermissions.HasAccessToOrg(guidOffice, AuthenticatedUser.PersonID))
{
return Guid.Empty;
}
else
{
return guidOffice;
}
}
}
protected void CrystalReportSource1_DataBinding(object sender, EventArgs e)
{
//TODO
}
This may be a bit flippant, but possibly consider not using crystal reports... We had a fair bit of trouble with them recently (out of memory errors being one), and we've moved off to other options and are quite happy...
Here's what I would do:
Put clocks from the time you get the field choices from the user, all the way to when you display the report. See where your processing time is going up.
When you look at the clocks, there can be various situations:
If Crystal Reports is taking time to fill the report, check how you're filling it. If you're linking the report fields directly to your data table, CR is probably taking time looking up the data. I suggest creating a new table (t_rpt) with dynamic columns (Field1, Field2,..FieldN) and pointing your report template to that table. I don't know if you're already doing this.
If it's taking time for you to lookup the data itself, I suggest creating a view of your table. Even though a memory hog, this will make your lookup quick and you can delete the view once you're done.
If it's none of the above, let us know what your clocks show.
In terms of loading any large amount of data, you'll always want to use a stored procedure.
Outside of that, you WILL see a delay in the report running the first time the Crystal DLLs load. Yes, you can preload them as you mentioned and that will help some.
I'm having an awful time with my GridView. I've been going over my code with a fine-tooth comb and can't find the problem.
I have an ASP.net GridView with seven columns; the data comes from SQL. Two columns hold javascript that the user can click on to remove or modify an entry in the database. The other five fields contain names, phone numbers, and e-mail addresses of people in a database.
Four of my fields are ASP.net TemplateFields.
When the page loads, everything is displayed correctly. However, if a user clicks a JavaScript link, clicks to sort the GridView by any field, or does any other action that causes a postback, the resulting page may not display the contents of my TemplateFields; they are all blank.
Just so you can see what I'm working with, I have a "name" column which is defined like this:
<asp:TemplateField HeaderText="Name" SortExpression="name" ItemStyle-Width="150">
<ItemTemplate>
<%#(string)Eval("surname") + ", " + (string)Eval("fname") %>
</ItemTemplate>
</asp:TemplateField>
If I step thru the code in the debugger, I see that in the case that the template fields display correctly, the debugger stops on the line that displays the name. In the case that the fields are all blank, it jumps over the code to display the contents of those fields; and for no discrenible reason what-so-ever.
The only thing that seems to cause the problem is that there is a single enum value that is set from the query-string (which tells the page what data to load). When the enum value is set to 1, I never see this error, but it seems that I always see it when the enum value is set to 2.
However, the enum is never ever referenced anywhere in my gridview code.
In any event, the GridView.DataSource = x is always called and GridView.DataBind() is always called. I've tried stepping thru the code and checking that the data from the database is correct. I've tried debugging on the code block where DataBind is called from and also the GridViewRow_DataBound Event handler.
I've seen other posts elesewhere about trouble with TemplateField, but none of them seem to address what's going on here.
Any ideas?
I figured it out part of the answer. I found some code that read like:
if (!userIsAllowedToSeePrivatePhoneNumbers)
removePrivatePhoneNumber(gridView);
***
protected void removePrivatePhoneNumber(GridView gridView)
{
DataControlField privatePhoneNumberColumn = null;
foreach (DataControlField column in gridView.Columns)
{
if (column.HeaderText.ToUpper() == "PRIVATE PHONE")
privatePhoneNumberColumn = column;
}
gridView.Columns.Remove(privatePhoneNumberColumn);
}
I discovered that if I set the visibility of the column to false instead of removing the column, all of my data displays correctly. I do not understand why this is, but it is a satisfactory solution to make the program work for now.
protected void removePrivatePhoneNumber(GridView gridView)
{
DataControlField privatePhoneNumberColumn = null;
foreach (DataControlField column in gridView.Columns)
{
if (column.HeaderText.ToUpper() == "PRIVATE PHONE")
privatePhoneNumberColumn = column;
}
privatePhoneNumber.Visible = false;
}