How to hide a control and prevent control from loading data - c#

I have a page that have the following code for a custom control:
<SiteControls:Announcements runat="server" id="UserAnnouncements" />
Let's also say I have a GridView control, just so I can cover multiple scenarios. I need to check if the user has permission to view this control by checking the Boolean:
PermissionsManagement.DoesUserHavePermission(userId, permissionId)
Which is defined as:
public static class PermissionsManagement
{
public static bool DoesUserHavePermission(int userAccountId, int permissionId)
{
// Code Goes Here
}
}
If the user doesn't have permission, DoesUserHavePermission will return false. I have the ASP.NET WebForms page laid out as if the user has full control (meaning I have all the controls on the page and want to remove them if they don't have permission vs adding every single control to the page).
I can set the control's visibility to false on Page_Load function if the user doesn't have permission, but that doesn't stop my control from loading or in the case of a GridView from loading its data. How do I stop a control (User control or standard control) from loading any data if the user doesn't have permission to use (view) the control? I have tried the following inline code which doesn't work:
<% if(PermissionsManagement.DoesUserHavePermission(1, 1))
{ %>
<SiteControls:Announcements runat="server" id="UserAnnouncements" />
<% } %>
But that doesn't work as the control Page_Load still fires for the control and I assume any other control will load data if it is data-bound or acts similar to my control.

Without knowing much of your code, it is a little difficult to figure out the exact answer. However, as much as I understood your question, here's my answer.
Loading data for Announcements or GridView should still be in your control. I would expose a method in Announcements control that actually loads data for it. For the GridView you should simply defer the binding of DataSource until the permission check is performed. Of course these things need to be done in addition to hiding (setting visibility) of these controls.
See the code below, not complete, but enough to express an idea:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Check permissions here
if (allowed)
{
// For custom/user control
UserAnnouncements.GetAnnouncements();
// For grid view
GridView1.DataSource = GetGridviewData(); // GetGridviewData would return DataSet or anything valid.
GridView1.DataBind();
}
else
{
// Hide the controls
}
}
}

Related

Manipulating parent page from User Control

I am working with the web application which I have only binaries. The application allows developing extension by providing internals to the derived classes.
What I would like to achieve is to add additional functionality to the existing aspx page. Because I can’t replicate and modify corresponding code I thought about developing a UserControl and modify markup of the discussed aspx page to include that control.
Until now I was successful. The control appears on the page and triggers server event handlers. It also has access to the application internal data. What I need now is to programmatically manipulate some of the original page elements from that UserControl server side.
I know that this is not the purpose of User Controls and they should not to have any knowledge about parrent page elements. However, this is as far as I know the only way to include some of the custom functionality to the existing page.
Before I asked this question I have spent a good amount of time for researching avaiable solutions.
Please, could you suggest the best possible way of referencing those elemnent from the User Control at server side?
Below is a simplified code representation of what I have done so far
The existing aspx page:
// SOME CONTENT OF THE ORGINAL PAGE
<%# Register TagPrefix="uc" TagName="MyControl" Src="~/usercontrols/MyControl.ascx" %>
// SOME CONTENT OF THE ORGINAL PAGE
<uc:MyControl ID="pnlMyControl" runat="server"></uc:MyControl>
// SOME CONTENT OF THE ORGINAL PAGE
My User Control:
public partial class MyControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
//DO SOMETHING HAVING ACCESS TO INTERNAL DATA
}
protected void lnkTest_Click(object sender, EventArgs e)
{
//DO SOMETHING HAVING ACCESS TO INTERNAL DATA
}
}
I've done something similar, though I've done it for variables rather than controls so I shall attempt to adapt it here.
I used properties to achieve this, working with:
<%# Register TagPrefix="uc" TagName="MyControl" Src="~/usercontrols/MyControl.ascx" %>
<uc:MyControl ID="pnlMyControl" runat="server" />
In the UserControl you do something like:
private string _myTextBox = new TextBox();
public string myTextBox
{
get
{
return _myTextBox;
}
set
{
_myTextBox = value;
}
}
Then in the parent page, you can set these properties; for example:
protected void Page_Load(object sender, EventArgs e)
{
pnlMyControl.myTextBox = MyParentTextBox;
}
Also, you may find this useful; you can directly fire methods on the parent from the user control using this:
this.Page.GetType().InvokeMember("MyMethodName", System.Reflection.BindingFlags.InvokeMethod, null, this.Page, new object[] { });
I hope that helps.

UpdatePanel.Update() command generates a full Page_load

I have a Update Panel inside a User Control i use on 2 pages in my website
Both pages use the same MasterPage, ScriptManger is declared in the MasterPage.
Both pages call the UC the same way:
<uc:SearchCube runat="server" ID="searchCube" />
in the Update panel i have many RadioButtons that on change generate a server side event that fill dropdown in the update panel and update the panel
protected void SearchCategoryChanged(object sender, EventArgs e)
{
FillDropdowns();
SearchOptions.Update();
}
Update Panel is set like this:
<asp:UpdatePanel ID="SearchOptions" runat="server" UpdateMode="Conditional"
hildrenAsTriggers="true"/>
Each RadioButton is set like this:
<asp:RadioButton ID="RadioButton1" GroupName="SearchCategory" runat="server"
AutoPostBack="true" OnCheckedChanged="SearchCategoryChanged" Text="Text"/>
I also have an AsyncPostBackTrigger on each Radio Button Controller
The problem i have is that on one page when i call the Update() function the panel is updated and Page_Load is triggered which causes the UC to refresh and reload the default settings of the UC
I can see in DEBUG mode that on the working page Update() does not generate Page_Load.
Can anyone explain to me why this is happening?
Everytime a request goes to the server, it executes the Page_Load event.
What you need to do is make sure you have a PostBack validation on all your pages:
protectec void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
//Not a postBack: Normal page load
//Init your page here
}
else
{
//It's a PostBack (from a command).
//Do nothing or init stuff your all your commands.
}
}
If you put some breakpoints in your Page Load and your SearchCategoryChanged method, you'll be able to see what the pipeline looks like.
Fixed my problem.
the problematic page is an index page that takes a few parameters in.
I have a Response.Redirect() on the page to avoid duplication of pages.
Apparently when the PostBack() is made it calls the page without any parameters and i was forcing it to be redirected into a default view since no parameters were sent to the page.
i found a lead to my problem in a Microsoft help forum that stated:
By calling Response.Write() directly you are bypassing the normal
rendering mechanism of ASP.NET controls. The bits you write are going
straight out to the client without further processing (well,
mostly...). This means that UpdatePanel can't encode the data in its
special format.
Anyway the page was reloading every time which caused it to reload the User Control with it's default values.

How can access property of .aspx in the user control?

I have an .aspx page in which I have a property. Now i create a user control and drop it on the page. Now how can i access that property in code behind of usercontrol.
The best way is to expose a public property in the UserControl and assign that property from the ASPX page:
By code:
var uc = this.myUserControl as MyCuserControlType;
uc.CustomUserControlProperty = this.MyPageProperty;
Declaratively
<uc:MyUserControlType1 runat="server= ID="myUserControl" CustomUserControlProperty="<%# this.MyPageProperty %>" />
Note: If you want to use declarative markup you would need to call this.DataBind(); in code to force the binding
Edit 1
In case you want to do the opposite (pass a value from the control to the page in response to an event) you could declare your own custom event in the user control and fire it when needed it.
Example:
User control code behind*
public event Action<string> MyCustomEvent = delegate{};
....
// somewhere in your code
this.MyCustomEvent("some vlaue to pass to the page");
Page markup
<uc:MyUserControl1 runat="server" onMyCustomEvent="handleCustomEvent" />
Page code behind
public void handleCustomEvent(string value)
{
// here on the page handle the value passed from the user control
this.myLabel.Text = value;
// which prints: "some vlaue to pass to the page"
}
If a user control needs to access something on the parent page, then maybe this user control should have included it as its own property which could be set from the parent. Ideally user controls should be independent from any parent context or other user controls on the page, otherwise they really are not something reusable. They need to be self contained and configurable throughout their the properties they are exposing.

Check is dirty for the gridview in asp.net?

I am developing a web application where I am using a GridView control to load data from the database.
I have a row that is loaded in editable mode. I have a save button which the user clicks after making the changes, and I want to check the IsDirty flag to stop the user from saving and notify them via an alert box. I'm using a Web User Control (ASCX) to load the GridView. How can I check dirty rows in the grid and stop the user from saving when user clicks the save button or logout button??
P.S. I am using a LoginView for the logout button.
You need to handle the OnRowUpdating event in your grid, for example:
<asp:GridView id="a" runat="server" OnRowUpdating="a_rowUpdating" ... />
In code behind:
protected void a_rowUpdating (object sender, GridViewUpdateEventArgs e)
{
//Add logic appropriately to know whether you should allow the update or not.
//If you shouldn't, just set e.Cancel=true as below:
e.Cancel=true;//will stop from updating.
}
You have access to the Old and New values in the GridViewUpdateEventArgs object. For more details and sample code, check here.
I use a simple JS method to check for a variety of changes in ASP.net pages. I added it to a JS filer called CheckDirty.js and added a link to it on the page, in the file is this code:
var checkDirty = true;
var form_clean;
//this should be called when the save button is clicked, but prior to the page post
function onSave() {
checkDirty = false;
}
// serialize clean form
$(function () {
form_clean = $("form").serialize();
});
window.onbeforeunload = function (e) {
if (checkDirty) {
var form_dirty = $("form").serialize();
if (form_clean != form_dirty) {
return 'Your changes will be lost';
}
}
};
This will also work for changes to a gridview and will alert the user. I find this method best because it works with everything and I don't need to keep writing different methods for different controls.

Remove statically added controls at runtime

The Scenario: I have an asp.net website where I show a div popup on page load for taking a few user details. When a user inputs the details, or closes the popup, I set up a flag cookie so that the popup is not displayed again for the user. The div is in the MasterPage so that it is displayed no matter on which page a user lands first time. The div contains an UpdatePanel which has all the controls required for taking the details. This whole functionality is working fine.
The Problem: Now this div popup is not showing(by setting display:none) on subsequent postbacks(which I want), but the html markup is still loading with the page unnecessarily adding to the page size. What I would idealy want to do is: Check if flag cookie is set. If no, show the popup, else remove the popup's markup from the page.
Now since the div is not a server control, I cannot possibly remove it and the all the controls inside it. So, I thought of removing the UpdatePanel from the page:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.Cookies["flag"] != null)
{
if (Page.Controls.Contains(updpnl_contact))
{
Page.Controls.Remove(updpnl_contact);
updpnl_contact.Dispose();
}
}
}
But I guess this tends to work with dynamically added controls only, and since the control is added at Design Time, it is not being removed.
Is there any way I can achieve this?
If you add a runat="server" attribute to your <div> element, it will be available in the code-behind. You'll need an id on it as well. Then you can just toggle the Visible property. If this property is false, the control won't be rendered to the client (i.e. no HTML markup).
What you're trying to do is not at all the usual workflow. I tend to think that it will not work as it would mess up control tree, maybe even corrupt the viewstate and so on.
As a possible solution, you can put it's visibility to hidden in the code behind. This, in the contrary to the usual 'gut feeling', doesn't work like the css propery 'display:none' for example - instead the control will not even be rendered into the page when it's not visible. This may be the workaround for you.
Happy coding.
A more efficient approach would be to create the panel as a UserControl and load it dynamically in codebehind when it's needed, then add it to your page. E.g, in code:
MyPopupControl popup = (MyPopupControl)Page.LoadControl("/path/to/usercontrol.ascx");
PopupPanel.Controls.Add(popup);
Where PopupPanel is an empty <asp:Panel>. Then, not even the markup will need to be loaded/processed except when its needed.
There is no reason that all the code you use to display and process this panel couldn't also be in the usercontrol, isolating it from the master page.
Can you build the panel dynamically, based on the cookie setting?

Categories