DataGrid and formatting data - c#

I'm new to ASP.NET and don't really understand how to display a table with database data. The data is loaded in an object, where I have a list of objects.
Now I want to show a table with some columns, an image (path created from two fields in the object), an link (passing one field of the object), a textarea (id from object, value from object), a radiobutton (id from object).
How should I do this. I have tried binding a datagrid to the list of objects, and it works. But I don't want to show all data members, and I don't know how to create correct headers and the image and form controls.
ImageDataGridView.DataSource = tradeObj.Images;
ImageDataGridView.DataBind();

To stop the automatic creation of a column for each column in the data source, set:
ImageDataGridView.AutoGenerateColumns = false
Then you need to define a column for each column in the data source that you want to display - depending on the column you may want a bound column (you can control the format) or something more involved.
See http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.datagrid.columns.aspx for a sample and the different column types available

You can spefify your column and header using boundfield
<asp:boundfield datafield="yourColumn"
headertext="theHeaderText"/>
And you need to turn off:
ImageDataGridView.AutoGenerateColumns = false
To format values look at this link at msdn.

You need to use template field to customize your datagrid as per below
<asp:GridView ID="GridView1" runat="server">
<Columns>
<asp:TemplateField ShowHeader="True">
<ItemTemplate>
<asp:Image runat="server" ID="Image1"
ImageUrl="Enabled.gif" />
</ItemTemplate>
</asp:TemplateField>
......
......
</Columns>
</asp:GridView>
See this msdn link to work with template field in datagrid
Update
For iterate through every row of gridview you need to handle Rowdatabound event as per below.
protected void gridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
Image imgCtrl = (Image) e.Row.FindControl("imgCtrl");
imgCtrl.ImageUrl = "you can apply any format of url here";
}
}
for more information of Rowdatabound event visit this link

Just set autogenerate to false on your datagrid/gridview control. You can then create a templateField column & drop a label or textbox control inside itemTemplate & bind them like
<asp:Label ID="lblMyColumn" Text="<%# Bind("YourColumnName") %>' runat="server"></asp:Label>
Alternatively you can also drop a boundField & set its properties
<asp:BoundField DataField="YourColumnName" HeaderText="Your Text" SortExpression="YourColumnName" />

Related

ASP.NET DataGrid is empty

I have a ASP.NET datagrid which is on a user control. I have a main page which adds the user control ( sometimes multiple copies of the user control ) and restores them when a post back occurs.
The dataGrid has insert / edit / delete links. I can add multiple copies of the user control to the page and the insert / edit delete functionality works perfectly for each separate control.
Yesterday I added some property binding to the main page to which are unrelated to the user control using the format Text='<%# DocumentTitle %>'. Initially I couldn't get this to work until I added Page.DataBind(); to the main page's Page_Load method. At this point the property binding started working correctly but then I noticed the insert functionality had stopped working in the datagrid within each user control....I debugged and found that when the following line executes it finds the text fields in the controls within the dataGrid to be empty or "":
eInfo.Ref = ((TextBox)gvEG.FooterRow.FindControl("txtEmployeeName")).Text;
If I remove the page.DataBind() method from the main page then the property binding stops working but the dataGrid(s) in the userControl start working.
My question is two fold i) Why does the seemingly unrelated change effect the dataGrid and ii) what do I do to get this working?
I've added the relevant sections of my code below...or at least what I think are the relevant sections.
Default.aspx
<div class="general">
<asp:TextBox Width="488" runat="server" placeholder="Document Title" Text='<%# DocumentTitle %>'></asp:TextBox>
</div>
Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Create an empty user control for the first requirements section.
EmployeeSectionUserControl myUserControl1 = (EmployeeSectionUserControl )LoadControl("~/EmployeeSectionUserControl .ascx");
// Add it to the panel control holding all the user controls.
MainPanel.Controls.Add(myUserControl1);
DocumentTitle = "I am the default document title and I'm bound.";
}
else
{
// Do nothing
}
Page.DataBind();
}
EmployeeSectionUserControl.ascx
<asp:GridView ID="gvEG" runat="server" AutoGenerateColumns="False" CssClass="grid"
AlternatingRowStyle-CssClass="gridAltRow" RowStyle-CssClass="gridRow" ShowFooter="True"
EditRowStyle-CssClass="gridEditRow" FooterStyle-CssClass="gridFooterRow" OnRowCancelingEdit="gvEG_RowCancelingEdit"
OnRowCommand="gvEG_RowCommand" OnRowDataBound="gvEG_RowDataBound" OnRowDeleting="gvEG_RowDeleting"
OnRowEditing="gvEG_RowEditing" OnRowUpdating="gvEG_RowUpdating" DataKeyNames="Id" ShowHeaderWhenEmpty="true">
<Columns>
<asp:TemplateField HeaderText="Id" HeaderStyle-HorizontalAlign="Left" ControlStyle-Width="50px">
<ItemTemplate>
<%# Eval("Id")%>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Ref" HeaderStyle-HorizontalAlign="Left" ControlStyle-Width="90px">
<EditItemTemplate>
<asp:TextBox ID="txtEmployeeName" runat="server" Text='<%# Bind("Ref") %>'
Width="90px"></asp:TextBox>
</EditItemTemplate>
<FooterTemplate>
<asp:TextBox ID="txtEmployeeName" runat="server" Width="90px"></asp:TextBox>
</FooterTemplate>
EmployeeSectionUserControl.ascx.cs
protected void gvEG_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName.Equals("Insert"))
{
employeeInfo eInfo = new employeeInfo();
eInfo.Id = 999;// Convert.ToInt32(((TextBox)gvEG.FooterRow.FindControl("Id")).Text);
// If we're inserting from the EmptyDataTemplate( ie an empty table ) of the gridview then we need to retreive the data differently.
// So we perform a check on the gridView FooterRow and if it's null then we can assume it's an empty table.
if (gvEG.FooterRow == null)
{
TextBox referenceTxtBox = (((Control)e.CommandSource).NamingContainer).FindControl("txtEmployeeName") as TextBox;
eInfo.Ref = referenceTxtBox.Text;
}
else
{
eInfo.Ref = ((TextBox)gvEG.FooterRow.FindControl("txtEmployeeName")).Text;
eInfo.Need =
}
// Store Update and Re-bind data to grid.
}
}
Page.DataBind() calls DataBind on it's children, so it updates DocumentTitle in the text box but it also DataBinds your grid. I didn't see a DataSource set in your grid, like an EntityDataSource, so I am assuming you are doing the smart retrieving (and preparation) of the data yourself in code and set the DataSource yourself:
gvEg.DataSource = someCollection;
gvEg.DataBind();
On the get your are loading the user-control and probably call this DataBind with specifying the DataSource. It binds and then you call Page.DataBind() which probably also triggers another DataBind for gvEg but since DataSource is set it shows the same.
On the post back you shouldn't do a DataBind() before handling events. Your call of Page.DataBind() does that. It triggers a DataBind() without a DataSource. Then the rowCommand comes and checks for the TextBox in the Footer which is cleared due to a DataBind with no elements.
What you should do is:
You shouldn't use Page.DataBind(). If you do so, you need todo it at a moment when all DataSources are set correctly and it shouldn't be kicked of during a post back. In general, I would not recommend using it because it makes it more complex and it's probably only helping a bit if you haven't set up your application correctly.
In your case it's definitely not necessary. Your textBox is a server control that's not part of any binding (GridView, Repeater, ListView). So your textBox is immediately available in your code behind.
So you should:
Give the textBox an ID you can use like txtDocumentTitle
<asp:TextBox Width="488" ID="txtDocumentTitle" runat="server" placeholder="Document Title"></asp:TextBox>
Replace setting DocumentTitle (unless you need it for something else too) with:
txtDocumentTitle.Text = "I am the default document title and I'm bound.";
Remove Page.DataBind();
So access server controls you have access immediately since they are also properties in your page or control.

Rowdeleteing event in Gridview

I have been trying to write this simple logic of deleting a row from the gridview and from the SQL database of the selected row, but keep getting a null reference to cell, which has the primary key [ID] in a field.
Here's my html:
<asp:GridView ID="grvInventoryEdit" runat="server" BackColor="White" onrowdeleting="grvInventoryEdit_RowDeleting"
onrowediting="grvInventoryEdit_RowEditing"
onrowupdating="grvInventoryEdit_RowUpdating">
<Columns>
<asp:CommandField ShowEditButton="True" />
<asp:CommandField ShowDeleteButton="True" /><asp:TemplateField HeaderText="Id">
<ItemTemplate>
<%#Eval("No")%>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox runat="server" ID="txtEditNo" ReadOnly="True" Text='<%#Eval("No")%>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>........ </Columns> </asp:GridView>
And my back-end code for rowdeleting event is :
protected void grvInventoryEdit_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
TextBox id = (TextBox)grvInventoryEdit.Rows[e.RowIndex].FindControl("txtEditNo");
Asset asset = db.Assets.Single(a => a.No == Convert.ToInt32(id));
db.Assets.DeleteOnSubmit(asset);
db.SubmitChanges();
binddata();
}
and when the event fires, this is what i am seeing while debugging:
I am not sure why i am getting a null value ,though, there is a value for that cell.
Could you tell me what i am doing wrong ?
Regards,
Might be it is due to the readonly property of textbox, not suer.
If you want to use the image button for edit and delete then use
protected void ibtnDelete_Click(object sender, ImageClickEventArgs e)
{
GridViewRow gvRow = (GridViewRow)((ImageButton)sender).NamingContainer;
Int32 UserId = Convert.ToInt32(gvUsers.DataKeys[gvRow.RowIndex].Value);
// delete and hide the row from grid view
if (DeleteUserByID(UserId))
gvRow.Visible = false;
}
For complete code see
You are passing TextBox object instead instead of Text property of TextBox
Asset asset = db.Assets.Single(x=>x.No == Convert.ToInt32(id.Text));
and your TextBox is also coming null means it's unable to find it in GridView, try like this:
TextBox id = e.Row.FindControl("txtEditNo");
Also see this CodeProject article to understand how to use ItemTemplate and EditItemTemplate
why are you adding a second commandfield instead of just enabling the delete button on the existing one.
if you are using a command field you should be supplying an compatible datasource that provides Delete functionality
if you're "rolling your own" delete functionality then just use a regular Button control and supply a CommandName and CommandArgument, such as CommandName="MyDelete" CommandArgument=<row number> where <row number> is supplied via GridView RowDataBound() event.
Regardless of how you choose to implement Delete you should be placing the key field in the GridView DataKeys Property and not as a field within each row. This will make obtaining the PK far easier than what you are trying to do
I guess, in my HTML, i have only the value that's bound to the item, is being displayed, and there are no textboxes in my <ItemTemplate>, hence, it pulls null value. Whereas, in my <EditItemTemplate> there is a textbox, which can pull the value from the cell.
So I changed my HTML to this:
<asp:TemplateField HeaderText="Id">
<ItemTemplate>`<asp:label runat="server" ID="lblEditNo" ReadOnly="True" Text='<%#Eval("No")%>'></asp:label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox runat="server" ID="txtEditNo" ReadOnly="True" Text='<%#Eval("No")%>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
and no change in my codebehind, and this resolved the issue.

Hyperlink in Gridview which is autogenerated in C#

I have a Gridview which is autogenerated by fetching data from various tables.
Now my requirement is i need to make my first column as hyperlink so that if it is clicked then it has to navigate to another page with hyperlinked value.
In the second page i have Lable this label should show the hyperlink value and based on that the data will be populated on the second page.
For example:
I have a gridview with 10 columns..My first column is Emp Id.
If that id is clicked it has to take me to second page and the label control must get this id value and based on that id the rest of the info like emp name emp DOB should be filled.
i am using C# as my code behind.
Can anyone help me to proceed..
Awaiting ur reply
You need the <asp:HyperLinkField />
<asp:GridView>
<Columns>
<asp:HyperLinkField HeaderText="Id" DataTextField="YourID" DataNavigateUrlFields="YourID"
DataNavigateUrlFormatString="SecondPage.aspx?Id={0}" />
</Columns>
</asp:GridView>
You might need to remove the AutoGenerateColumns="true" property and type the fields yourself, selecting only the columns you want to show - using <asp:BoundFied DataField="ColumnName" />
In case you want to pass multiple values in the querystring, separate the fields with comma
DataNavigateUrlFields="YourID, SecondField"
and your format string would be
DataNavigateUrlFormatString="SecondPage.aspx?Id={0}&param2={1}"
Other links
HyperLinkField.DataNavigateUrlFormatString Property
How to pass multiple values in HyperlinkField
You can use a TemplateField column in your GridView:
<asp:TemplateField>
<ItemTemplate>
<asp:HyperLink ID="linkToDetails" runat="server" NavigateUrl='Details.aspx?empId=<%# Eval("empId") %>' Text='<%# Eval("empId") %>'></asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
On the Details.aspx page you should get the empId from the QueryString and get the details from the database.

Get Item from GridViewRow ASP.NET

I have a GridView which I Bind a DataSource to it from a SQL Database, the grid has a column with a checkbox in it so I can "select" a few Item in it (Rows actually). What I want here is to do some updates on the Item in each selected rows, but after some search I can't find how to access the Item in a Row, I though DataItem would work, but it's giving me a Null.
Edit: To make it short, I have a GridView which is built from a DataSource, so basically, each rows represent an Object, when I have a checkbox checked in one of the rows, I want to be able to grab the Object related to that Row, what is the easiest way to achieve that?
The DataBinding on Page_Load:
if (!Page.IsPostBack)
{
gvUnusedAccessories.DataSource = currentContext.Items.OfType<Accessory>().Where(ac => ac.Item_Parent_Id == ((PhoneLine)currentItem).Parent.Item_Id);
gvUnusedAccessories.AutoGenerateColumns = false;
gvUnusedAccessories.DataBind();
}
The event when I press the Update Button, It actually browse the rows and if the row has a checked box it's gonna do the update:
protected void btnAddToMobile_Click(object sender, EventArgs e)
{
foreach (GridViewRow row in gvUnusedAccessories.Rows)
{
if(((CheckBox)row.FindControl("chkSelect")).Checked)
{
((Accessory)row.DataItem).PhoneLine_Id = currentItem.Item_Id;
}
}
}
And here's my GridView in the .aspx :
<asp:GridView ID="gvUnusedAccessories" runat="server">
<Columns>
<asp:CommandField ShowSelectButton="True" />
<asp:TemplateField HeaderText="Select">
<ItemTemplate >
<asp:CheckBox ID="chkSelect" runat="server" AutoPostBack="True"/>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Item_Id" HeaderText="ID" ReadOnly="True"/>
<asp:BoundField DataField="Item_Name" HeaderText="Name" ReadOnly="True"/>
<asp:BoundField DataField="AccessoryModel" HeaderText="Modèle" ReadOnly="True"/>
<asp:BoundField DataField="AccessoryBrand" HeaderText="Marque" ReadOnly="True"/>
</Columns>
</asp:GridView>
Any hint on how to access the Object contained inside a Row?
I know I could actually get the ID and then do a SQL request to my DB, but it seems to be a bit heavy and there must be a better solution.
Unless you're storing the DataSource in ViewState or session once the databinding is done you lose the data source. The DataItem will always be null unless you do this. Because of this I often find myself storing the data source in view state. Of course this means your page size is going to get bigger. The other option as you stated is to requery the data source with some sort of primary key. Depending on your needs I can't say which option is better. I tend to lean towards view state rather than a second DB call since that can be an expensive call to make
Given that you have the AutoPostBack set to true on your asp:checkbox you must update the row as you set the checkbox
So I would suggest you you set event OnCheckedChanged="chkStatus_OnCheckedChanged" on asp:checkbox called chkSelect and then you can only update the selected row and don't have to iterate over the enitre grid.
Here is an example how you can get the row items of the selected checkbox
public void chkStatus_OnCheckedChanged(object sender, EventArgs e)
{
CheckBox chkStatus = (CheckBox)sender;
//now grab the row that you want to update
GridViewRow row = (GridViewRow)chkStatus.NamingContainer;
string cid = row.Cells[1].Text;
bool status = chkStatus.Checked;
//now you can do you sql update here
}

ASP.NET 2.0 Gridview CheckBox column

I have a GridView that displays data on three columns. On the third column I have a CheckBox. I have two things that I need to achieve
CheckBox will be checked based on the column value (1,0)
If it is checked the rest of the two columns should display #### However the data for the two columns should remain in the database.
How can this be achieved?
Can I find the CheckBox on RowDataBound event and check the value and make the CheckBox checked and unchecked? How about making the other columns ####?
NEW Comments:
string str = ((System.Data.DataRowView)(e.Row.DataItem)).Row.ItemArray[2].ToString();
this helps to set the checkbox checked or not.
if checked is true I am trying the following.
((System.Data.DataRowView)(e.Row.DataItem)).Row.ItemArray[0] = "#####";
((System.Data.DataRowView)(e.Row.DataItem)).Row.ItemArray[1] = "#####";
((System.Data.DataRowView)(e.Row.DataItem)).Row.AcceptChanges();
It is displaying the gridview checkbox as checked but the column value is not changed to "####"
You can turn your item columns into TemplateColumns and do the following which will localize your code to the control level and you don't have to worry about all the searching. I pefer to never use the built in column types because there are usually future enhancements that require changing the columns to TemplateColumns anyways. It also gives you a lot of flexibiltiy on useage.
Here is an example:
<asp:GridView ID="grdYourGrid" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="YourField1">
<ItemTemplate>
<asp:Literal runat="server" ID="ltYourField1"
OnDataBinding="ltYourField1_DataBinding" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="YourField2">
<ItemTemplate>
<asp:Literal runat="server" ID="ltYourField2"
OnDataBinding="ltYourField2_DataBinding" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="YourCheckBoxField">
<ItemTemplate>
<asp:CheckBox runat="server" ID="chkYourCheckBoxField"
OnDataBinding="chkYourCheckBoxField_DataBinding" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Then in your codebehind implement each control's OnDataBinding:
protected void ltYourField1_DataBinding(object sender, System.EventArgs e)
{
Literal lt = (Literal)(sender);
lt.Text = (bool)(Eval("YourCheckBoxField")) ?
"##########" : Eval("YourField1");
}
protected void ltYourField2_DataBinding(object sender, System.EventArgs e)
{
Literal lt = (Literal)(sender);
lt.Text = (bool)(Eval("YourCheckBoxField")) ?
"##########" : Eval("YourField2");
}
protected void chkYourCheckBoxField_DataBinding(object sender, System.EventArgs e)
{
CheckBox chk = (CheckBox)(sender);
chk.Checked = (bool)(Eval("YourCheckBoxField"));
}
The advantages to doing it this way is your could replace code easily as it is all isolated and has no 'searching' for expected controls. I very rarely use the RowDataBound event because it makes you have to write specific code to look for the controls and it makes more sense to me to have the code localized to the control. If someone changes something they know there are ONLY affecting that one control instead of everything on the row possibly as a side effect. You could also use the <%# method and do the Evals right in the markup but I personally prefer to never have any code in the aspx markup at all.

Categories

Resources