I ask this question because I think I have different problem with this : How to hide gridview column after databind?
My gridview has data from database. I don't set any "td" in my code, but html changes the gridview to table and have "td". The problem is, I don't want the cell or "td" is shown on the page, I just want to receive the data in the cell to show the image in the database.
This is code to retrieve data from database:
public static DataTable FetchAllImagesInfo(int id)
{
string sb = "Select img_content, Img_id, csrid FROM images WHERE Img_Id = " + id + ";";
SqlConnection conn = DatabaseFactory.GetConnection();
SqlDataAdapter da = new SqlDataAdapter(sb, conn);
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
This is codebehind to bind GridView, here I tried to set Visible to true or false, but it doesn't work. I set column index manually because it's only has 3 column :
GridView1.DataSource = ProductAllLocationCatalog.FetchAllImagesInfo(_id);
GridView1.DataBind();
GridView1.Columns[0].Visible = true;
GridView1.Columns[1].Visible = false;
GridView1.Columns[2].Visible = false;
And, this is my aspx code :
<asp:GridView ID="GridView1" runat="server">
<Columns>
<asp:TemplateField runat="server">
<ItemTemplate runat="server">
<asp:Image ID="image1" runat="server" ImageUrl='<%#"Handler.ashx?csrid="+Eval("csrid") %>' style="max-height:400px; max-width:940px; text-align:center; margin:auto; display:block;" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
I just need the image from the database, not other. But if I only SELECT the image, gridview can not do DataBind(), and I can't get value of "csrid".
Thank you!
Try
protected void GridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
e.Row.Cells[1].Visible = false;
e.Row.Cells[2].Visible = false;
}
I believe the issue is that your GridView is automatically generating your columns, and the GridView.Columns property only stores explicitly declared columns. Instead of hiding the column, you can hide the cells comprising the columns you don't want when each row is bound. It seems like there should be a better way to handle this, but outside of using explicitly declared columns, I don't know one.
Related
I have a Gridview in a C# ASPX Page called Gridview1 that pulls a Table from a SQL Server and displays it on PageLoad.
There are 10 columns in the Gridview and I need all the distinct values in column 7 which is Code
Code
A
C
D
A
A
D
B
E
R
A
A
C
B
Basically I need some kind of structure, list or even a datatable to get all the distinct values from the Column "Code". From the example above it would be a list or datatable with 6 entries since there are 6 unique codes in the Gridview column.
Distinct
A
B
C
D
E
R
Any ideas how this can be implemented?
Well, ALWAYS but always try to do such code against the data source and NOT the web page HTML (be it a list view, or grid view, repeater or whatever). The web page is for display of the data, not data base stuff.
Now, I suppose in this case, we could operate against the grid, but it usually a WHOLE lot easier to operate against the data.
So, say this grid:
<div style="float:left;width:40%">
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false"
CssClass="table table-hover table-striped"
DataKeyNames="ID">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Button ID="cmdDel" runat="server"
Text="Delete"
CssClass="btn"
onclick="cmdDel_Click"
onclientClick="return confirm('really delete this?');"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
<div style="float:left;margin-left:40px">
<h4>City list</h4>
<asp:ListBox ID="ListBox1" runat="server"
DataTextField="City"
DataValueField="City" Width="163px" Height="159px"
></asp:ListBox>
</div>
</div>
So, right next to the grid, I have a list box we will list out each seperate city.
So, code to load is this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
DataTable rstData = MyRst("SELECT * FROM tblHotelsA ORDER BY HotelName");
GridView1.DataSource = rstData;
GridView1.DataBind();
// now fill out a list box of each city
DataTable rstCity = new DataTable();
rstCity = rstData.DefaultView.ToTable(true, "City");
rstCity.DefaultView.Sort = "City";
ListBox1.DataSource = rstCity;
ListBox1.DataBind();
}
And we get this:
So, NOTE how we went to the data source - NOT the grid (the grid is not a database and in most cases we should not think of the grid as such).
However, we could also pull the values out of the grid (can't see why we would do this).
So, lets drop in listbox 2, and add this code that operates against the grid:
our 2nd listbox - this time NOT data bound.
So, this:
<div style="float:left;margin-left:40px">
<h4>City list 2nd example</h4>
<asp:ListBox ID="ListBox2" runat="server"
DataTextField="Text"
DataValueField="Value"
Width="163px" Height="159px"
></asp:ListBox>
</div>
And say a button click or whatever - we run this code to fill out 2nd listbox from the data grid.
FYI:
If you using templated fields, then you have to use findcontrol to get the control.
If you using data fields, then you use .cells[] array/collection.
but, CAUTION, since empty cells will render as a non breaking space &nsb;
So, we convert from html, just to be save, and we have this code:
protected void Button1_Click1(object sender, EventArgs e)
{
List<string> CityList = new List<string>();
foreach (GridViewRow gRow in GridView1.Rows)
{
string sCity = Server.HtmlDecode(gRow.Cells[2].Text);
if (!CityList.Contains(sCity))
CityList.Add(sCity);
}
// display our list in 2nd listbox
CityList.Sort();
foreach (string sCity in CityList)
{
ListBox2.Items.Add(new ListItem(sCity, sCity));
}
}
So, now we have this:
So try to operatee against the data. I mean, we could even say get a list of distinct citys wiht a query, say this:
string strSQL = "SELECT City from tblHotels GROUP BY City";
Datatable rstCity = MyRst(strSQL);
ListBox1.DataSource = rstCity;
ListBox1.DataBind();
So, in most cases??
Much less effort and better to get this data from the data source, and NOT go to the GV - as it is a display and render system - not a data base, nor is it a data source.
Now, in above, I used a helper function MyRst. All that does is return a table based on sql - (became VERY tired very fast having to type that type of code over and over). So that was this:
DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
I have the examples of data saved in the database as shown in the figure:
list of attachments uploaded by 3 different users (STAFF_145, STAFF_143 and STAFF_147)
When I called it from gridview list, it shows like this:
Gridview of list attachment
Based on the gridview, I tried to apply the "Attachments & TRF" column with <asp:Label ID="txt_training_attach_name" runat="server" Text='<%# Bind("training_attach_name") %>' ReadOnly="true">.
It shows error when I've change to "Dropdownlist" instead of using "Label" or "Textbox".
System.ArgumentOutOfRangeException: ''txt_training_attach_name' has a
SelectedValue which is invalid because it does not exist in the list
of items. Parameter name: value'
The error points out at here when I used Dropdownlist:
if (dt.Rows.Count > 0)
{
Grid_Attachment.DataSource = dt;
Grid_Attachment.DataBind();
}
It is possible if I want to make a gridview as shown as like this?
Dropdownlist and Merge Column
I've try many ways since last month but I still cannot get the answer. Appreciate if you could help me. Thank you in advanced.
You don't mention if the staff table of up-loaded files is a different table then the one that supposed to drive the grid.
if it is for some reason, then build a group by query that does not include the file(s) column, and group by so you wind up with a SINGLE row for each staff member.
So, then we can drop in a grid list this:
And I am going to use a listbox in place of a combo (dropdown), so it will NICE display the files - you can change that to a dropdown if you want - same code
So, the markup might be this:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table table-hover" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:BoundField DataField="Firstname" HeaderText="First Name" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
<asp:BoundField DataField="TrainingDate" HeaderText="Training Date" DataFormatString="{0:yyyy-MM-dd}" />
<asp:BoundField DataField="ApplicationDate" HeaderText="Application Date" DataFormatString="{0:yyyy-MM-dd}" />
<asp:BoundField DataField="ProgramTitle" HeaderText="Program Title" />
<asp:BoundField DataField="TrainingCost" HeaderText="Training Cost" DataFormatString="{0:c}" />
<asp:TemplateField HeaderText="Documents Submitted">
<ItemTemplate>
<asp:ListBox ID="cboFiles" runat="server" Width="200PX"
DataTextField ="FileName"
DataValueField="FileName">
</asp:ListBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Note how we added a listbox (as noted, use a drop down if you want).
So, the code to fill this gv would thus be this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
GridView1.DataSource = MyRst("SELECT * from Users ORDER BY FirstName");
GridView1.DataBind();
}
DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
}
return rstData;
}
However, for each row, we need to load up the list of files for that one row. As noted, I don't know if you have two tables here - or one. (but, it really does not matter - as noted, use a group-by for this main grid data source.
Now, the only extra part is to use the gv "row data bound" event. This fires for each row during render, and is the idea event to load up the combo or list box.
That code is thus this:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// get PK row id (user id)
int? PKID = GridView1.DataKeys[e.Row.RowIndex]["ID"] as int?;
string strSQL = "SELECT FileName FROM MyFiles WHERE User_ID = " + PKID;
DataTable rstFiles = MyRst(strSQL);
ListBox cboFiles = e.Row.FindControl("cboFiles") as ListBox;
cboFiles.DataSource = rstFiles;
cboFiles.DataBind();
cboFiles.Rows = 1;
if (rstFiles.Rows.Count > 1)
cboFiles.Rows = rstFiles.Rows.Count;
}
}
And above I do have two columns. One is JUST file name, and one column is the full path name + file to the up-load folder. If you don't have just a file name column, then we can write a bit of code to JUST include + show file name.
the results of running the above is thus this:
So I have a web application that uses a GridView.
We currently add 1 new blank record at a time fill it in and move on. There are times when the data needing to be entered has several fields that need to be duplicated. Is there a way to add a blank row, fill it in , and then copy that row and paste it back into the GridView?
I've looked at clone, but i haven't seen anything that works in a web application. Thanks for any advice.
Well, one way, is you could add a copy button to the grid?
Say we have this grid:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID"
cssclass="table table-hover borderhide">
<Columns>
<asp:TemplateField HeaderText ="First Name">
<ItemTemplate>
<asp:TextBox ID="txtFirst" runat="server" Text = '<%# Eval("FirstName") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText ="Last Name">
<ItemTemplate>
<asp:TextBox ID="txtLast" runat="server" Text = '<%# Eval("LastName") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText ="City">
<ItemTemplate>
<asp:TextBox ID="txtCity" runat="server" Text = '<%# Eval("City") %>'></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText ="Active">
<ItemTemplate>
<asp:CheckBox ID="Active" runat="server" Checked = '<%# Eval("Active") %>'></asp:CheckBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText ="Copy">
<ItemTemplate>
<asp:ImageButton ID="cmdCopy" runat="server" Text="Copy"
ImageUrl="~/Content/copy1600.png" Height="32px" Width="32px"
OnClick="cmdCopy_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="cmdSave" runat="server" Text="Save" CssClass="btn-primary" OnClick="cmdSave_Click1" />
<asp:Button ID="cmdAdd" runat="server" Text="Add Row" CssClass="btn-primary" style="margin-left:20px" OnClick="cmdAdd_Click1"/>
<br />
So, code to load this grid up
private DataTable rstPeople = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
LoadGrid();
ViewState["MyTable"] = rstPeople;
}
else
rstPeople = (DataTable)ViewState["MyTable"];
}
public void LoadGrid()
{
using (SqlCommand cmdSQL = new SqlCommand("SELECT * from People",
new SqlConnection(Properties.Settings.Default.TEST4)))
{
cmdSQL.Connection.Open();
rstPeople.Load(cmdSQL.ExecuteReader());
GridView1.DataSource = rstPeople;
GridView1.DataBind();
}
}
And the add row button code:
protected void cmdAdd_Click1(object sender, EventArgs e)
{
GridToTable(); // user may have edits
// add a new row to the grid
DataRow OneRow = rstPeople.NewRow();
OneRow["Age"] = 0;
OneRow["Active"] = true;
rstPeople.Rows.Add(OneRow);
GridView1.DataSource = rstPeople;
GridView1.DataBind();
}
So we click on add row, and that gives us this:
So, we have that blank row. But, in place of add row, we could click the copy button, and that would add a row - but copy from current. (I suppose we could have a copy + paste button - but that's WAY TOO much UI here).
So, add row = add blank row.
but, copy row button - add row - copy.
The code for that looks like this:
protected void cmdCopy_Click(object sender, ImageClickEventArgs e)
{
GridToTable(); // user might have done some editing
ImageButton cmdCopy = (ImageButton)sender;
GridViewRow gvRow = (GridViewRow)cmdCopy.Parent.Parent;
DataRow CopyFrom = rstPeople.Rows[gvRow.RowIndex];
DataRow OneRow = rstPeople.NewRow();
OneRow["Age"] = 0;
OneRow["FirstName"] = CopyFrom["FirstName"];
OneRow["LastName"] = CopyFrom["LastName"];
OneRow["City"] = CopyFrom["City"];
OneRow["Active"] = CopyFrom["Active"];
rstPeople.Rows.Add(OneRow);
GridView1.DataSource = rstPeople;
GridView1.DataBind();
}
Now I not shared how teh save button works.
So, the user now can add new rows. Tab around - edit any row. or even copy a new row (and again, edit some more).
So save the whole mess and grid back to the database, we
Send Grid back to table
Send table back to database.
So the save all button is thus this:
protected void cmdSave_Click1(object sender, EventArgs e)
{
GridToTable();
// now send table back to database with updates
string strSQL = "SELECT ID, FirstName, LastName, City, Active from People WHERE ID = 0";
using (SqlCommand cmdSQL = new SqlCommand(strSQL,
new SqlConnection(Properties.Settings.Default.TEST4)))
{
cmdSQL.Connection.Open();
SqlDataAdapter daupdate = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder cmdBuild = new SqlCommandBuilder(daupdate);
daupdate.Update(rstPeople);
}
}
again, really simple. And note how we did not bother with templates etc. (too messy, and really not less code then above).
I suppose you could have for a new row a "paste" icon, but if the users going to have to pick a row and copy - might as well make it "add row + copy" in one operation.
(and it not really a copy button, but more of a "duplicate row" button.
Only routine not posted was the GridToTable. This works, since we always persist the table, but any edits in GV have to be send back to the table, and thus we use this:
void GridToTable()
{
// pull grid rows back to table.
foreach (GridViewRow rRow in GridView1.Rows)
{
int RecordPtr = rRow.RowIndex;
DataRow OneDataRow;
OneDataRow = rstPeople.Rows[RecordPtr];
OneDataRow["FirstName"] = ((TextBox)rRow.FindControl("txtFirst")).Text;
OneDataRow["LastName"] = ((TextBox)rRow.FindControl("txtLast")).Text;
OneDataRow["City"] = ((TextBox)rRow.FindControl("txtCity")).Text;
OneDataRow["Active"] = ((CheckBox)rRow.FindControl("Active")).Checked;
}
}
As noted I suppose you could drop in a "copy" button, and ONLY persist + save the row index, and then have a paste button - this would allow a cut + paste between any rows, and not be limited to just new rows. (but, that would allow the user quite easy to over-write a existing row - again UI overload from user training point of view.
The above trick is quite slick, since any new rows, any edits are sent back to the database in one simple Update operation. (and the provider is smart - if a row was not touched or changed, then sql update statements are not generated.
This whole trick works due to persisting the table in ViewState. Be warned, if you have a datapager, then you would have to call GridToTable in such navigation, or in fact execute a save command.
Also note how we picked up the .parent.parent (grid row) and again did not bother with teh GV event model. And without a gazilion template stuff, we also saved world poverty in terms of not having to mess with mutiple templates.
In fact, for any grid beyond the above, I use the exact same above approch, but perfer a ListView. The reason is that you can just drag + drop in standard asp.net controls, and you don't have to needless surround them with "item template" which again is too much work and effort.
I use datatable as data source for grid view.
And one of the columns of the data table have to display image.
Here is how I create data table:
DataTable dt = new DataTable();
List<ReportFeature> featureProps = fim.getFeatureProperties().ToList();
var headers = featureProps.FirstOrDefault().Properties.Select(k => k.Key).ToList();
headers.ForEach((h) => dt.Columns.Add(h, typeof(string)));
foreach (var feat in featureProps)
{
DataRow row = dt.NewRow();
foreach (var header in headers)
{
row[header] = feat.Properties[header];
}
dt.Rows.Add(row);
}
And here is how I bind the data table to grid view datas source:
gvfeatureProps.DataSource = dt;
gvfeatureProps.DataBind();
one of the columns in data table contains path to image.
My question is how do I make images displayed in my grid view after bind programatically?
All within <Columns> you can also use template fields
Using a asp.net Image:
<asp:TemplateField>
<ItemTemplate>
<asp:Image ID="Image1" runat="server" ImageUrl='<%# Eval("MyImageUrlColumnName") %>' />
</ItemTemplate>
</asp:TemplateField>
or the standard HTML img:
<asp:TemplateField>
<ItemTemplate>
<img src='<%# Eval("MyImageUrlColumnName") %>' />
</ItemTemplate>
</asp:TemplateField>
If you need a bit more flexibility that the ImageField used in previous answer.
If you want to add an image programatically, use the RowDataBound event.
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
//check if the row is a datarow
if (e.Row.RowType == DataControlRowType.DataRow)
{
//cast the row back to a datarowview
DataRowView row = e.Row.DataItem as DataRowView;
//create a new cell
TableCell cell = new TableCell();
//create an image
Image img = new Image();
img.ImageUrl = row["imageUrl"].ToString();
//add the image to the cell
cell.Controls.Add(img);
//add the cell to the gridview
e.Row.Controls.Add(cell);
//or use addat if you want to insert the cell at a certain index
e.Row.Controls.AddAt(0, cell);
//or don't add a new cell but add it to an existing one (replaces original content)
e.Row.Cells[2].Controls.Add(img);
}
}
I am using GridView in asp.net like this:
mygrid.DataSource = dTable;
mygrid.DataBind();
if (mygrid.Columns.Count > 1)
{
mygrid.Columns[2].Visible = false;
}
my grid view code is as follows
<asp:GridView ID="mygrid" runat="server" AllowPaging="True"
onpageindexchanging="mygrid_PageIndexChanging" PageSize="15"
PersistedSelection="true"
ondatabound="mygrid_DataBound">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:HyperLink ID="Edit" runat="server" Text="Edit" NavigateUrl='<%# Eval("Value", "~/myweppage.aspx?Id=M{0}") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
<PagerSettings PageButtonCount="4" />
</asp:GridView>
Here I am not able to set visible=false.
I tried with the following answer
How do I make several gridview columns invisible dynamically?
I am not finding datarow event in Visual Studio 2010. Can anyone help me to set the column visible property?
my Column structure of data table is
column[0] is Value column then 4 other columns are there.
my Column structure of Grid view is
column[0] is link field
column1 is Value field from Dtable
4 other columns
This is perfect solution for dynamically generated columns in gridview
Please try this :
int indexOfColumn = 1; //Note : Index will start with 0 so set this value accordingly
protected void mygrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.Cells.Count > indexOfColumn)
{
e.Row.Cells[indexOfColumn].Visible = false;
}
}
For .aspx page edit gridview tag as follow :
<asp:GridView ID="mygrid" runat="server" AllowPaging="True"
onpageindexchanging="mygrid_PageIndexChanging" PageSize="15"
PersistedSelection="true"
ondatabound="mygrid_DataBound"
OnRowDataBound="mygrid_RowDataBound">
Here is the simple answer. Create css as below
.classHide{ display:none }
then instead of column.visible = false, just assign classHide CSS class to the column.
e.g.
grdRole.Columns(0).ItemStyle.CssClass = "classHide"
grdRole.Columns(0).HeaderStyle.CssClass = "classHide"
*strong text*Try to make use of the event ItemDataBound event and try the following syntax to hide the column dynamically:
mygrid.Columns[1].Visible = false //(Example)
Column count for a datatable starts from 0 not from 1 . so if it is the second column , you want to hide, index should be 1.
Hope this helps..
right Click on gridview and select Properties then select Events you will find there RowDataBound Double Click on it and in Row data bound write this
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
e.Row.Cells[0].Visible = false;
}
Try this:
for (int i = 0; i < YourGrid.Rows.Count; i++)
{
(YourGrid.Columns[2]).Visible = false;
}