I'm using ASP.Net for web development. I've situation here. say I've many HTML/ASP.Net controls on my page, and I've to set visibility of each control based on Logged-in user's role. for this I'm doing as follows:
Storing each Function-Name and Role combination is DB
During render, checking for role permission for each HTML/ASP.Net control.
e.g: Displaying something like this:
<asp:Label runat="server" id="Lbl1" visible='<%=CheckVisibility("Display","Admin")%>'>
public bool CheckVisibility(string FunctionName, string RoleName){
// checks for db entry and returns bool value
}
Problem is, I've to do this for all the Controls. Is there any other optimized approach available to do this? please help me
Given only your description of what you're trying to solve, I would suggest you create your own controls which inherit from the built-in ones and add some properties to them. Then the controls can do the visibility check themselves. Something like
namespace StackOverflowTest
{
public class Label : System.Web.UI.WebControls.Label
{
public string DisplayRoles { get; set; }
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
Visible = PermissionHelper.CheckPermission("Display", DisplayRoles.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
}
}
public static class PermissionHelper
{
public static bool CheckPermission(string function, string[] allowedRoles)
{
// TODO: hit some sort of cache, so you don't make a bajillion queries to the DB
return true;
}
}
}
And then if you put this in your web.config (sorry, can't figure out how to do proper XML formatting here): <system.web>
<pages>
<controls>
<add tagPrefix="sot" assembly="StackOverflowTest" namespace="StackOverflowTest"/>
</controls>
</pages>
</system.web>
You can add this to your markup:
<sot:Label ID="AdminLabel" runat="server" Text="Bind this in OnLoad/!IsPostback or something" DisplayRoles="Admin,Management" />
This is just one of the many ways you can do this. It all depends on the requirements, of course. But I'm pretty sure you'll need your own classes for controls to have the possibility of making it manageable.
C# code:
public enum previlageType
{
superAdminPrevilages=1,
partnerPrevilages = 2,
dealerPrevilages = 3,
customerPrevilages=4
}
if ((previlageType)Enum.Parse(typeof(previlageType), Session["previlageType"].ToString())== previlageType.partnerPrevilages)
{
accordion.Visible = false;
}
ASP code:
<div id="accordion" runat="server">
Hello World, I'l be Hidden if a person with partner previlages is logged in. BUt will be visible if superadmin or any person except Partner logs in.
</div>
Hope it helps
If you're using a master page, you could get all the child page controls on load (get contentplaceholders, then get contentplaceholder controls).
Then when you have all the control names, do a lookup on your table and set its visibility to false if needed.
(below is vb but the translation should be easy.)
For Each cp As String In Me.ContentPlaceHolders
For Each ctl As Control In Me.FindControl(cp).Controls
If adminonly.Contains(ctl.ID) Then
ctl.Visible = False
End If
Next
Next
Related
I have a webusercontrol with a public int property SelectedCatID. I use this control on other pages and in other controls as follows:
<NewStore:LeftMenuLinks runat="server" SelectedCatID="<%#CatIDToSelect%>" />
How do I output cache this control based on SelectedCatID? Everything I've tried fails.
The closest I've gotten is getting it to cache, but it doesn't vary on SelectedCatID leaving the same menu item selected until the cache expires. Without caching, the control works as expected.
I figured out why the VaryByControls approach you used initially does not work. Sadly you edited it out of your question, so my research for this will just have to go into a blog post. Update: the blog post in question: http://tabeokatech.blogspot.be/2014/09/outputcache-on-user-controls.html .
The long and short of it though is that VaryByControls is kinda shorthand for VaryByParams, and does nothing for properties: it only looks at POST values. The fact that it ever worked for properties with a static value appears to be a bug - any string whatsoever in the VaryByControls would have made that part work. The accepted answer to this question is wrong: Vary by control properties using PartialCaching in ASP.NET .
There is no built-in way to vary by control property values.
That wouldn't make sense anyway, because user controls need to be created to have property values, and you want to avoid creating them, instead caching their rendered markup - cached user controls fields are null in code-behind if cached markup is served for them.
This works by injecting a PartialCachingControl into the page instead of the actual user control. This PartialCachingControl checks the cache, and only creates the control if no cached version exists.
As for making it work, I see two options:
If you only have 1 usercontrol per page, you could use the VaryByCustom approach. To make things easy you could write an interface that returns your property value for that page, and implement it on every page that hosts the user control, e.g.:
interface INumberProvider
{
int GetNumber();
}
// and the page:
public partial class _Default : Page, INumberProvider
{
public int GetNumber()
{
return this.SomeNumberPropertyOrWhatever;
}
...
In your Global.asax you cast the current handler to INumberProvider and get the number:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if (custom == "INumberProvider")
{
var page = context.CurrentHandler as INumberProvider;
if (page != null)
{
return page.GetNumber().ToString();
}
}
return base.GetVaryByCustomString(context, custom);
}
And in your control you obviously add:
OutputCache Duration="180" VaryByCustom="INumberProvider" VaryByParam="None" Shared="true"
That's if you only have one user control per page, and should be pretty straightforward. If you need more than one user control per page you're out of luck:
Build your own wrapper around your user control by writing a custom WebControl. Add the properties you need, capture the output of the rendered user control, and insert it into HttpContext.Current.Cache with a key that includes the SelectedCatID. Basically write your own custom PartialCachingControl.
There's also option 3:
Decide caching is not that important after all
<%# OutputCache Duration="60" VaryByParam="SelectedCatID" %>
Now store youre <%#CatIDToSelect%> as an a parameter ex ?SelectedCatID=12
Now you're Page or UserControl depending on what you want to cache will output the cache depending on what the Request.Param["SelectedCatID"] is equal to.
You can also do something like this (although not the easiest way)
This goes on the page/usercontrol you want cached:
<%# OutputCache duration="120" varybyparam="None" varybycustom="SelectedCatID" %>
This goes into the Gloabal.asax file:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if(custom == "SelectedCatID")
{
return CatIDToSelect;
}
return String.Empty;
}
I'm late to the party here what with an accepted answer and a 500 point bounty awarded. Still wanted to give my few cents on how this could be achieved.
It can be made to work in the control itself. You can have the control store it's own output in the cache and use the cached version in the Render method if found. I have made a really simple UserControl to test with. The markup looks like this:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="TestUC.ascx.cs"
Inherits="Webforms_Test.UserControls.TestUC" %>
<div>
<asp:Label ID="curTime" runat="server"></asp:Label>
</div>
It just contains a label that is set to DateTime.Now when it is initialized. The code behind looks like this:
public partial class TestUC : System.Web.UI.UserControl
{
private string cachedOutput = null;
public bool RenderFromCache = true; // set to false in containing page if this control needs to be re-rendered
protected void Page_Load(object sender, EventArgs e)
{
cachedOutput = HttpContext.Current.Cache["key"] as string;
if (cachedOutput == null)
{
// not found in cache, do the heavy lifting here to setup the control
curTime.Text = "UC:" + DateTime.Now.ToString("yy-MM-dd hh:mm:ss");
}
}
protected void Page_PreRender(object sender, EventArgs e)
{
if (cachedOutput == null || !RenderFromCache)
{
RenderFromCache = false;
StringBuilder b = new StringBuilder();
HtmlTextWriter h = new HtmlTextWriter(new StringWriter(b));
this.RenderControl(h);
cachedOutput = b.ToString();
HttpContext.Current.Cache.Insert("key", cachedOutput, null, DateTime.UtcNow.AddSeconds(10), TimeSpan.Zero);
RenderFromCache = true;
}
}
protected override void Render(HtmlTextWriter writer)
{
if (!RenderFromCache)
base.Render(writer);
else
writer.Write(cachedOutput);
}
}
In this sample, the control itself checks if its output is found in the cache, and if so the Render method will just write the cached output. If it is not found in the cache, the PreRender method will run the Render method normally and capture the output and store it in the cache.
In your case you would of course need a bit more logic which would check the relevant property on the control and use that to check if a cached version exists.
Disclaimer: This is an extremely simple test control. I have not tried to figure out how to make all of this work with controls that contain event handlers etc. So take it for what it's worth...
Let's say I have an ASCX user control that requires access to the current user's full name. An ASPX page contains this line at the top
<%# Register src="top.ascx" tagprefix="custom" tagname="top" %>
and this line in the body:
<custom:top runat="server" />
The ASPX file knows the user ID of the current user and could determine his full name. So how can I use the code run by the ASPX file to provide its information to the ASCX file?
Declare a property on the UserControl and have the parent page set it.
On your usercontrol:
public string FullName { get; set; }
On the aspx page either set it in the code behind
YourUserControl.FullName = FullName
or through markup
<custom:top runat="server" FullName="<%= SomeProperty %>" />
You could use the Page property of the user control and cast it to the instance of your page. Then, call the method of your page class to get the user name.
To make this work in a dynamically compiled project, you have to do a little more work to have the control recognize the data type of the dynamically compiled page. Here is a short tutorial on how to do.
Or, as Brandon outlines, do the opposite and let your page tell your user control the information.
This sounds like you might be mistaken about how the page lifecycle works and how you can expose data across your controls. For example, lets say you have this code in your ASPX:
public override void OnLoad(EventArgs e)
{
string userName = "Bob";
}
In your ASPX file, you can reference the control and set a property on it to pass the data along:
<custom:top ID="someControl" runat="server" />
You expose a property in your top control like so:
public string UserName { get; set; }
You could then add this code to your OnLoad method:
someControl.UserName = userName;
Then your control will have access to that data. Alternatively, you can stick things in the Request cache if you dont have a direct line to the control:
HttpContext.Current.Items["key"] = userName;
And then pull the data from your control via the same fashion:
string fromCache = HttpContext.Current.Items["key"];
You could go about this in several ways. I typically use a session variable, since the user will be bound to the session.
In the ASPX (or when the user logs in):
Session["UserFullName"] = GetFullName(); //Code to get full name here
In the ASMX:
this.FullName = Session["UserFullName"]; //TODO: Check for null values
i have 2 aspx files . I need to access a public function in b.aspx from a.aspx. How can i do that in asp.net using C#
My function from a.aspx is the following:
<script language="C#" runat="server">
public String user()
{
return l1.Text;
}
</script>
Ideally, don't. Don't put common logic in aspx files - put it in other classes which both pages can access. Code in a page should only be about displaying that page.
Don't forget that when you're displaying b.aspx, there is no instance of page a, logically. You could create a new one, but if you're trying to get the value of a label which was displayed previously to a user, or something like that, this could go badly wrong.
#Sir Jon says,Create a new Class for Properites
public class UserEntity()
{
public UserEntity(string user)
{
User = user;
}
public UserEntity()
{
}
public string User { get;set;}
}
then use and pass it on your pages:
var ent = new UserEntity();
ent.User = li.Text
Regards
While that's not an everyday task, it's still possible.
You could use cross-page posting, and then access the properties of the first page.
The MSDN article Cross-Page Posting in ASP.NET Web Pages describes it.
I have an app full of pages and user controls, many of which have one or more label controls on them for displaying various different messages to the user.
Example: the AddCompany.ascx user control, normally used on the Company.aspx page (with App.Master MasterPage) has a label on it called "OutOfCreditLabel" with Text="Error: You cannot create a new company, as you are out of credit". The code checks the credit and shows the label if needed.
I want to get rid of all these labels all over the place and just have a method I can call from anywhere like
ShowUserMessage("Text goes here");
In previous projects I've implemented this as a single label on the master page and public method in the .master.cs - as long as the page has the line
<%# MasterType VirtualPath="~/App.master" %>
in it, this works - but I can't get it to work on user controls (.ascx.cs). Is there a trick to this?
Or... Is there a better way?
What would you recommend for a "global" user message method that works from anywhere in the site?
Any nice jQuery solutions, perhaps?
Update
RPM1984 has asked for further clarification, so I'm trying to ask this a different way:
I need a method I can call from the code-behind (of a page or a user control) which will then display whatever text I specify to the user, like how stackoverflow tells you about new answers to your question when you next visit the site. It can be up the top of the window (like SO) or somewhere on the page, doesn't matter. What matters is that it's a "global" approach, rather than having various javascript alerts and asp:label's littered over every other page and user control in the project.
Something like this scenario:
A user clicks the "Create Widget" button on my "widget manager" user control on my page. In the event handler is:
if (User.IsOutOfCredit)
{
ShowUserMessage("Sorry, you cannot create widgets; you are out of credit.");
}
This results in the user seeing "Sorry, you cannot create widgets; you are out of credit." Either in a pop-up or red text in the page somewhere or at the top like StackOverflow, anything is fine
Does that make sense?
Why not a simple HTML "old-school" extension method? (i.e static method)
namespace Web.Helpers
{
public class HtmlHelpers
{
public static string Label(string target)
{
var dynamicText = SomeWhere.GetSomeCoolText();
return String.Format("<label for='{0}'>{1}</label>", target, dynamicText);
}
}
}
Then in your HTML:
<%= HtmlHelpers.Label("sometarget") =>
In your main master page, just import the namespace:
<%# Import Namespace="Web.Helpers" %>
EDIT after question updated
Ok, i see what you're trying to do now. I would recommend doing it all client-side.
That is, in your main master page, create an initially hidden <div> with a unique id:
<div id="message" style="display: none"></div>
Then create a helper method somewhere in your web project, rendering out some script.
public void DisplayMessage()
{
string message = SomeWhere.GetSomeCoolText();
StringBuilder script = new StringBuilder();
script.AppendFormat("$('message').show().append("<span>{0}</span>")", message);
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), script.ToString(), true);
}
Of course, this is just a guideline. You dont have to use jQuery, you don't have to hardcode the script in the method. You could create a JavaScript function that accepts a string and modifies the HTML of the div, then just call the function.
It all depends on how complicated your "message" is, if you need special server controls, internationalization, etc.
But this is certainly the easiest way to accomplish what you want (IMHO).
Personally, I'd prefer using the HttpContext.Current.Items dictionary with a custom control. Similar to Keith Bluestone's approach, but doesn't require an arbitrarily named control on the page; it makes it very clear what's going on. You could package it into one class as a server control easily enough, but here it is to drop into a standard web project.
To register a message in your code behind:
SiteMessageUtility.Add("Test message");
To display in your page, or master page, or wherever, really:
<%# Register TagPrefix="custom" TagName="SiteMessage" Src="~/Controls/SiteMessage.ascx" %>
<custom:SiteMessage runat="server" />
Here's the files you'll need:
~\App_Code\SiteMessageUtility.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
public static class SiteMessageUtility
{
public static void Add(string message)
{
string currMessage = HttpContext.Current.Items["message"] as string;
if (currMessage == null)
{
HttpContext.Current.Items["message"] = message;
}
else
{
HttpContext.Current.Items["message"] = currMessage + "<br/>" + message;
}
}
}
~\Controls\SiteMessage.aspx
<%# Control Language="C#" AutoEventWireup="true" CodeFile="SiteMessage.ascx.cs" Inherits="Controls_SiteMessage" %>
<asp:Literal runat="server" ID="message" />
~\Controls\SiteMessage.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class Controls_SiteMessage : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected override void OnPreRender(EventArgs e)
{
message.Text = (string)HttpContext.Current.Items["message"];
base.OnPreRender(e);
}
}
On the master page add the following controls:
the hfMsg hidden field will hold the message that will be displayed
and the hfCtrl will hold the name of the html control that will display this message which will be in this example lblMsg.
<label id="lblMsg" style="background-color:Yellow; border:solid 1px; width:200px;height:100px;display:none;"></label>
<asp:HiddenField ID="hfMsg" runat="server" />
<asp:HiddenField ID="hfCtrl" runat="server" />
NOTE:you can add another html control with a different id on an ASCX control and use it to display the message instead of the lblMsg.
and the following script:
<script language="javascript" type="text/javascript">
var msg = $('#<%= hfMsg.ClientID %>').attr("value");
var ctrl = $('#<%= hfCtrl.ClientID %>').attr("value");
if (msg != undefined && msg != "") {
$("#" + ctrl).html(msg);
$("#" + ctrl).show();
}
else {
$("#" + ctrl).hide();
}
</script>
NOTE:the script simply checks to see if the hfMsg control has a message to display or not.
and add the following two methods to the master page:
public void ShowMessage(string control, string message)
{
this.hfCtrl.Value = control;
this.hfMsg.Value = message;
}
public void ClearMessage()
{
this.hfMsg.Value = string.Empty;
}
finally you can call the ShowMessage method from any page like this to display a message on the master page:
Master.ShowMessage("lblMsg","hello world!");
and if you have a user control that holds an html label (e.g lblUserMsg) to display the message you can simply call ShowMessage and pass it the name of the label:
Master.ShowMessage("lblUserMsg","hello world!");
Having a SetStatus method in the MasterPage is always the way I've done this, to access the MasterPage from inside a user control, just create a private property in the usercontrol (or create a baseControl class that all user controls inherit from):
private TheNameSpaceOfMyMasterPage.MyMasterPage Master
{
get { return (TheNameSpaceOfMyMasterPage.MyMasterPage)Page.Master; }
}
protected void btnSave_OnClick(object sender, EventArgs e)
{
// Do your stuff...
// Set the Status
this.Master.ShowStatus("blah blah blah");
}
Also if you're using a control to hold the status message remember to disable ViewState on it, otherwise you'll end up with the same status message across postbacks which you don't want.
Some good answers, but...
To Robert W: the master page impl works, but it does require strong coupling (knowledge of) with the master page type. Master pages should generally affect style only, right? E.g. I should be able to change master pages without breaking my app.
SubPortal: yes, very clever, but... too clever for me. Also has master page issue.
RPM1984: again, too clever for me!
MGOwen didn't mention any special DHTML requirements (e.g. update from client side). So why not just implement a simple server-side helper method as he mentioned, find the target control which displays the message, and display it?
The following ShowMessage will find the target message control wherever it is on the page, as well as enable any page to override the default application's ShowMessage behavior if desired.
public static class ASPHelper {
// Defines something that shows a message
public interface IShowMessage
{
void ShowMessage(string msg);
}
// default implementation: finds a target message display control
// wherever it is on the page.
static void ShowMessage_Default(string msg)
{
const string SHOWMESSAGE_CONTROL_ID = "ctlShowMessage"; // or whatever
// find the control
Page currentPage = HttpContext.Current.CurrentHandler as Page;
Control ctlMessage = currentPage.FindControlRecursive(SHOWMESSAGE_CONTROL_ID);
if (ctlMessage == null)
throw new Exception("ShowMessage control not found!" );
Literal ctlMessageLiteral = ctlMessage as Literal;
if (ctlMessageLiteral == null)
throw new Exception("ShowMessage control must be a Literal!");
// Message control should not implement viewstate -- unneccesary
Debug.Assert(ctlMessageLiteral.EnableViewState == false);
// show it
ctlMessageLiteral.Text = msg;
ctlMessageLiteral.Visible = true;
}
// public version for use across app & in pages
static public void ShowMessage(string msg)
{
// Allow the current page to implement its own way of showing
// messages -- provides flexibility.
Page currentPage = HttpContext.Current.CurrentHandler as Page;
IShowMessage showMessageImpl = currentPage as IShowMessage;
if (showMessageImpl != null)
{
// Show using custom message displayer
showMessageImpl.ShowMessage(msg);
}
else
{
// static/global/default version
ShowMessage_Default(msg);
}
}
} // end ASPHelper
To use, simply place a literal control on the page, as in:
<div><asp:Literal
ID="ctlShowMessage" runat="server"
Visible="false"
EnableViewState="false"
/>
</div>
To use, simply call ShowMessage, as in ASPHelper.ShowMessage("insufficient credit"). Hope this is what you're looking for... Keith
Javascript safe popup. Works with Ajax/jQuery.
Namespace Utilities
''' <summary>
''' Utility class for injecting JavaScript into pages. Used primarily for throwing a JavaScript alert box, with correct focus.
''' </summary>
''' <remarks></remarks>
Public Class WriteJava
Region "Public Subs"
Public Shared Sub Script(ByVal script As String, ByRef p As Page, Optional ByVal scriptName As String = "")
If String.IsNullOrEmpty(scriptName) Then
scriptName = GetScriptName(p)
End If
If Not p.ClientScript.IsStartupScriptRegistered(scriptName) Then
ToolkitScriptManager.RegisterStartupScript(p, p.GetType, scriptName, script, True)
End If
End Sub
Public Overloads Shared Sub Alert(ByVal MyAlert As String, ByRef p As Page)
Script("alert('" & Format(MyAlert) & "');", p)
End Sub
Private Shared Function Format(ByVal value As String) As String
Return value.Replace("'", "\'").Replace(Chr(13), "\r").Replace(Chr(10), "\n")
End Function
Private Shared Function GetScriptName(ByVal p As Page) As String
Dim i As Integer = p.AppRelativeVirtualPath.LastIndexOf("/")
Dim pageName As String = p.AppRelativeVirtualPath.Substring(i + 1)
Return pageName
End Function
End Region
End Class
End Namespace
Use by calling:
Utilities.WriteJava.Alert("DANGER WILL ROBINSON", Me.Page)
I was looking for a site-wide way to display message to the user. I found jnotifica. It's similar to stackoverflow's bar at the top of the page.
The author's site appears to be down at the moment.
Raise an event in the user control, subscribe to the event from the page. The event handler updates your custom page property. Seems like the least amount of moving parts.
I would like to suggest to use a class for custom page(Inherited from System.Web.UI.Page) inside that add follwing as
protected void AlertError(string ErrorString)
{
StringBuilder scriptBuidler =
new StringBuilder(#"<script type='text/javascript' language='javascript'>");
scriptBuidler.Append(#"alert('");
scriptBuidler.Append(ErrorString);
scriptBuidler.Append(#"');");
scriptBuidler.Append(#"</script>");
AjaxControlToolkit.ToolkitScriptManager.RegisterClientScriptBlock
(this, typeof(Page),
"Patient Detail Not Found",
scriptBuidler.ToString(),
false
);
}
and inherit all your pages from this class instead of inherinting from system.web.ui.page
and use this function to to show your messages to your clients
So, I've been working on this project for a few days now, and have been unable to resolve the issue of getting intellisense support for my custom-defined inner properties for a user control (ascx, mind you).
I have seen the solution to this (using server controls, .cs mind you) many times. Spelled out in this article very well. Everything works for me while using ascx controls except intellisense.
Here's the outline of my code:
[PersistChildren(true)]
[ParseChildren(typeof(BreadCrumbItem))]
[ControlBuilder(typeof(BreadCrumbItem))]
public partial class styledcontrols_buttons_BreadCrumb : System.Web.UI.UserControl
{
...
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public List<BreadCrumbItem> BreadCrumbItems
{
get { return _breadCrumbItems; }
set { _breadCrumbItems = value; }
}
...
protected override void AddParsedSubObject(object obj)
{
base.AddParsedSubObject(obj);
if (obj is BreadCrumbItem)
BreadCrumbItems.Add(obj as BreadCrumbItem);
}
...
public class BreadCrumbItem : ControlBuilder
{
public string Text { get; set; }
public string NavigateURL { get; set; }
public override Type GetChildControlType(string tagName, System.Collections.IDictionary attribs)
{
if (String.Compare(tagName, "BreadCrumbItem", true) == 0)
{
return typeof(BreadCrumbItem);
}
return null;
}
}
}
Here's my mark up (which works fine, just no intellisense on the child object declarations):
<%# Register src="../styledcontrols/buttons/BreadCrumb.ascx" tagname="BreadCrumb" tagprefix="uc1" %>
...
<uc1:BreadCrumb ID="BreadCrumb1" runat="server" BreadCrumbTitleText="Current Page">
<BreadCrumbItem Text="Home Page" NavigateURL="~/test/breadcrumbtest.aspx?iwentsomewhere=1" />
<BreadCrumbItem Text="Secondary Page" NavigateURL="~/test/breadcrumbtest.aspx?iwentsomewhere=1" />
</uc1:BreadCrumb>
I think the issue lies with how the intellisense engine traverses supporting classes. All the working examples I see of this are not ascx, but Web Server Controls (cs, in a compiled assembly).
If anyone could shed some light on how to accomplish this with ascx controls, I'd appreciate it.
I have solved this before by removing all the user controls and directives from the page and then switching the markup to design view. You then drag the ascx file from the solution explorer to the design window. If you swich back to markup view suddenly intelisense picks up all the properties. I am sure there is a better way but i have never found one that works.