How to hide link button based on a result returned by a class ? - asp.net

I am bit new to C# and got a question.
I have a class as below that simply return false ( this is just to test)
public class SetAuthority
{
public SetAuthority()
{
//
// TODO: Add constructor logic here
//
}
public static Boolean AuthorizedToAddEdit()
{
return false;
}
}
I have a DetailsView with two link buttons to Edit and add New record. I want to hide the link buttons based on the above class method returning value.
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="False" visible='<%# SetAuthority.AuthorizedToAddEdit() %>'
CommandName="Edit" Text="Edit"></asp:LinkButton>
<asp:LinkButton ID="LinkButton2" runat="server" CausesValidation="False" visible='<%# SetAuthority.AuthorizedToAddEdit() %>'
CommandName="New" Text="New"></asp:LinkButton>
</ItemTemplate>
Above works file and Edit and New link buttons are hidden when I run the program.
But the question is, I have a separate link button outside of the DetailsView. It is just a link to navigate to another page. I want to hide this in similar way using the same logic. I have the below code in my webform.
<asp:LinkButton ID="LinkButton5" runat="server" CausesValidation="False" visible='<%# SetAuthority.AuthorizedToAddEdit() %>'
CommandName="OpenAdminPage" Text="Open Admin Page"></asp:LinkButton>
But the link button is always visible and seems it is not calling the class and not getting the value back. It appeared to be the class not return any value and can someone help me to identify what is the different between having this and working in DetailsView and not working for a simple link button.
Note: have a workaround where I can call the same method in Page Load event that works fine without any issue. Code is below
protected void Page_Load(object sender, EventArgs e)
{
Boolean myAllowAdd;
myAllowAdd = SetAuthority.AuthorizedToAddEdit();
if (myAllowAdd == false)
{
LinkButton1.Visible = false;
}
}

The reason is that this is for databinding expressions only: <%# Since the DetailsView is databound it works there.
If you would DataBind the page it worked also for the LinkButton outside of the DetailsView:
protected void Page_Load(object sender, EventArgs e)
{
Page.DataBind();
}
inline asp.net tags... sorting them all out (<%$, <%=, <%, <%#, etc.)
Side-note: be careful with static in ASP.NET. The static method does not yet hurt. But if you'd also use static fields you'd enter a minefield since it would be shared across all requests. Your current code-behind "work-around" is the better approach anyway.

Related

Repeater ItemCommand does not work on large data

I have a webform that shows a list of items using a repeater and there is a Edit button associated with each item.
By clicking the Edit button, the page is redirected to the Edit page
Html
<asp:Repeater ID="r epeaterRequest" runat="server">
<ItemTemplate>
<asp:LinkButton ID="btnEdit" CommandArgument='<%# Eval("ItemID") %>' CommandName="Edit" runat="server">Edit</asp:LinkButton>
</ItemTemplate>
</asp:Repeater>
Code Befind
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (Page.IsPostBack == false)
{
List<MyItem> data = new repository().getData();
repeater.DataSource = data;
repeater.DataBind();
}
}
private void repeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
int itemId;
if (int.TryParse(e.CommandArgument.ToString(), out itemId))
{
if (e.CommandName == "Edit")
{
Response.Redirect("~/Edit.aspx?id=" + itemId, false);
}
}
}
The problem is that when the number of list items gets larger like 2800 items in the List, it halts after clicking the Edit button. The ItemCommand does not get called or takes too long to get to the ItemCommand function.
(Loading and rendering the data is quick. It halts when the Edit button is clicked.
Everything is okay when there are less items like 1000.
I've tried adding this <httpRuntime maxRequestLength="102400" executionTimeout="300" /> to Web.Config but did not work.
Have you tried to add some simple paging to your repeater. That is a lot of data to load into the DOM at once. See this for an idea.
Why don't you change your LinkButton to simple hyperlink?
<asp:Repeater ID="r epeaterRequest" runat="server">
<ItemTemplate>
<a href='<%# Eval("href") %>'>Edit</a>
</ItemTemplate>
</asp:Repeater>
I think it is better solution in your case. Caz' you are doing the same, but using another way.

Get values from repeater that is filled with objects from a custom class

I have stuck on how to get values from a specific row in a repeater.
I fill the repeater with objects from a coustom class like this(C#):
rptVisaBarn.DataSource = client.SkickaForalderBarn();
rptVisaBarn.DataBind();
(ASP.NET)
<asp:Label ID="lblFornamn" runat="server" Text='<%#DataBinder.Eval(Container.DataItem, "NamnBarn").ToString() %>'></asp:Label>
<asp:Label ID="lvlPersonNr" runat="server" Text='<%#DataBinder.Eval(Container.DataItem, "PersonNrBarn").ToString() %>'></asp:Label>
The thing i want to is when i click on the button that creates on every row i want to colect values from that object on that row and send them to a method that i have in a webbserivce.
I have tried some things but they dont work and i dont know where i should go from here..
A little help in the right direction would be really nice!
I you need more info just ask, becuse i really need help with this..
Do you want that click to be client or server side? There's a decent writeup here: http://www.developer.com/net/asp/article.php/3609466/ASPNET-Tip-Responding-to-the-Repeater-Controls-ItemCommand-Event.htm.
The highlights:
Register (somewhere) your repeater item command event. e.g.:
override protected void OnInit(EventArgs e)
{
base.OnInit(e);
rptData.ItemCommand += new RepeaterCommandEventHandler(rptData_ItemCommand);
}
Create a button in your repeater:
<asp:LinkButton ID="btnEdit" Runat="server" CssClass="tabletext" CommandName="edit"
CommandArgument='<%# Eval("pkRecordID") %>'>Edit</asp:LinkButton>
Handle the event:
private void rptData_ItemCommand(object source, RepeaterCommandEventArgs e)
{
//e.Item contains your data item.
//e.CommandName contains 'edit' in the case, or whatever is in your button's CommandName
//e.CommandArgument contains a record ID in this case, or whatever is in your button's CommandArgument
}

ListView + ObjectDataSource SelectMethod called twice when EnableViewState="false"

Note: This question has been completely modified now that I have a simpler example.
I have set up a sample page which only has a ListView and ObjectDataSource. The first time the page comes up (!IsPostBack), my GetList method is called once. After paging (IsPostBack), the GetList method is called twice--the first time with the old paging values and the second time with the new values.
If I set EnableViewState="true" on the ListView, then the GetList method is only called once. It seems to me that the ListView wants an "initial state", which it either gets from ViewState or by re-running the method.
Is there any way to disable ViewState on the ListView and also prevent SelectMethod from being called twice?
ASPX page:
<asp:ListView ID="TestListView" runat="server" DataSourceID="ODS" EnableViewState="false">
<LayoutTemplate>
<asp:PlaceHolder ID="itemPlaceHolder" runat="server" />
<asp:DataPager ID="TestPager" runat="server" PageSize="10">
<Fields>
<asp:NumericPagerField />
</Fields>
</asp:DataPager>
</LayoutTemplate>
<ItemTemplate>
<div><%# Eval("Title") %></div>
</ItemTemplate>
</asp:ListView>
<asp:ObjectDataSource ID="ODS" runat="server" SelectMethod="GetList" SelectCountMethod="GetListCount"
TypeName="Website.Test" EnablePaging="true" />
ASPX code-behind:
namespace Website
{
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
public IList<DataItem> GetList(int maximumRows, int startRowIndex)
{
return GetListEnumerable().Skip(startRowIndex).Take(maximumRows).ToList();
}
public IEnumerable<DataItem> GetListEnumerable()
{
for (int i = 0; i < 100; i++)
{
yield return new DataItem { Title = i.ToString() };
}
}
public int GetListCount()
{
return 100;
}
}
public class DataItem
{
public string Title { get; set; }
}
}
Either turn ODS caching on.
<asp:ObjectDataSource ID="ODS" ... EnableCaching="true" />
This way the GetList will be called only when new data is needed. Post backs to pages that already had data retrieved will use the cached version and not call the GetList.
Or move your DataPager out of the ListView and set the PagedControlID property.
Actually you should be using the OnSelecting event.
What happens is that ObjectDataSource calls the method SelectMethod twice
First time it gets the data.
Next time it gets the count.
So I think you have to implement the OnSelecting event
<asp:ObjectDataSource ID="ODS" runat="server" SelectMethod="GetList" SelectCountMethod="GetListCount"
OnSelecting="ods_Selecting">
TypeName="Website.Test" EnablePaging="true" />
and then cancel the event when the ObjectDataSource tries to call the count method.
protected void ods_Selecting(object sender,
ObjectDataSourceSelectingEventArgs e)
{
if (e.ExecutingSelectCount)
{
//Cancel the event
return;
}
}
You can look for full implementation as mentioned in the link below
http://www.unboxedsolutions.com/sean/archive/2005/12/28/818.aspx
Hope this helps.
I had a similar problem where it worked different depending on browser. IE one way and all other browsers one way.. Might not be the same issue as you have.
I solved it this way:
protected void DropDownDataBound(object sender, EventArgs e)
{
// Issue with IE - Disable ViewState for IE browsers otherwhise the dropdown will render empty.
DropDownList DDL = (DropDownList)sender;
if (Request.Browser.Browser.Equals("IE", StringComparison.CurrentCultureIgnoreCase))
DDL.ViewStateMode = System.Web.UI.ViewStateMode.Disabled;
else
DDL.ViewStateMode = System.Web.UI.ViewStateMode.Inherit;
}

Set Custom ASP.NET UserControl variables when its in a Repeater

<%# Register Src="~/Controls/PressFileDownload.ascx" TagName="pfd" TagPrefix="uc1" %>
<asp:Repeater id="Repeater1" runat="Server" OnItemDataBound="RPTLayer_OnItemDataBound">
<ItemTemplate>
<asp:Label ID="LBLHeader" Runat="server" Visible="false"></asp:Label>
<asp:Image ID="IMGThumb" Runat="server" Visible="false"></asp:Image>
<asp:Label ID="LBLBody" Runat="server" class="layerBody"></asp:Label>
<uc1:pfd ID="pfd1" runat="server" ShowContainerName="false" ParentContentTypeId="55" />
<asp:Literal ID="litLayerLinks" runat="server"></asp:Literal>
</ItemTemplate>
</asp:Repeater>
System.Web.UI.WebControls.Label lbl;
System.Web.UI.WebControls.Literal lit;
System.Web.UI.WebControls.Image img;
System.Web.UI.WebControls.HyperLink hl;
System.Web.UI.UserControl uc;
I need to set the ParentItemID variable for the uc1:pdf listed inside the repeater.
I thought I should be able to find uc by looking in the e.Item and then setting it somehow. I think this is the part where I'm missing something.
uc = (UserControl)e.Item.FindControl("pfd1");
if (uc != null) { uc.Attributes["ParentItemID"] = i.ItemID.ToString(); }
Any thoughts would be appreciated.
Also tried this with similar results... when I debug inside my usercontrol (pfd1) the parameters I am trying to set have not been set.
uc = (UserControl)e.Item.FindControl("pfd1");
if (uc != null)
{
uc.Attributes.Add("ContainerID", _cid.ToString());
uc.Attributes.Add("ParentItemId", i.ItemID.ToString());
}
UPDATE: It looks like my controls are not connected by a namespace. I've wrapped by the parent control (Layer) and the PressFileDownlad control in a namespace "MyControls". Also updated their Inherits reference on the aspx to read "MyControls.xxxxx". I'm able to type "MyControls.Layer" inside the code on layer.aspx.cs but I'm not able to get "MyControls.PressFileDownload"
If you implement ParentItemID as a public property in your user control, then you should be able to set it declaratively, e.g:
<asp:Repeater id="Repeater1" ...>
<ItemTemplate>
<uc1:pfd ID="pfd1" runat="server" ParentItemId='<%# Eval("ItemID") %>' ... />
Martin is right you should be able to set it in declarative way (in case your property is public) .
But your way should also work (just cast it properly)
((PressFileDownload)e.Item.FindControl("pfd1")).ParentItemId = 0;
The best way is to implement the OnDataBinding event for the user control. I try to stay away from putting code inline in the aspx using webforms if possible.
When the repeater gets bound, for each item that is bound, the OnDataBinding will fire for your user control and your handler can do what it needs. You don't have to go searching for the controls.
Here is an example:
// in your aspx
<uc1:pfd ID="pfd1" runat="server" ShowContainerName="false" ParentContentTypeId="55"
OnDataBinding="pfd1_DataBinding" />
// in your codebehind implement the OnDataBinding event
protected void pfd1_DataBinding(object sender, System.EventArgs e)
{
pfd uc = (pfd)(sender);
uc.ContainerID = _containerID.ToString();
uc.ParentItemID = Eval("ItemID");
// Here you can do more like access other items like hidden fields
// or cached objects or even other controls etc... Skys the limit.
}
EDIT: Notice from your comment you require more data than what is found in the datasource. In this case what I usually do is just make private member variables in the .cs that I store data in. So when you have the container ID just store it in a variable that will be accessible.
Eg in your .cs for your page:
public partial class _TestPage : System.Web.UI.Page
{
private int _containerID { get; set; }
Then when you load the data just set the _containerID property and it will be accessible in the OnDataBinding event. Just make sure you are binding after you have set the _containerID.

ASP.NET linkbutton visible property issue

I'm using a public variable called IsAdmin in the code behind of an aspx page.
public partial class _news : System.Web.UI.Page
{
public bool IsAdmin = false;
protected void Page_Load(object sender, EventArgs e)
{
if (User.Identity.Name.Contains("admin"))
{
IsAdmin = true;
}
else
{
IsAdmin = false;
}
}
And i use the property Visible='<%#IsAdmin%>' to assign to panels which i want to show if the user is an admin in the aspx design of the page. Strangely it works for the linkbuttons i've put on the repeater.
<asp:Panel ID="Panel1" runat="server" Visible='<%#IsAdmin%>'>
<asp:LinkButton ID="LinkButton2" runat="server" PostBackUrl='<%# "news_edit.aspx? Action=edit&id=" + Convert.ToString( Eval("news_id")) %>Edit</asp:LinkButton>
<asp:LinkButton ID="LinkButton3" runat="server" PostBackUrl='<%# "news.aspx?Action=delete&id=" + Convert.ToString( Eval("news_id")) %>'>Delete</asp:LinkButton>
</asp:Panel>
and it works fine, however outside the repeater i've put another linkbutton without a panel
<asp:LinkButton ID="LinkButton4" runat="server" PostBackUrl="~/news_edit.aspx?action=new" Visible='<%#IsAdmin%>'>Add New Item</asp:LinkButton>
but the visible property doesn't work on it! I tried putting it inside a panel too and setting it's visible property but that too didn't work.
So i have following doubts
1)what is the issue?
2)what is the technical name when we use references like '<%#IsAdmin%>' in the design page
3)Does page load happen before page is rendered of after page is rendered?
Thanks
<%# %> is the syntax used for accessing databound fields. Since you are likely databinding the Repeater control at some point, these expressions will be evaluated.
Since you are likely not calling databind on the Panel and the Linkbuttons outside of the Repeater, these expressions will not be processed. You can probably change them to something like
<%= IsAdmin.ToString() %>
and get the result you want.
Check this great blog entry for more information on the differences.
Also, Page Load happens before the page is rendered. Rendering the page is the last thing that happens in the ASP.Net page lifecycle.

Resources