Everyone.
I have a question when combining cells in GridView. I konw how to combine BoundField cells, but I do not know how to combine TemplateField cells in asp.net GridView.
EDIT:
Perhaps I did not make my question clearly and I am sorry about that. My question is that I use GridView to bind data from db and There is a field named UserName, one user has several records in the db, so I want to combine UserName in one cell(i can combine it correctly). In the same way, I want to do some operation to this user such as Add, Delete. So i put these operations into TemplateField, but i do not konw how to combine TemplateField like BoundField. I have a low reputation, so i can not post images
Any good ideas?
Sorry for my poor english! Thanks in advance.
There isn't a way to merge/combine fields. I think you misunderstood the BoundFields/TemplateField. However you can use Eval() and Bind() to show/bind one or more expression into single cell//column..
Read MSDN articles:
BoundField
TemplateField
EDIT:
#loren : There is a field named UserName, one user has several records
in the db.
I guess you need to use "nested" grid or you may also use any data control (formview, detail view or ListView).
Here is demo that shows how to bind nested data controls.
I've define two classes - Contact, Info
public class Contact
{
public string Address{get;set;}
public string Phone {get;set;}
}
public class Info
{
public string UserName {get;set;}
private List<Contact> _addr=new List<Contact>();
public List<Contact> Address
{
get { return _addr; }
set { _addr = value; }
}
}
In .aspx page (Markup),
<asp:GridView
ID="GridView1"
runat="server"
AutoGenerateColumns="false"
onrowdatabound="GridView1_RowDataBound"
>
<Columns>
<asp:TemplateField>
<ItemTemplate>
<p>
Username :
<asp:Literal
ID="UserName"
runat="server"
Text='<%#Eval("UserName") %>'
>
</asp:Literal>
</p>
<asp:GridView
ID="GridView2"
runat="server"
AutoGenerateColumns="false"
>
<Columns>
<asp:TemplateField>
<ItemTemplate>
<p>Phone :
<asp:TextBox
runat="server"
ID="txtDetail"
Text='<%#Bind("Phone") %>'
></asp:TextBox>
</p>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
and in code-behind (aspx.cs),
List<Info> info;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
info = new List<Info>()
{
new Info()
{
UserName="User1",
Address =
{
new Contact() { Phone="2929927", Address="Address1"},
new Contact() { Phone="2929928", Address="Address2"},
}
},
new Info()
{
UserName="User2",
Address =
{
new Contact() { Phone="2929929", Address="Address3"},
new Contact() { Phone="2929930", Address="Address4"},
}
},
};
GridView1.DataSource = info;
GridView1.DataBind();
}
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
Literal username=(Literal)e.Row.FindControl("UserName");
GridView view=(GridView)e.Row.FindControl("GridView2");
if (view != null)
{
var result = from ele in info
from add in ele.Address
where ele.UserName == username.Text
select add;
view.DataSource = result;
view.DataBind();
}
}
If possible, you can update the source type.
For example, if you an object data source and a model like this :
[DataObject]
public class MyOds{
[DataObjectMethod(DataObjectMethodType.Select)]
public ICollection<MyModel> GetMyModels()
{
var result = new ListMyModel();
Populate(result); // load model with any method of you choice
return result;
}
}
public class MyModel{
public string Address { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string FullAddress {
get
{
return string.Format("{0} - {1} - {2}", Address, City, Country);
}
}
}
Note the FullAddress property. The idea is to build, for the view, properties easy to exploit. The ASPX can looks like this :
<asp:TemplateField HeaderText="Header">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text="Label">
<%# Eval("FullAddress")%>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
you can use Eval as bellow
<asp:TemplateField HeaderText="Header">
<ItemTemplate>
<asp:TextBox runat="server" ID="txt1" Text='<%#Bind("Phone") %>'></asp:TextBox>
<asp:TextBox runat="server" ID="txt2" Text='<%#Bind("Address") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
Related
I used this code: (Eval("RegDtTime")-DateTime.Now to calculate the difference between Registered DateTime (is in a database) and DateTime.now in a gridview, But get this error: operator '-' is not defined for types 'Object' and 'Date'. So what should I use instead?
Use below Eval Object
<%# System.Convert.ToDateTime(Eval("RegDtTime"))%>
So that your template will be
<asp:TemplateField ItemStyle-Width = "100px" HeaderText = "DATE" >
<ItemTemplate >
<%# (System.Convert.ToDateTime(Eval("Date")) - (DateTime.Now)) %>
</ItemTemplate>
</asp:TemplateField>
Instead of coding the logic in aspx files, you can define a method in code behind and call that from GridView.
This is my GridView in aspx.
<asp:GridView ID="GridView1" AutoGenerateColumns="false" runat="server">
<Columns>
<asp:TemplateField HeaderText="Date">
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# GetCalculatedDateTime(Convert.ToDateTime(Eval("RegDtTime"))) %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
This is my Entity or Model.
public class MyClass
{
public DateTime RegDtTime { get; set; }
}
And this is the code behind for ASPX.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
var lst = new List<MyClass>();
lst.Add(new MyClass { RegDtTime = DateTime.Now.AddDays(-5) });
lst.Add(new MyClass { RegDtTime = DateTime.Now.AddDays(6) });
lst.Add(new MyClass { RegDtTime = DateTime.Now.AddDays(5) });
lst.Add(new MyClass { RegDtTime = DateTime.Now.AddDays(-9) });
lst.Add(new MyClass { RegDtTime = DateTime.Now.AddDays(-7) });
GridView1.DataSource = lst;
GridView1.DataBind();
}
}
public static string GetCalculatedDateTime(DateTime dt)
{
var result = dt - DateTime.Now;
return result.ToString();
}
You can write the required logic in GetCalculatedDateTime method.
Error Message:
The data source for GridView with id 'FormProprietari' did not have
any properties or attributes from which to generate columns. Ensure
that your data source has content.
I have a ASP.NEt application in which I try to bind a GridView to a List<T> objects which from what I can tell on the net it should be possible.
This is my GridView:
<asp:GridView ID="FormProprietari" runat="server">
<Columns>
<asp:TemplateField >
<ItemTemplate>
<%#((Lab_TAP_web.Proprietar)Container.DataItem).NumeProprietar%>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField >
<ItemTemplate>
<%#((Lab_TAP_web.Proprietar)Container.DataItem).PrenumeProprietar%>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField >
<ItemTemplate>
<%#((Lab_TAP_web.Proprietar)Container.DataItem).ProprietarID%>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And this is the function in which I add a new object of the Proprietar class I defined to the database then rebind the gridview to show it, I should mention that intially the database is empty and so is the gridview i,e it doesn't show up.
protected void Button2_Click(object sender, EventArgs e)
{
var Nume = TBNumeProprietar.Text;
var Prenume = TBPreNumeProprietar.Text;
MyCars db = DBSilo.db;
Proprietar newOwner = new Proprietar();
newOwner.NumeProprietar = Nume;
newOwner.PrenumeProprietar = Prenume;
newOwner.ProprietarID = (db.Proprietari.Count() + 1);
//newOwner.ProprietarID = 1;
db.Proprietari.InsertOnSubmit(newOwner);
db.SubmitChanges();
try
{
FormProprietari.DataSource = db.Proprietari.ToList();
}
catch (Exception)
{
throw;
}
FormProprietari.DataBind();
}
The problem being that I checked the List<Proprietar> which is the data source with breakpoints and the list always contains a Proprietar object.
Does anyone have a idea what I did wrong?
Moved from comment to Answer.
Please make sure you have getter and setter for each property of Proprietar class like this -
public class Proprietar
{
public string NumeProprietar { get; set; }
public string PrenumeProprietar { get; set; }
public int ProprietarID { get; set; }
}
We currently use asp:Repeater with <%#Eval("SomeField")%> in aspx page to display data.
We would like to use a single record and bind it to a asp.net control on the aspx page so we can <%#Eval("SomeField")%>.
I have tried FormView, DetailsView, and other asp.net controls. All of which required a .ToList() or IEnumerable. However, we are returning ctx.Jobs.SingleOrDefault(j => j.ID == id);
We don't want to use asp:Label or asp:Literal ..
What can we do to use the <%#Eval("SomeField")%> in the page when returning a single record?
PRESENTER
public static Job GetByID(int id)
{
using (var ctx= new CareersEntities())
{
return ctx.Jobs.SingleOrDefault(j => j.ID == id);
}
}
CODE-BEHIND
protected void Page_Load(object sender, EventArgs e)
{
Job d = new Job();
d = JobPresenter.GetByID(ID);
fvJob.DataSource = d;
fvJob.DataBind();
}
ASPX PAGE
<asp:FormView ID="fvJob" runat="server">
<ItemTemplate>
<%#Eval("Title")%>
</ItemTemplate>
</asp:FormView>
Both DetailsView and FormView will work with a single object if it's using a data source control (such as ObjectDataSource). With ObjectDataSource you can return a single element from your Select method and the data source will then wrap it in a list just for the sake of the programming interface - but it's not something you'd ever see.
If you want to directly set the control's DataSource property and call DataBind, just wrap the object in an array and then pass that in.
Here's the DetailsView:
<asp:DetailsView runat="server" ID="DetailsView1" AutoGenerateRows="false">
<Fields>
<asp:TemplateField HeaderText="First name:">
<ItemTemplate><%# Eval("FirstName") %></ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Last name:">
<ItemTemplate><%# Eval("LastName") %></ItemTemplate>
</asp:TemplateField>
</Fields>
</asp:DetailsView>
And here's the DetailsView binding code in Page_Load:
var person = new Person { FirstName = "John", LastName = "Doe" };
DetailsView1.DataSource = new object[] { person };
DetailsView1.DataBind();
Or here's a FormView:
<asp:FormView runat="server" ID="FormView1">
<ItemTemplate>
First name: <%# Eval("FirstName") %><br />
Last name: <%# Eval("LastName") %><br />
</ItemTemplate>
</asp:FormView>
And here's the Page_Load code:
var person = new Person { FirstName = "John", LastName = "Doe" };
FormView1.DataSource = new object[] { person };
FormView1.DataBind();
And here's the model type (same in both DetailsView and FormView):
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
A DetailsView requires a List?! Anyhow, why don't you use ctx.Jobs.SingleOrDefault(j => j.ID == id).ToList() ?
I have a List<string[]> items list filled with arrays of strings in my code. On the ASPX page, I have added a new grid view control:
<asp:GridView ID="ProductList" runat="server" AllowSorting="True" AutoGenerateColumns="False" DataKeyNames="ProductID" EnableViewState="False">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product" SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category" ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier" ReadOnly="True" SortExpression="SupplierName" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:C}" HeaderText="Price" HtmlEncode="False" SortExpression="UnitPrice" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" SortExpression="Discontinued" />
</Columns>
</asp:GridView>
I know that I should specify the DataSourceID attribute for the grid view in a fashion similar to this:
<asp:GridView ... `DataSourceID="ObjectDataSource1" ... >
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
But, I don't know what do OldValuesParameterFormatString, SelectMethod and TypeName attributes represent. Also, I don't have the database to bind to, I just have the list of string arrays named items. Can you help me populate the grid view? It is not necessary to do it through the binding at all. Thanks!
You don't even need an ObjectDataSource. At Page_Load in the codebehind, you can parse through the string array list and create a DataTable on the fly.
Make sure to wrap this around a Not Page.IsPostback so that it doesn't rebind on postback.
List<string[]> stringList = null;
DataTable dt = new DataTable();
DataRow dr = null;
dt.Columns.Add("ProductName", System.Type.GetType("System.String"));
dt.Columns.Add("CategoryName", System.Type.GetType("System.String"));
dt.Columns.Add("SupplierName", System.Type.GetType("System.String"));
dt.Columns.Add("UnitPrice", System.Type.GetType("System.Double"));
dt.Columns.Add("Discontinued", System.Type.GetType("System.String"));
foreach (string[] s in stringList) {
foreach (string str in s) {
dr = dt.NewRow();
dr["ProductName"] = s[0];
dr["CategoryName"] = s[1];
dr["SupplierName"] = s[2];
dr["UnitPrice"] = s[3];
dr["Discontinued"] = s[4];
dt.Rows.Add(dr);
}
}
dt.AcceptChanges();
ProductList.DataSource = dt;
ProductList.DataBind();
Edit: You'll have to change some of this code to match your needs. I'm making assumptions on the data types stored in your string[] based on the GridView code you provided.
You'll want to look into creating a class to use for your items, instead of a string[]. Maybe something like:
public class MyObject
{
public string ProductName { get; set; }
public string CategoryName { get; set; }
public string SupplierName { get; set; }
public decimal UnitPrice { get; set; }
public bool Discontinued { get; set; }
}
You'd then need something to translate the string[] into MyObject:
private MyObject ConvertToMyObject(string[] values)
{
var myObject = new MyObject();
myObject.ProductName = values[0];
myObject.CategoryName = values[1];
myObject.SupplierName = values[2];
decimal unitPrice;
if (decimal.TryParse(values[3], out unitPrice))
{
myObject.UnitPrice = unitPrice;
}
bool discontinued;
if (boo.TryParse(values[4], out discontinued))
{
myObject.Discontinued = values[4];
}
}
Then you could use that method in your code and then bind:
protected void Page_Load(parameters here)
{
if (IsPostback)
{
var myObjects = new List<MyObject>();
foreach (string[] values in items)
{
myObjects.Add(ConvertToMyObject(values));
}
ProductList.DataSource = myObjects;
ProductList.DataBind();
}
}
Like I said in the comment, make sure you have access to items in the Page_Load event handler. Also, I typed this from memory, forgot the parameters in Page_Load. You most likely already have a Page_Load handler in your code behind though.
You can try this
List<string[]> items = List<string[]>();
//add items to List
GridView1.DataSource = items;
GridView1.DataBind();
Your GridView
<asp:GridView runat="server" ID="GridView1">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Label ID="stringLabel" Text="<%# Container.DataItem %>" runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
This seems like something simple, but I can't seem to figure it out! I'm trying to get 2-way data-binding to work on an ASP.net page with a check box as one of the columns. How do I get the updated values (from check boxes) back from the gridview ?????
Here is my data type:
[Serializable]
public class UserRequirements
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserId { get; set; }
public string Email { get; set; }
public bool ThingRequired { get; set; }
}
My markup looks something like this:
<form id="form1" method="post" runat="server" >
<asp:GridView ID="UserTable" runat="server" AutoGenerateColumns="false" >
<Columns>
...
<asp:TemplateField HeaderText="Required ?">
<ItemTemplate>
<asp:CheckBox id="chkBox1" runat="server" on
Text ="Required"
checked='<%# DataBinder.Eval(Container.DataItem,"ThingRequired") %>'>
</asp:CheckBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button id="thebutton" Text="Save Changes" OnClick="UpdateRequirements" runat="server" CausesValidation=false />
</form>
My code behind looks something like this:
List<UserRequirements > _userList = new List<UserRequirements >();
protected void Page_Load(object sender, EventArgs e)
{
_userList = data_layer.GetUserRequirments();
this.UserTable.DataSource = _userList;
this.UserTable.DataBind();
}
Eventually, I will call something like this, but I don't know where this should go or how to get the values back from the gridview:
void UpdateRequirements(object sender, EventArgs e)
{
_userList = ???????????? // How do I get the data?
data_layer.UpdateUserRequirements( _userList );
}
foreach (GridViewRow di in GridView1.Rows)
{
HtmlInputCheckBox chkBx = (HtmlInputCheckBox)di.FindControl("chkBox1");
if (chkBx != null && chkBx.Checked)
{
/// put your code here
}
}
try something like this to get the value on change:
protected void OnCheckedChanged(object sender, EventArgs e)
{
CheckBox c = (CheckBox)sender as CheckBox;
string checkBoxId = c.ID;
bool checkBoxValue = c.Checked;
//update database
}
[EDIT]
If you want to get all the values from the rows in the grid in one go, you will need to bind the checkboxes using the Id for the row or item in your list of UserRequirements, so in your grid do something like this:
<asp:CheckBox ID="<%# Eval('Id') %>" />
then on postback, iterate through the items in the UserRequirements list matching the object/item Id with the Ids of the checkboxes in the grid .. something like this:
foreach (UserRequirement item in Requirements)
{
Control c = grid.FindControl(item.Id);
CheckBox cbx = c as CheckBox;
if (cbx != null)
{
bool value = cbx.Checked;
//update db
}
}
Note: you may need to use FindControl recursively to search child controls, or do a foreach on each GridViewRow object in the grid to pickup the checkbox you are looking for.