How to insert arbitrary number of links in a gridview cell? - asp.net

I'm populating a gridview using a table and there is column which holds link IDs.
There can by many link IDs in the same cell.
If the cell contains one link ID then it works fine. The challenge is to support arbitrary number of links on the same cell.
My code:
<asp:HyperLinkField DataNavigateUrlFields="CWEID"
DataNavigateUrlFormatString="https://cwe.mitre.org/data/definitions/{0}.html"
DataTextField="CWEID" HeaderText="CWE ID" Target="_blank"/>
The cell value retrieved from table can be: [770\n838\n120], thus the cell should show 3 links for each ID.
I searched around, and it seems we can do it statically but not for arbitrary number of links.
Any pointers on how to accomplish this?

My suggestion is to replace HyperLinkField with TemplateField and nested Repeater inside.
There is example :
<asp:TemplateField HeaderText="CWE ID">
<ItemTemplate>
<asp:Repeater runat="server" ID="rptLinks" DataSource='<%# Eval("CWEID").ToString.Replace("\n", "").Split(" ")%>'>
<ItemTemplate>
<%# Container.DataItem%>
<br />
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:TemplateField>
Repeater will split CWEID (with \n, I think that is vbCrLf in vb.net so You can replace \n with vbCrLf, without double quotes) record and place all links in separated <a href.... You'll get all links in that cell. There is no matter how many links are stored into CWEID (one or more).
So, result will be (for example) :
770<br>
838<br>
120<br>
Ot just one link, depend how many links You have in CWEID.
UPDATE :
Code changed for DataSource to <%# Eval("CWEID").ToString.Replace("\n", " ").Split(" ")%>

You could add a handler to the gridview's RowDataBound event. In that event you have the ability to modify the contents of any of the cells being rendered in the current row of the gridview, including the ability to create new HTML elements and insert them. In the code below I'm adding an icon to the first cell in a gridview if the current row has child data to be shown.
'New Bootstrap style toggle button for details view
Dim toggle As New HtmlGenericControl("i")
With toggle
.Attributes("class") = "icon-plus icon-white"
.Attributes("onclick") = "javascript: gvrowtoggle(" & e.Row.RowIndex + (e.Row.RowIndex + 2) & ")"
.Attributes("id") = "toggleBttn"
End With
Then I append the new control to the first cell in the current row:
e.Row.Cells(0).Controls.Add(toggle)

Related

Why am I losing a DataItemTemplate control in a column when I remove all other columns in an ASPxGridView?

I have a 1 column grid. During user interaction, more columns are built and added dynamically. No matter how many columns are added or removed from the grid, the initial Print button column should always remain. Here's the grid.
<dx:ASPxGridView ID="gvAdvancedResults"
ClientInstanceName="gvAdvancedResults" runat="server" EnableRowsCache="False" KeyFieldName="ID" AutoGenerateColumns="True">
<Columns>
<dx:GridViewDataColumn Width="3%" VisibleIndex="0" Caption="Print">
<DataItemTemplate>
<dx:ASPxButton ID="btnDisplayMEC" runat="server" OnClick="btnDisplayMEC_OnClick" ClientInstanceName="btnDisplayMEC" CommandArgument='<%# Eval("ID") %>'
CssClass="reportbutt" BackColor="Transparent" Border-BorderStyle="None" Width="16" Height="16">
<Image Url="~/Assets/Images/printer.png" Width="16" Height="16"></Image>
</dx:ASPxButton>
</DataItemTemplate>
</dx:GridViewDataColumn>
</Columns>
</dx:ASPxGridView>
On a button click, I use the following to clear and repopulate the grid columns from datatable dt
'Remove all columns except the first (index 0)
For gix As Integer = gvAdvancedResults.Columns.Count - 1 To 1 Step -1
If gix <> 0 Then gvAdvancedResults.Columns.RemoveAt(gix)
Next
'Add new columns to the gridview
For Each col As DataColumn In dt.Columns
Dim xcol As Object = gvAdvancedResults.Columns(col.ColumnName)
If xcol IsNot Nothing Then Continue For
Dim newcol As New GridViewDataColumn(col.ColumnName, col.ColumnName)
gvAdvancedResults.Columns.Add(newcol)
Next
gvAdvancedResults.DataSource = dt
gvAdvancedResults.DataBind()
Now here's the problem. The "Print" column remains through the column removal process (as it should), but the ASPxButton inside the column's DataItemTemplate disappears. All the columns that are supposed to be added, are added.
Why am I losing my print button but keeping its column?
To answer your original question, it is probably due to having AutoGenerateColumns set to True. When you bind a dataSource it probably auto generates the columns at that point. You can test this by removing your code that adds the columns and I bet you will still see the columns that were in the dataSource. It might be as simple as setting AutoGenerateColumns to False.
For a few alternative ways of doing this if that doesn't work...
It would be a bit of work but you could try making the button column template in the code behind so that you can just clear and recreate all of the columns during each page load.
Or an easier method would be to use a custom command column like so...
This is c# code but it should be similar in VB:
gvAdvancedResults.Columns.Clear();
GridViewCommandColumn commandCol = new GridViewCommandColumn(" ");//Blank for no caption.
commandCol.Name = "command";
commandCol.Width = Unit.Pixel(30);
commandCol.ButtonType = GridViewCommandButtonType.Image;
gvAdvancedResults.Columns.Add(commandCol);
commandCol.VisibleIndex = 0;
GridViewCommandColumnCustomButton btnPrint = new GridViewCommandColumnCustomButton();
btnPrint.ID = "print";
btnPrint.Image.Url = "~/Assets/Images/printer.png";
btnPrint.Image.ToolTip = "Print";
commandCol.CustomButtons.Add(btnPrint );
//Then add the rest of the columns.
Then add a clientSide CustomButtonClick event to the gridView to handle the actual printing via the CustomCallback event:
<dx:ASPxGridView ID="gvAdvancedResults"
ClientInstanceName="gvAdvancedResults" runat="server"
EnableRowsCache="False"
KeyFieldName="ID"
AutoGenerateColumns="False"
OnCustomCallback="gvAdvancedResults_CustomCallback"
OR
OnCustomButtonClick="gvAdvancedResults_CustomButtonClick"
>
<ClientSideEvents CustomButtonClick="function(s, e) {
if (e.buttonID == 'print')
{
//Trigger a callbackPanel that is the parent to the gridView.
someCallbackPanel.PerformCallback(gvAdvancedResults.GetRowKey(e.visibleIndex));
//Or trigger a callback on the gridView and use GetRowKey on the server side.
gvAdvancedResults.PerformCallback('print');//Handle it on the server.
//Or some other way.
}
}" />
Or handle the server side ASPxClientGridView.CustomButtonClick Event. No example unless you really need it.
Notice that I changed AutoGenerateColumns to false since you are manually creating the columns.
Maybe if you make two gridviews, one that contain only the button column, and the other one for the rest of the data, that would surely solve the problem as you won't touch the first gridview and only bind your datas to the second gridview. Just a workaround... Not really an easy solution because you already coded the rest.

Adding an edit button to Gridview

I have written a method that retrieves data from the database and returns a datatable comprising of three columns.
This datatable I am binding to a gridview control after hiding the ID field.
DataTable dt = _qbObj.getAllTags();
dvTags.DataSource = dt;
BoundField bfName = new BoundField();
bfName.DataField = dt.Columns["Name"].ToString();
bfName.HeaderText = "Name";
BoundField bfId = new BoundField();
bfId.DataField = dt.Columns["ID"].ToString();
bfId.Visible = false;
BoundField bfDesc = new BoundField();
bfDesc.DataField = dt.Columns["Description"].ToString();
bfDesc.HeaderText = "Description";
dvTags.Columns.Add(bfId);
dvTags.Columns.Add(bfName);
dvTags.Columns.Add(bfDesc);
dvTags.DataBind();
To this gridview control, I want to add an edit button, which should pop-up a jquery modal dialog box where I can enter the updated details.
I realize that I can go with a , but the problem is that I need to pop that modal dialog box without refreshing the page, and the doesn't exactly have great support for scripting.
So inside my gridview I inserted this, an Item Template.
<asp:GridView ID="dvTags" runat="server" CssClass="labs-grid-view"
AutoGenerateColumns="False" >
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btnEdit" runat="server" Text="Edit" OnClick="dvTagEdit" CommandName="UpdateRecord"
CommandArgument='<%# Eval("ID") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Now after I am done editing the gridview doesn't update automatically, and hence I have a dedicated refresh grid button which deletes the existing "dynamically inserted columns" using this code :-
int noOfRows = dvTags.Columns.Count;
if (noOfRows > 1)
{
dvTags.Columns.RemoveAt(noOfRows - 1);
dvTags.Columns.RemoveAt(noOfRows - 2);
dvTags.Columns.RemoveAt(noOfRows - 3);
// THERE ARE A TOTAL OF **THREE** COLUMNS
}
But the problem is that after refreshing the page a couple of times, my button inside the ItemTemplate disappears and in the html is replaced with an " "
Please help me find the error. I'm thinking there is a better and easier way to achieve this. If so I'm open to them.
Thanks for reading,
Abijeet.
A few things to consider:
First, can you post your code behind for your ItemCommand event, which is rendering the modal popup and which is performing the update? It could be that your refresh after edit is not processing properly.
Second, instead of doing your databinding "inline" on your GridView, consider using the RowDataBound event within the Gridview. You can detect which row is being generated (header, data, footer) and you can properly create your edit button in there. Better yet, you can access your button from within this method and simply set the CommandArgument to your Id.
Third, when using the asp button in your GridView, it will trigger the "ItemCommand" event when clicked, which will cause a postback.
I'd recommend having a simple link in your template column, or something that you can use to trigger a jQuery modal, and you can setup a static naming convention for your items that will properly retrieve the data to put into your modal popup for editing. Then from there you should be able to process your update as normal.
I hope something in here helps.

Dynamic Gridview Template and Unique Control (ie textbox, label) IDs?

When creating a Gridview at design time you can create a template column like this:
<asp:TemplateField>
<ItemTemplate>
<asp:Label runat="server" ID="Label1"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
And in the HTML it will give it a unique name like:
<span id="gvSelect_ctl02_Label1">blahblah</span>
And I can then reference this label in the code behind by:
CType(e.Row.FindControl("Label1"), Label)
Which is PERFECT. But I can't figure out how to do this when I'm creating TemplateFields Dynamically. I've got the following code in my "InstantiateIn":
Dim hl As New HiddenField
hl.ID = "hHidden"
hl.Value = 0
AddHandler hl.DataBinding, AddressOf Me.hl_DataBinding
container.Controls.Add(hl)
And this DOES create a hidden control with the ID as hHidden in each row. But it doesn't give it the unique ID like "gvSelect_ctl02_hHidden" it's just "hHidden". And I know there are ways to append the row number to it myself. But I was wondering if there was a way for it to do this automatically. And still allowing me to reference the hiddenfield like:
CType(e.Row.FindControl("hHidden"), HiddenField)
Ugh.. another answer to my own question. I was looking for the name in the RowCreated. I should have been looking for it in the RowDataBound event.
it works now.. now that I'm doing it correctly.
(I may have too many things on the go at once..) :S

tooltip in asp.net

I have a gridview for which I am binding data from a Generic List collection. Currently not connected to DB. All the columns in the GridView are defined as properties(get;set.
I want to have tooltip on one of the columns. The column has a very big description. I want to show only 3 words in the column and the rest of the description should appear in tooltip.
Currently my gridview has only asp:gridview id and runat server
There are no columns, headertemplate and itemtemplate.
Could anyone suggest some idea on this.
Thanks in advance
Well, I don't know how you are getting your columns in place...but I suppose you could put a Label webcontrol in the itemtemplate for the header of each column, and give that label's tooltip property the value you want it to have.
Seems to me like that would be a pretty viable solution for this, if I'm understanding you correctly..
You can use an itme template with a label as mentioned. Bind the label the full description:
<ItemTemplate>
<asp:Label id="l1" runat="server" Text='<%# Eval("Description")' />
</ItemTemplate>
In code-behind, use RowDataBound to process each row accordingly:
protected void RowDB(..)
{
Label l = e.Row.Cells[4].Controls[1] as Label;
if (l == null) return;
string description = l.Text;
l.Text = //Partial text here
}
And the grid will bind each row, the full text is passed to a variable, and you can insert a substring of the text (3 words or such) by assigning the new value to the text property.
What kind of tooltip are you looking for? You could use the tooltip property, or consider using the ACT HoverMenuExtender: http://www.asp.net/AJAX/AjaxControlToolkit/Samples/HoverMenu/HoverMenu.aspx

ASP.NET: Gridview Showing a button on a row, when a row cell vlaue = false in the Bound row from the database

I have a GridView binded to a datasource, i was wondering of how i can check a row cell value (bool) from the database row being bound , and then show a button on the rows where the cell value equals to false..
i am using OndataBound Event to retrieve the Gridview-row being bound, i take the ID show, run another procedure against the database to find the value of the cell from the corresponding Database row..
but i cant figure out how to add the button..
also is there any other ways to handle this scenario?
Solution 1: Create a button with an ID where you want it in the gridview, with an attribute visible=false. Whenever you want to show the button, retrieve it (currentGridRow.FindControl("chosen button ID")) and set it's visible attribute to true.
put your button in a templatefield, like that:
<asp:TemplateField HeaderText="foobar" >
<ItemTemplate>
<asp:ImageButton ID="plusbutton" CssClass="cplusButton" ToolTip="plusButton" OnClick="buttonAdd_Click" runat="server" Visible = "false"/>
</ItemTemplate>
</asp:TemplateField>
Solution 2: dynamically create the button (Button b = new Button; currentGridRow.Cell[].Controls.Add(b);), but it's a pain to deal with the viewstate and the events handler. Don't go that way.

Resources