I would like to find a GridView Control within a separate class and I am having issues doing so. I even tried placing my code in the aspx.cs page to no avail. I keep getting Object reference not set to an instance of an object. I'm sure there is a simple step I'm missing, but in my research I cannot seem to find anything.
Aspx code
<asp:GridView ID="GridView1" EnableViewState="true"
runat="server"
BackColor="White" BorderColor="#CC9966"
BorderStyle="None" BorderWidth="1px" CellPadding="4" Width="933px"
onrowdatabound="GridView1_RowDataBound"
onrowdeleting="GridView1_RowDeleting"
onrowediting="GridView1_RowEditing"
onrowupdating="GridView1_RowUpdating"
onsorting="GridView1_Sorting"
AllowSorting="true"
AutoGenerateColumns="False"
PersistedSelection="true" onrowcancelingedit="GridView1_RowCancelingEdit">
<EditRowStyle Font-Size="Small" Width="100px" />
<FooterStyle BackColor="#FFFFCC" ForeColor="#330099" />
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton runat="server" ID="EditLinkButton" CausesValidation="True"
Text="Edit" CommandName="Edit"/>
<asp:LinkButton runat="server" ID="DeleteLinkButton" CausesValidation="False"
Text="Delete" CommandName="Delete"/>
</ItemTemplate>
<EditItemTemplate>
<asp:LinkButton runat="server" ID="UpdateLinkButton" CausesValidation="True"
Text="Update" CommandName="Update"/>
<asp:LinkButton runat="server" ID="CancelLinkButton" CausesValidation="False"
Text="Cancel" CommandName="Cancel"/>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
.cs code
protected void Page_Load(object sender, EventArgs e) {
SetDirectory();
System.Web.UI.Page page = (System.Web.UI.Page)System.Web.HttpContext.Current.Handler;
GridView GridViewCopy = (GridView)page.FindControl("GridView1");
Log.WriteLine("SortBindGrid: GridView Row Count: " +
GridViewCopy.Rows.Count, Log.DEBUG_LEVEL.TERSE);
return;
}
I've tried a few variations of using MainContent_GridView for the find to get and Master.FindControl with all the same result.
In one of your comments you state that the GridView isn't on the Master Page, so is it safe to assume that it's on a page that uses a Master Page? And therefore it must be in a ContentPlaceholder control?
The key issue is that FindControl method only looks for direct children (emphasis added):
This method will find a control only if the control is directly contained by the specified container; that is, the method does not search throughout a hierarchy of controls within controls.
So you either need to:
Search for the control within the correct ContentPlaceholder control, rather than from Page.
Loop through each of the Controls in Page.Controls recursively until you find the control you're after.
An example of 2:
private Control FindControlRecursive(Control rootControl, string controlID)
{
if (rootControl.ID == controlID) return rootControl;
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn =
FindControlRecursive(controlToSearch, controlID);
if (controlToReturn != null) return controlToReturn;
}
return null;
}
Once you've got your control, you should cast it using as and then check for null just in case it's not quite what you were expecting:
var gridView = FindControlRecursively(Page, "GridView1") as GridView
if (null != gridView) {
// Do Stuff
}
Don't get the page from HttpContext if you are already within the page. Instead, is there a control you can use FindControl from? Instead of use page, use:
parentControl.FindControl("GridView1") as GridView;
Instead. There is an issue with finding the grid from the page level, and using a lower level control closer to the grid will have better success.
Brian got it right but he forgot the essential part.
You won't be able to do use his code unless you add this code on top of your HTML-Code of the file where you want to use it.(Page.aspx)
<%# MasterType VirtualPath="~/Master/Site.master" %>
then you can use the code Brian suggested:
GridView grid = this.Master.FindControl("GridView1");
Edit:
If you want to use the gridview from within another class in the same file i would use the following:
Add this to the class created when you make the page
public partial class YourPageName: System.Web.UI.Page
{
public static Gridview mygrid = this.GridviewnameOFYourASPX
...
}
And to your custom class add this in your method
YourPageName.mygrid.(The changes you want to make);
Related
Is there someway to turn the row of a gridview into a hyperlink so that when a user opens it in a new tab for example, it goes to that link? Right now I am using a LinkButton and when the user opens it in a new tab, it doesn't know where to go.
I figured the .aspx code would look something like:
<asp:TemplateField>
<ItemTemplate>
<Hyperlink ID="hyperlink" runat="server" ForeColor="red" HtmlEncode="false" navigationURL="testUrl.aspx"
</ItemTemplate>
</asp:TemplateField>
The only thing is, our URLs are set up in the C# code behind as a query string, so I'm not sure how to pass that into the navigationURL section.
I'm guessing there's something I can do on the page_load with the query string to redirect to the page I need, but this is my first time working with query strings so I'm a little confused.
Thanks!
<asp:TemplateField>
<ItemTemplate>
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl='<%#String.Format("~/controller.aspx?routeID1={0}&routeID2={1}", Eval("routeid1"), Eval("routeid2"))%>'></asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
routeid1 and routeid2 are passed as query strings to the controller of that page.
What I did recently is modified my class to have a readonly property that constructs the A tag for me. This way I have control over what gets displayed; just text or a link.
<ItemTemplate>
<asp:Label ID="ColumnItem_Title" runat="server" Text='<%# Bind("DownloadATag") %>'> </asp:Label>
</ItemTemplate>
The code behind just binds an instance of the class to the gridview. You can bind the gridview whenever, on load on postback event, etc.
Dim docs As DocViewList = GetViewList()
GridViewDocuments.DataSource = docs
GridViewDocuments.DataBind()
In the above code, the DocViewList, instantiated as docs, is a list of a class that has all the properties that are needed to fill my GridView, which is named GridViewDocuments here. Once you set the DataSource of your GridView, you can bind any of the source's properties to an item.
Something like:
<asp:LinkButton ID="LinkButton_Title" runat="server" target="_blank"
PostBackUrl='<%# Eval(Request.QueryString["title"]) %>'
or binding them from the RowCreated event:
protected void GridView_OnRowCreated(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
(e.Row.FindControl("LinkButton_Title") as LinkButton).PostBackUrl = Request.QueryString["title"]))
}
}
I am having an issue with the behavior of a GridView between post backs.
The real problem comes from a TemplateField I define in the markup at column[0] with a child CheckBox control. Things work fine for the first, and second search executions. However, at some point between the second execution and anything that causes a post back there after, I lose the contents of the TemplateField.
Its only the the contents of the column and not the whole column itself that gets removed. The TemplateField is present in the source and shows a formated column at position 0 of the table.
CODE:
protected void ExecuteSearch(object sender, EventArgs e)
{
if (lb_SelectedFields.Items.Count == 0) { return; } //if no selected fields
//Generates custom SQL query based on user inputs and column Selections
BuildQuery(); // sets txbSqlText.Text = to the SQL string
DataTable Table = SqlAdapter.Select(new System.Data.SqlClient.SqlCommand(txbSqlText.Text));
for (int i = gv_SearchResults.Columns.Count - 1; i > 0; i--)
{ gv_SearchResults.Columns.RemoveAt(i); } //removes all the columns except[0]
foreach (ListItem Item in lb_SelectedFields.Items) //adds all the user defined columns
{
//Column object that is able to find the column definition
Column Col = ColumnsBasedOnFocus.FindColumName(Item.Value);
if (Col.Type == "HyperLink") { gv_SearchResults.Columns.Add(CreateHyperLinkField(Col)); }
else { gv_SearchResults.Columns.Add(CreateBoundColumn(Col, true)); } //true is if the column is visable
}
gv_SearchResults.DataSource = Table;
gv_SearchResults.DataBind();
}
ASP.NET:
<asp:GridView ID="gv_SearchResults" runat="server" GridLines="None" CellSpacing="0"
CellPadding="0" AutoGenerateColumns="false" CssClass="TABLE_LIGHTBLUE" Width="100%">
<HeaderStyle CssClass="TABLE_LIGHTBLUE_HEADERROW" />
<Columns>
<asp:TemplateField ItemStyle-Width="30" ItemStyle-Wrap="false">
<HeaderTemplate>
<center>
<asp:Button ID="btn_SelectAll" runat="server" OnClick="SelectAll" Text="All" CssClass="TEXT_SMALL" />
<asp:CheckBox ID="chk_Placeholder" runat="server" Visible="false" /></center>
</HeaderTemplate>
<ItemTemplate>
<center>
<asp:CheckBox ID="chk_Select" runat="server" Visible="true" />
<asp:Label ID="lbl_AssetGID" runat="server" Visible="false" Text='<%# Bind("i_GID") %>' /></center>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Found a link that describes a similar situation.
https://connect.microsoft.com/VisualStudio/feedback/details/104994/templatefield-in-a-gridview-doesnt-have-its-viewstate-restored-when-boundfields-are-inserted#details
They describe a bug in ASP.Net code that fails to properly manage view states with template fields in dynamically generated grid views.
Basically TemplateFields can't be properly restored from ViewState, and if you modify the ASPX-declared columns programmatically, it can't create them from the declarations either.
The only solution I could get working was to create a new class deriving from TemplateField that in the constructor set the ItemTemplate to an ITemplate-derived class, which means having to define the template programmatically instead of declaratively.
You can also rebind the gridview on each postback but that's its own can of worms.
Its very simple and i feel myself as an idiot :(
I newly started to using DevX Controls. Its documentation and sample projects are SUCKS!
My problem is:
I have an ASPxGridView on my aspx page:
<dx:ASPxGridView ID="dxdgMyGrid" runat="server" AutoGenerateColumns="False" OnStartRowEditing="DxGridStartRowEditing">
<SettingsEditing Mode="PopupEditForm" PopupEditFormHeight="200px" PopupEditFormWidth="500px"
EditFormColumnCount="2" PopupEditFormHorizontalAlign="Center" PopupEditFormVerticalAlign="Middle"
PopupEditFormModal="true" />
<Columns>
<dx:GridViewDataTextColumn FieldName="MyField1" VisibleIndex="1">
<EditFormSettings VisibleIndex="0" />
<EditItemTemplate>
<dx:ASPxDateEdit ID="dxdateMyField1" runat="server">
</dx:ASPxDateEdit>
</EditItemTemplate>
</dx:GridViewDataTextColumn>
<dx:GridViewDataColumn FieldName="MyField2" VisibleIndex="4">
<EditFormSettings VisibleIndex="1" />
<EditItemTemplate>
<dx:ASPxComboBox ID="dxcomboMyField2" runat="server">
</dx:ASPxComboBox>
</EditItemTemplate>
</dx:GridViewDataColumn>
</Columns>
How can i reach dxdateMyField1 or dxcomboMyfield2 on ASPX.CS file? I want to write:
dxcomboMyField2.DataSource = GetMyData2List();
dxcomboMyField2.SelectedItemIndex = 0;
... etc.
Thanks a lot.
You cannot access the EditItemTemplate Control Directly. You can access them at the HtmlRowCreated event as:
if (e.RowType != GridViewRowType.InlineEdit) return;
ASPxTextBox txtBox = ASPxGridView1.FindEditRowCellTemplateControl(ASPxGridView1.Columns["Name"]
as GridViewDataColumn, "ASPxTextBox1") as ASPxTextBox;
Check the documentation on Accessing Controls Contained within Templates
It is possible to cast the ASPxLabel.NamingContainer property to GridViewEditItemTemplateContainer and get a column value via the GridViewEditItemTemplateContainer.Text property.
But I like the technique of using the Init/Load event handler.When the grid switches to edit mode, the ASPxLabel.Load event is raised. Check this article The general technique of using the Init/Load event handler for implementation help.
[ASPx]
<dxe:ASPxTextBox ID="txtName" runat="server" Width="170px" OnInit="txtName_Init">
</dxe:ASPxTextBox>
[C#]
ASPxTextBox txtName;
protected void txtName_Init(object sender, EventArgs e)
{
txtName = (ASPxTextBox)sender;
GridViewEditFormTemplateContainer container = txtName.NamingContainer as GridViewEditFormTemplateContainer;
// You can remove the if statement, and try to insert a new record. You'll catch an exception, because the DataBinder returns null reference
if (!container.Grid.IsNewRowEditing)
txtName.Text = DataBinder.Eval(container.DataItem, "CategoryName").ToString();
}
Update Event:
protected void grid_RowUpdating(object sender, DevExpress.Web.Data.ASPxDataUpdatingEventArgs e)
{
e.NewValues["CategoryName"] = txtName.Text;
}
There is already an question - ASPxGridView - How to find a control inside the EditItemTemplate on DevExpress fourm .
You can use combo box init/load event handler for setting combo datasource. If that doesn't work for you, use FindEditRowCellTemplateControl (use link in comments for further explanation).
ASCX File:
<asp:datagrid runat="server" id="gridFormFields" datakeyfield="FieldID"
autogeneratecolumns="False"
onitemcommand="gridFormFields_ItemCommand" onitemdatabound="gridFormFields_ItemDataBound">
<columns>
<asp:templatecolumn>
<itemtemplate>
<asp:imagebutton runat="server" id="buttonMoveUpFormField" resourcekey="buttonMoveUpFormField"
commandname="Item" commandargument="MoveUp" imageurl="~/images/up.gif" />
</itemtemplate>
</asp:templatecolumn>
<asp:templatecolumn>
<itemtemplate>
<asp:imagebutton runat="server" id="buttonMoveDownFormField" resourcekey="buttonMoveDownFormField"
commandname="Item" commandargument="MoveDown" imageurl="~/images/dn.gif" />
</itemtemplate>
</asp:templatecolumn>
</columns>
Code behind:
protected void gridFormFields_ItemDataBound(object sender, DataGridItemEventArgs e)
{
(e.Item.FindControl("buttonMoveUpFormField") as ImageButton)
.Visible = gridFormFields.Items.Count > 1 && e.Item.ItemIndex > 0;
(e.Item.FindControl("buttonMoveDownFormField") as ImageButton)
.Visible = gridFormFields.Items.Count > 1 && e.Item.ItemIndex < gridFormFields.Items.Count - 1;
}
In the code behind, the Control returned by FindControl is null. Why?
How can I access the buttonMoveUpFormField and buttonMoveDownFormField controls?
From the code behind, is it possible to access controls which are declared in the ItemTemplate section of the TemplateColumn section of a DataGrid?
Because you need to add code to include "Item" and "AlternatingItem" and exclude all other types, before you try to find that control.
if (e.Item.Type == ...
You can certainly access the controls that are within the ItemTemplate section. I'm dealing with a similar issue. One thing that I've found is, depending what is calling your "gridFormFields_ItemDataBound", you may not have access to those controls yet.
I know that in my instance, I've got an "ItemTemplate" and an "EditItemTemplate", when I click edit, it fires an event "RowEditing" before it is actually switched to "Edit Mode", so the control will not be there yet. I do though have access to the controls in "RowUpdating" which is fired when I click save in the edit mode.
Maybe this helps? For example, your "OnDataBound" might be the event that is trying to access your controls, but you may not have access to them on databound?
Just a thought. I'll edit this if I get any further on mine.
I have a basic GridView that displays a list of tasks to do (just an example)
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowSorting="True" >
<Columns>
<asp:BoundField DataField="todo" HeaderText="To Do" ReadOnly="True" SortExpression="todo" />
<asp:BoundField DataField="byDate" HeaderText="By When" ReadOnly="True"
SortExpression="byDate" />
the data source is specified within the aspx page and it is a result set from a stored procedure
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="..."
SelectCommand="pToDoList" SelectCommandType="StoredProcedure">
</asp:SqlDataSource>
So the rendered page presents tasks as rows of data (a row per task)
My question is
When there is not data returned by stored procedure the page remains blank. I would like to have a text instead saying for example: "nothing to do today"
How to do that? Thank you
Use the EmptyDataTemplate:
<asp:gridview id="CustomersGridView"
datasourceid="CustomersSqlDataSource"
autogeneratecolumns="true"
runat="server">
<emptydatarowstyle backcolor="LightBlue"
forecolor="Red"/>
<emptydatatemplate>
<asp:image id="NoDataImage"
imageurl="~/images/Image.jpg"
alternatetext="No Image"
runat="server"/>
No Data Found.
</emptydatatemplate>
</asp:gridview>
Example from http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.emptydatatemplate.aspx
there is a property "EmptyDataText" that allows you to specify text if the gridview is empty
Add a Label to the page, call it ErrorLabel, then do something like this in the DataBound event of the GridView:
protected void GridView1_DataBound(object sender, EventArgs e)
{
if(GridView1.Rows.Count <= 0) ErrorLabel.Text = "Nothing to do today";
else ErrorLabel.Visible = false;
}
Although a Google search would have probably gotten that for you.
One option is to use the Footer to display this message. During the ItemDataBound, if the ItemType is the footer, check if the DataSource is empty and if it is, display the message.
Or if you want to work declaritvely in the ASPX you can use the EmptyDataTemplate and add your message there.
I would simply would add a label control noDataLabel containing the text "Nothing to do today", and add some code in the Page_Load event:
if (GridView1.Rows == 0)
{
GridView1.Visible = false;
}
else
{
noDataLabel.Visible = false;
}
It is a bit crude, but it beats have embedded C# inside your webform HTML. If there is no data, and the form is rendered, the GridView is simply ignored.