I have this page with a GridView control inside that's bound to database. GridView has a command row for insert, delete and updating. The problem is that, since my database table is initially empty, I see an empty grid. I don't even see the command row in order to be able to insert anything into it.
I managed to solve this by checking for GridView row count and changing its display to InsertTemplate. But I'm wondering if there's a standard way of doing this, may it already has such functionality?
The same problem with DetailView.
Thanks
You can use the EmptyDataTemplate to handle inserting a new item if the grid's data source is initially empty.
Define your grid in the ASPX as follows:
<asp:GridView runat="server" ID="grid" AutoGenerateColumns="false"
OnRowCommand="grid_RowCommand">
<Columns>
<asp:ButtonField ButtonType="Link" CommandName="Add" Text="Add" />
<asp:BoundField DataField="Id" HeaderText="Id" />
<asp:BoundField DataField="FirstName" HeaderText="First Name" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
</Columns>
<EmptyDataTemplate>
<asp:TextBox ID="CustomerFirstName" runat="server"></asp:TextBox><br />
<asp:TextBox ID="CustomerLastName" runat="server"></asp:TextBox><br />
<asp:Button ID="Save" Text="Save" runat="server" CommandName="EmptyAdd"
UseSubmitBehavior="False" />
</EmptyDataTemplate>
</asp:GridView>
A collection of Customer objects is used as the datasource for the grid.
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Bind the grid to a data source (empty for this example).
protected void Page_Load(object sender, EventArgs e)
{
var customers = new List<Customer> {};
grid.DataSource = customers;
grid.DataBind();
}
You can then handle the Add and EmptyAdd command in the grid_RowCommand event handler.
protected void grid_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "EmptyInsert")
{
}
if (e.CommandName == "Insert")
{
}
}
Related
I want to remove templatefield from gridview during pageload or before databind to GridView. I have 2 data sources for retrieving data. The data retrieved from one of the data sources do not have the columns ExpireDate and ExpireDays.
So I want to delete the templatefields corresponding to ExpireDate and ExpireDays if the GridView is populated from the data source that do not have those 2 fields.
Setting the visibility to false still will have error of DataRowView doesn't contain property name ExpireDate and ExpireDays.
Markup
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" OnRowCommand="GridView1_RowCommand" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:BoundField DataField="ID" HeaderText="No."/>
<asp:BoundField DataField="Name" HeaderText="Name"/>
<asp:BoundField DataField="CourseName" HeaderText="Course Enroll" />
<asp:BoundField DataField="SubMember" HeaderText="ChildMember" />
<asp:TemplateField HeaderText="Expiry Days">
<ItemStyle HorizontalAlign="Center" />
<ItemTemplate>
<asp:Label runat="server" ID="expDsL" Text=' <%# Eval("ExpiryDays") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Expiry On">
<ItemStyle HorizontalAlign="Center" />
<ItemTemplate>
<asp:Label runat="server" ID="expDeL" Text=' <%# Eval("ExpiryDate") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Function">
<ItemStyle HorizontalAlign="Center" Width="100px"></ItemStyle>
<ItemTemplate>
<asp:ImageButton ImageUrl="~/Images/editB.gif" ID="btnEdit" runat="server" ToolTip="Edit" CommandName="Edit" CommandArgument='<%# Eval("ID") %>' />
<asp:ImageButton ImageUrl="~/Images/delB.gif" ID="btnDelete" runat="server" ToolTip="Delete" CommandName="Delete" CommandArgument='<%# Eval("ID") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code Behind
protected void Page_Load(object sender, EventArgs e)
{
if(Class.ToLower() != "classAA")
{
// using naveen answer can remove the column.
var expiryDateF = ((DataControlField)GridView1.Columns.Cast<DataControlField>().Where(fid => fid.HeaderText == "Expiry Days").SingleOrDefault());
var expiryDaysF = ((DataControlField)GridView1.Columns.Cast<DataControlField>().Where(fid => fid.HeaderText == "Expiry On").SingleOrDefault());
if (expiryDateF != null)
{
GridView1.Columns.Remove(expiryDateF);
}
if (expiryDaysF != null)
{
GridView1.Columns.Remove(expiryDaysF);
}
}
if(!this.IsPostBack)
{
BindData();
}
}
protected void SaveMember(object sender, EventArgs e)
{
//getting member information and perform checking.
bool success = dbbb.AddMem(memberdetails);
if(success == true)
{
BindData();
}
else
{
//prompt fail message.
}
}
protected void BindData()
{
DataTable dt = dbbb.RetrieveList();
if(dt != null)
{
GridView1.DataSource = dt;
GridView1.DataBind();
}
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
ImageButton btnDel = (ImageButton)e.Row.FindControl("btnDelete");
btnDel.Attributes.Add("onclick", "return confirm('Are you sure you want to delete this member?')");
}
}
How could I delete the column?
Two methods to achieve this
Method 1 - Remove by Index
if(!table.Columns.Contains("CustomerID1"))
{
//seven is the column index here. ie, 8th column
CustomersGrid.Columns.RemoveAt(7);
}
Method 2 - Remove using Columns Header Text
var expiryDateField= ((DataControlField)CustomersGrid.Columns
.Cast<DataControlField>()
.Where(fld => fld.HeaderText == "Expiry Date")
.SingleOrDefault());
if(expiryDateField != null)
{
CustomersGrid.Columns.Remove(expiryDateField);
}
Please not that
CustomersGrid is the name of the asp:GridView here.
table is the DataTable that acts as the DataSource of the GridView
The code should be called before DataBind of the GridView
Attach to the rowDataBound event of the grid, there you can set it dynamically.
You have to know the datasource name of the field you want to hide,
for example the headertext for the cell is "SomeHeader", but the databoundfield name for that cell is
"SomeOtherName"
then you have to check it like this (debug through GetColumnIndexByName) and
check the value of
((BoundField)cell.ContainingField).DataField
int GetColumnIndexByName(GridViewRow row, string columnName)
{
int columnIndex = 0;
foreach (DataControlFieldCell cell in row.Cells)
{
if (cell.ContainingField is BoundField)
if (((BoundField)cell.ContainingField).DataField.Equals(columnName))
break;
columnIndex++; // keep adding 1 while we don't have the correct name
}
return columnIndex;
}
remember that the code above will use a BoundField... then use it like:
protected void GridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
int index = GetColumnIndexByName(e.Row, "SomeOtherName");
string columnValue = e.Row.Cells[index].Text;
}
}
I have a grid view with below markup and below datasourse (linq query-stored procedure), I have added delete and update command field, but I do not know what code I have to add until deleting and updating for this grid view works.
<asp:GridView ID="GridViewDocuments_Search" runat="server" AutoGenerateColumns=False Visible="False" onrowcommand="GridViewDocuments_Search_RowCommand"
DataKeyNames="DocID" PageSize="100" >
<Columns>
<asp:TemplateField HeaderText = "Details">
<ItemTemplate>
<asp:Button ID ="btn_Show" Text="Details" runat= "server" CommandName= "Details" CommandArgument='<%#
Container.DataItemIndex%>' />
</ItemTemplate>
</asp:TemplateField>
<asp:HyperLinkField DataNavigateUrlFields="Docid,Transid"
DataNavigateUrlFormatString="~/DocResult.aspx?Docid={0}&TransID={1}"
DataTextField="DocumentNo" HeaderText="Doc" />
<asp:BoundField DataField="title" HeaderText="Title" SortExpression="title" />
<asp:BoundField DataField="transmittal" HeaderText="transmittal" SortExpression="transmittal" />
<asp:BoundField DataField="Docid" HeaderText="Docid" Visible="false" />
<asp:CommandField ShowEditButton="True" />
<asp:CommandField ShowDeleteButton="True" />
</Columns>
</asp:GridView>
protected void btnSearch_Click(object sender, EventArgs e)
{
_DataContext = new EDMSDataContext();
var query = _DataContext.spQuickSearch(txtSearchKeywords.Text);
GridViewDocuments.Visible = false;
GridViewDocuments_Search.Visible = true;
GridViewDocuments_Search.DataSource = query;
GridViewDocuments_Search.DataBind();
}
The stored procedure spQuickSearch is like below:
ALTER proc [dbo].[spQuickSearch]
#Searchtext varchar(50)=null
AS
select DocId,TransId,DocumentNo,Title,TRANSMITTAL
from DocumentSum2
where DocumentNo like '%'+#SearchText + '%'
or Title like '%'+#SearchText + '%'
or TRANSMITTAL like '%'+#SearchText + '%'
You can handle commands like this:
protected void GridViewDocuments_Search_RowCommand(object sender, GridViewCommandEventArgs e)
{
string cmdArg = e.CommandArgument.ToString();
switch (e.CommandName)
{
case "Details":
//TODO: handle your Details command...
break;
case "Delete":
//TODO: handle your Delete command...
break;
}
}
You can add as many commands as you want (CommandName property for control). For example you can add another button and set Delete CommandName like this:
<asp:Button ID ="btn_Delete" Text="Delete" runat= "server" CommandName= "Delete" CommandArgument='<%#
Container.DataItemIndex%>' />
After command is completed you can call DataBind to refresh grid:
GridViewDocuments_Search.DataBind();
check this example
http://www.vkinfotek.com/gridview/gridview-commandfield.html
for detail
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.commandfield.showeditbutton.aspx
Below is my gridview ,
<asp:GridView ID="gridview1" AutoGenerateColumns="False" runat="server"
EnableModelValidation="True" >
<Columns>
<asp:CommandField ButtonType="Link" HeaderText="Delete" InsertImageUrl="~/_layouts/images/TBS.WebParts/Button-Delete-icon.png" ShowDeleteButton="true"/>
<asp:BoundField HeaderText ="Size" DataField="FileSize" />
<asp:BoundField HeaderText ="File" DataField="Size" />
<asp:TemplateField HeaderText="SupportIncluded">
<ItemTemplate>
<asp:CheckBox ID="Checkbox1" runat="server" Checked="false" />
</ItemTemplate>
Now on server side i want to check if the checkbox is checked or not on Submit button click event.
private void btnSubmit_Click(object sender, EventArgs e)
{
if (IsValidPost())
{
bool flag = false;
for( int i=0; i < gridview1.Rows.Count ; i++)
{
if(dgdUpload.Rows[i].FindControl("Checkbox1"),CheckBox).Checked) erorr here...I also tried ....if(Checkbox1.checked)...but unable to access Checkbox1..it says it does not exist in the current context....
flag = true;
}
if(flag)
{
}
}
}
You need to access not only the row but also the template field control. Another option is to develop your own recursive version of FindControl that does a search on the whole tree and not just on one level.
Something like:
dgdUpload.Rows[i].Controls[5].FindControl("Checkbox1")
if I counted the columns in your gridview correctly 5 should be the index of the template field.
I have following Gridview:
<asp:GridView ID="GridView1" runat="server" CssClass="table" DataKeyNames="groupId"
DataSource="<%# dsUserGroupsSelected %>" DataMember="Group" etc....>
and after firing RowDeleting event handler:
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
e.Keys is empty. Moreover, in runtime if I check
dsUserGroupsSelected.Group.PrimaryKey
it is poulated with:
{System.Data.DataColumn[1]}
[0]: {groupId}
so it's really odd to me. Am I missing something? I have this kind of a workaround:
int groupId = (int)GridView1.DataKeys[e.RowIndex].Value;
which will work just fine, but I just can't get it why e.Keys (and e.Values) would be empty!? Any ideas?
It looks like this behaviour is intentional.
From http://forums.asp.net/p/1050092/2128091.aspx
Looking in Reflector at Gridview.HandleDelete(), it appears that
e.Keys and e.Values are only populated if
gridview.IsBoundUsingDataSourceID. That is, if you set the DataSource
in code then none of this will work. Good one, Microsoft! Might have
been useful to mention that in the help perhaps??!! Lachlan
Edit:
I ended up making my own data objects and put them in the app_code folder
ex.
public class CustomDataViews
{
public class FileQuery
{
public class File
{
public DateTime CreatedDate { get; set; }
public string FileName { get; set; }
public string Path { get; set; }
public void Delete() { }
}
public ArrayList GetFiles()
{
System.Collections.ArrayList files = new ArrayList();
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(HttpContext.Current.Server.MapPath("~/UserUpload/"));
foreach (System.IO.FileInfo fi in (from a in di.GetFiles() orderby a.CreationTime descending select a))
{
File myFile = new File();
myFile.CreatedDate = fi.CreationTime;
myFile.FileName = fi.Name;
myFile.Path = "/VACWeb/UserUpload/" + fi.Name;
files.Add(myFile);
}
return files;
}
public void Delete(string FileName)
{
if (FileName != null)
{
string path = HttpContext.Current.Server.MapPath("~/UserUpload/") + FileName;
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
}
}
}
}
aspx
<asp:GridView ID="gvFiles" runat="server" AutoGenerateColumns="False" DataKeyNames="FileName"
DataSourceID="ods1">
<Columns>
<cc:ExtendedCommandField DeleteConfirmationText="Are you sure you wish to delete this file?"
DeleteText="Delete" ShowDeleteButton="true" />
<asp:BoundField DataField="CreatedDate" HeaderText="Created Date" DataFormatString="{0:MM/dd/yyyy}" />
<asp:BoundField DataField="FileName" HeaderText="File Name" />
<asp:ImageField DataImageUrlField="Path" AlternateText="No Image" HeaderText="Image Preview"
ControlStyle-Width="100px">
<ControlStyle Width="100px" />
</asp:ImageField>
<asp:BoundField DataField="Path" HeaderText="Path" />
<asp:HyperLinkField DataNavigateUrlFields="Path" DataTextField="FileName" HeaderText="Link" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ods1" runat="server" DeleteMethod="Delete" SelectMethod="GetFiles"
TypeName="CustomDataViews+FileQuery">
<DeleteParameters>
<asp:Parameter Name="FileName" Type="String" />
</DeleteParameters>
</asp:ObjectDataSource>
Simple! ASP is a big piece of .... and GridView is a small piece in the big peace. Have the same problem, and while the workaround is ok for deleting, updating becomes really interesting... The actual problem is it seems that for no good or apparent reason a looooooooot of the functionality of GridView is missing if the DataSource is not a DataSourceControl: Like filling the keys & values properties in the eventargs. Enjoy! Viva Microsoft!
Is it possible you're programatically sorting your gridview in your Page_Load method? If so, try moving the sort into the Page_Init method, and see if that fixes the problem.
Apparently, the GridViewDeleteEventArgs.Keys property only works if you set the GridView's DataSource by setting the DataSourceID property -- i.e. setting the DataSource property and then manually calling DataBind() leaves the Keys property (and the Values property as well) empty.
Source: http://forums.asp.net/t/1050092.aspx
I'm trying to implement a DataGrid in ASP.NET, and want to achieve custom paging so that I don't have to provide all the data in one go. I've spent several hours researching on the internet, but haven't found anything useful.
When I view the page I see the first set of results in the grid, with the previous link disabled. When I click next however, I once again see the first page of the grid with the previous link disabled. When debugging the code I ascertained that the MyGrid_PageIndexChanged() event handler is never called.
I've included my simplified code below. I've changed variable names and omited methods to focus on the datagrid paging issue.
In the ASPX file:
<asp:DataGrid ID="myGrid" runat="server" GridLines="None" UseAccessibleHeader="true" AutoGenerateColumns="false" AllowPaging="true" AllowCustomPaging="true" PageIndexChanged="MyGrid_PageIndexChanged">
<PagerStyle Mode="NextPrev" NextPageText="Next >" PrevPageText="< Previous" />
<Columns>
<asp:BoundColumn HeaderText="Title" DataField="Name" />
<asp:BoundColumn HeaderText="Date" DataField="Date" />
</Columns>
</asp:DataGrid>
And in the CS file:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
myGrid.PageSize = 20;
myGrid.VirtualItemCount = GetNumItems();
BindMyGrid();
}
}
protected void MyGrid_PageIndexChanged(object sender, DataGridPageChangedEventArgs e)
{
myGrid.CurrentPageIndex = e.NewPageIndex;
BindMyGrid();
}
private int GetNumItems()
{
return 500;
}
private void BindMyGrid()
{
Data[] array = GetDataFromInternetSomehow();
this.myGrid.DataSource = array;
this.myGrid.DataBind();
}
private class Data
{
public string Date { get; set; }
public string Name { get; set; }
}
Any thoughts on this would be much appreciated.
There is an error in your ASPX: to wire up the PageIndexChanged event handler use the property OnPageIndexChanged (not PageIndexChanged as in your code):
<asp:DataGrid ID="myGrid" runat="server"
OnPageIndexChanged="MyGrid_PageIndexChanged" /// <--- here's the error
...
Then, if you have AllowCustomPaging="true", you must ensure that the GetDataFromInternetSomehow() method will only return the data for the currently selected page, e.g. pass the current page to the method and return only the corresponding data:
GetDataFromInternetSomehow(e.NewPageIndex);
Otherwise, disable custom paging and it will just work (but all data will be loaded everytime).