loads of useful information, examples and tutorials pertaining to web development utilizing asp.net, c#, vb, css, xhtml, javascript, sql, xml, ajax and everything else...

 






Cascading DropDowns with SQL

by naspinski 6/28/2008 2:16:00 AM

an improved cascade class that includes methods using both xml and sql

I posted an entry of how to make cascading ddls with xml in the past, now I extended the class to include sql.  In this case, one of the few times I may say so I decided not to use LINQ as in this case it actually seemed to make more work.  The idea is basically the samejust usingan SQL database.  This is what the info in my DB looks like:

 

dropDowns

idcategoryitem
1 ford mustang
2 ford f-150
3 ford focus
4 chevy impala
5 chevy corvette
6 chevy blazer

 

Now I just have to make my ddls, notice the second one is empty:

 

<asp:DropDownList ID="ddlMake" runat="server" AutoPostBack="true"   onselectedindexchanged="ddlMake_SelectedIndexChanged"
    cascadeTo="ddlModel"  cascadeBlank="- select make -" >
    <asp:ListItem>- select make -</asp:ListItem>
    <asp:ListItem>ford</asp:ListItem>
    <asp:ListItem>chevy</asp:ListItem>
</asp:DropDownList>
<asp:DropDownList ID="ddlModel" Enabled="false" runat="server">
    <asp:ListItem>- select make -</asp:ListItem>
</asp:DropDownList>

 

Also notice that the attributes cascadeTo and cascadeBlank are set.   cascadeTo is the ddl you are going to cascade to, and cascadeBlank is what the empty value of the  cascaded-to ddl will be if the original is returned to index 0 (that is much easier to demonstrate than explain).

 

Now just call it in the code-behind (don't forget to put the class in your App_Code folder):

 

protected void ddlMake_SelectedIndexChanged(object sender, EventArgs e)
{
    DropDownList dll = (DropDownList)sender;
    string connString = ConfigurationManager.ConnectionStrings[ "mytestDB" ].ConnectionString;
    cascade2.fromThisDropDownSql(this.Page, (DropDownList)sender, connString, "item", "category", "dropDowns" );
}

 

This takes more inputs than the xml one, but is quite simple if you compare it to the database above.  The first two variables will always be the same, and the next 4 are simply the connection string, the table column you wish to populate the cascaded ddl with, the table column that you are filtering with, and the table name.  Doesn't really matter how your tables are layed out or where everything is located, you just change your inputs accordingly.  Really that is all that it takes.

 

 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

asp.net | c# | steal some code

Simple Gantt Chart with Asp.net

by naspinski 6/27/2008 3:33:00 AM

It's very easy to make a Gantt Chart in Asp.Net, just takes a little math

Recently I was asked how to make a Gantt chart in Asp.Net.  Now I am too cheap to actually go and buy some software to do this for me, so I decided to figure it out on my own; can't be that hard right?  I will just use some strategically crafted div's to look like legitimate graphs.  Turns out it really wasn't that tough... wasn't even a lot of code!

 

First thing I did was make some sample data.  Whenever I have used a Gantt Chart in the past, it has been used to plot projects over time.  So my basic elements were:

  • Title
  • Start Date 
  • End Date

 

Now you can have endless extra crap on there, but that is the basics.  Also, instead of dates, you could easily substitute numbers, but I am going to go with dates.  I just produced a DataTable with those as my 3 DataColumns and some dummy data:

 

titlestartend
Super Important Project 6/8/2008 7/3/2008
A Project 6/3/2008 6/30/2008
Crappy Project 6/25/2008 7/3/2008
Party Project 6/13/2008 6/23/2008
Being stupid 6/28/2008 7/8/2008
Getting Hammered 6/18/2008 7/1/2008
Recovering 7/2/2008 7/5/2008

 

Now that we have the data, it is just down to the math of how we are going to get this to work.  First of all, let me explain my approach to CSS graphing: using divs and the css 'width' property can easily make you a horizontal bar graph, just stack a couple divs on top of eachother that are different widths, different backgrounds and there you go, you have some nifty graphs.  The only challenge here is that we can't just use a simple percentage.  The left side of the graph isn't necessarily on the far left side, and with width is going to be relative to where it starts... hmmm.

 

I actually drew this out on some scratch paper on my desk to make it easier to see, using a nice even number: 10.


Now with this information, we can figure out how to render each div (graph line).  Since I am working with DateTime variables, I can easily convert this into TimeSpans and then Days which is an int... then it's easy math.  Notice I added in the *100 up above, that is so I am working with full percentages instead of decimals, like css uses.  Here is the code I cam up with for defining where to start a div and how wide for it to be.  Here is my function that takes in title String, start DateTime and end DataTime  and returns a nicely formatted div.  I am also using the global variables dtMin, and dtMax which are DateTime variables that are the maximum and minimum dates in the data (I use LINQ to find that easily, you can see in the code).  dateSpan is another global variable, an int that is simply (dtMax - dtMin).Days.

 

public string doGantt(object t, object s, object e)
{
    string title = (string)t;
    DateTime start = (DateTime)s;
    DateTime end = (DateTime)e;

    int numberOfDays = (end - start).Days;
    int startDivAt = (start - dtMin).Days > 0 ? (start - dtMin).Days * 100 / dateSpan : 0;
    int howWide = end != dtMax ? ((end - start).Days + 1) * 100 / dateSpan : (end - start).Days * 100 / dateSpan;
    count++;
    return "<div class=\"gantt\" style=\"background:" + colors[count%colors.Count()] + ";width:" + howWide + "%;margin-left:" + startDivAt + "%;\">&nbsp;&nbsp;"+title+"</div>";
}

 

Notice in there I call an array I had declared called colors[] which simply has the colors {"navy","maroon","orange"} in it - this simply rotates the colors of the graph.  The code is pretty straight forward I think; had to do a little magic to prevent it from falling off the edge of the page.  Then to implement it, you just need to add in a repeater in your aspx:

 

<fieldset>
    <legend>Gantt Chart</legend>
    <asp:Repeater ID="rpt" runat="server">
        <HeaderTemplate>
            <div style="font-weight:bold;font-size:1.2em"><%= dateHeader %><br /></div>
        </HeaderTemplate>
        <ItemTemplate>
            <%# doGantt(Eval("title"), Eval("start"), Eval("end")) %></td>
        </ItemTemplate>
    </asp:Repeater>
</fieldset>

 

And then you set your DataSource and DataBind and you have a Gantt Chart...

 

rpt.DataSource = dt;
rpt.DataBind();

 

It even resizes liquidly to the size of the container. It is very vanilla, but definitely a good start to a simple, no images Gantt chart that could be expanded/spruced up very easily!

 


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

asp.net | c# | steal some code | tutorials

Adding Multiple Persistent Controls is Asp.Net

by naspinski 6/16/2008 5:21:00 PM

It's easy to add one control in asp.net during runtime, but it's not so straight-forward to add a bunch dynamically

You would think to add more and more controls, you could simply do something like this on a button click event (I will be using LiteralControls for ease of explanation, but this works the same for all controls, even custom ones):

 

somePanel.Controls.Add(new LiteralControl("<div>I AM A NEW CONTROL</div>"));

 

Which does work perfectly, and does exactly what you think it would do.  But, if you click it again, guess what?  It just re-makes the same control, replacing the old one.  Doing this over and over.  This is because what is produced is not kept in any sort of persistent state.  You need to 'tell' your program what you want it to keep.  For this,  I like to use Session variables... and if you don't like that, then too bad!

 

With that said, we will need some sort of way to keep all the controls in an easily accessable structure.  My choice here is a Generic List as they are so easy to work with and offer so much that you can do do/with them.  To start with, I will be working with a basic List<LiteralControl> but I will get on later to a list with multiple controls contained within it as it is likely that you will want to add multiple controls at each click.

 

Now we just need to show how this is going to be persistant.  First, we need to declare a list in the class.  Then, each time a control is added, it must be pushed into the list as well as the page as to keep a 'copy' of it.  But that still will not survice a postback.  We also need to put the List into a Session variable.  And now that we have that list of controls in the session, we need to check every Page_Load to see if there is any controls we have stowed away, and if so, push them to the page.  Here is the most basic way to show this with functioning code:

 

aspx 

<asp:Button ID="btn" runat="server" Text="Add Control" onclick="btn_Click" />
<asp:Panel ID="pnl" runat="server" />

 

code-behind (c#)

List<LiteralControl> persistControls = new List<LiteralControl>();
protected void Page_Load(object sender, EventArgs e)
{
    // if you already have some controls populated
    if (Session["persistControls"] != null)
    {
        // pull them out of the session
        persistControls = (List<LiteralControl>)Session["persistControls"];
        foreach (LiteralControl lc in persistControls)
            pnl.Controls.Add(lc); // and push them back into the page
    }
}
protected void btn_Click(object sender, EventArgs e)
{
    // basic control for demo
    LiteralControl lc = new LiteralControl("<div style=\"border:solid 2px navy;padding:3px;margin:3px\">NEW CONTROL</div>");
    pnl.Controls.Add(lc);// add it to your page
    persistControls.Add(lc);// add it to the list
    Session["persistControls"] = persistControls; // put it in the session
}

 

Now that is just a basic example to get the point across that this is actually a pretty easy concept.  Now on to a bit more functionality.  There are two basic things I would think an average use of this would require:

 

  • Ability to delete each 'set' of controls
  • Ability to add a bunch of controls each time and persist all of them

 

Turns out both of these are also quite easy given the structure we are using. 

 

Looking at the first one: Ability to delete each 'set' of controls should be no problem as we are using a generic List. What does a List have that makes this so simple?  List.Remove(List Item)  In fact, using a List makes this ridiculously easy.  Simply add a btnDelete_Click method to our code-behind, Now every time a control is added, a Button must also be added with a corresponding CommandArgument that relates to it's position in the List and add a Button.Click += new EventHandler(btnDelete_Click) so the new delete method will be called.  Since the List itself will automatically adjust it's size and move it's items dynamically we can simply use an integer to count up from 0 each time we push a control to the page.  And when a new Control is added, all that is needed is to add the List.Count to the CommandArgument.

 

Now on to: Ability to add a bunch of controls each time and persist all of them which will be even easier.  Instead of passing just one Control like above, we can pass a collection of Controls inside another control.  For this I chose Panels for the easy to work with <div> that they produce.  So now, every time you add a Control, you simply add all your Controls to a Panel, then push that Panel to the List (which is now a List<Panel> by the way).  And really that is all you need to do.  

 

With those two additions, the example code now looks like this:

 

aspx 

<asp:Button ID="btn" runat="server" Text="Add Control" onclick="btn_Click" />
<asp:Button ID="btnClear" runat="server" Text="Reset" onclick="btnClear_Click" />
<br /><br />
<asp:PlaceHolder ID="ph" runat="server" />

 

code-behind (c#) 

List<Panel> persistControls = new List<Panel>();
Random rand = new Random(); // for display so we can get a simple difference in controls
protected void Page_Load(object sender, EventArgs e)
{
    // if you already have some controls populated
    if (Session["persistControls"] != null)
    {
        persistControls = (List<Panel>)Session["persistControls"]; // pull them out of the session
        int count = 0;
        foreach (Panel lc in persistControls)
        {
            lc.CssClass = "smallPanel";
            Button btn = new Button();
            btn.Click += new EventHandler(btnDelete_Click);
            btn.Text = "Delete";
            btn.CommandArgument = count.ToString();
            ph.Controls.Add(lc); // and push them back into the page
            ph.Controls.Add(btn);
            ph.Controls.Add(new LiteralControl("<br /><br />")); // for formatting
            count++;
        }
    }
}
protected void btn_Click(object sender, EventArgs e)
{
    LiteralControl lc1 = new LiteralControl("<span style=\"border:solid 2px navy;margin:3px\"> NEW CONTROL [ "+ rand.Next(1000,9999).ToString() + "] </span>");
    LiteralControl lc2 = new LiteralControl("<span style=\"border:solid 2px navy;margin:3px\"> NEW CONTROL [ " + rand.Next(1000, 9999).ToString() + "] </span>");
    Panel pnl = new Panel();

    pnl.Controls.Add(lc1);
    pnl.Controls.Add(lc2);
    Button btn = new Button();
    btn.Click += new EventHandler(btnDelete_Click);
    btn.Text = "Delete";
    btn.CommandArgument = persistControls.Count.ToString();
    ph.Controls.Add(pnl); // and push them back into the page
    persistControls.Add(pnl);// add it to the list
    ph.Controls.Add(btn);
    ph.Controls.Add(new LiteralControl("<br /><br />")); // for formatting
    Session["persistControls"] = persistControls; // put it in the session
}
protected void btnClear_Click(object sender, EventArgs e)
{
    Session["persistControls"] = null;
    Response.Redirect(Request.Url.ToString());
}
protected void btnDelete_Click(object sender, EventArgs e)
{
    int deleteThisOne = int.Parse(((Button)sender).CommandArgument);
    persistControls.Remove(persistControls[deleteThisOne]);
    Session["persistControls"] = persistControls; // put it in the session
    Response.Redirect(Request.Url.ToString());
}

 

And that is all you need to do.  This could be cleaned up a bit and redundant code could be consolidated, but you get the idea.  This will work with any group of controls be it TextBoxes, DropDownLists or even custom Controls that you make.  I throw mine inside an UpdatePanel to make it function smoother.  Remember though, since this is using Session, high traffic or large control collection can make this a bit of a memory hog, so be careful. 

 

Here is an example and the code:

 



code:


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

asp.net | c# | steal some code | tutorials

Custom Web Part Template

by naspinski 5/20/2008 1:26:00 AM

You can use this web part as a starting point for all of your custom web parts

Especially since WSS 3.0 has been introduced, home-grown web parts have been more and more attractive to make.  The hardest part is figuring out how to start them. 

 

One option is to use a new class that simply inherits WebPart, that way everything is taken care of for you on the structure side.  That is great, but then the actual building of the insides of the web part become much more convoluted; such as using a writer to output all sorts of strange .net html elements and implementing everything programatically outside the designer.

 

A much more intuitive way is to use an ascx (web user control) and design it just like a webpage.  But the problem with that is the fact that it is a bit more complicated than that.  Simply inheriting WebPart does not really do you any good, it will work, but you can't change and WebPart attribute such as TitleUrl, Description, TitleIconImageUrl, etc.  The base Web Part properties.

 

The zip available below is a simple blank web part with inheritance taken care of all ready, you just start putting together your webpart like any other user control.  Then all you need is to register it in your page like any other control:

 

 <%@ Register src="~/WebParts/blank.ascx" TagName="blank" TagPrefix="wp" %>

 

And implement like you would any webpart:

 

 <wp:blank ID="wpBlank" runat="server" Title="Blank Web Part" TitleUrl="http://naspinski.net" TitleIconImageUrl="http://naspinski.net/pics/blogengine.ico" />


Currently rated 4.5 by 2 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

asp.net | c# | steal some code

Complete Web-Based Excel Spreadsheet Builder

by naspinski 5/8/2008 5:27:00 PM

Have your users make spreadsheets online, no excel needed

Now first off, this places a DataTable intot he Session State, and I know some people have a problem with that... I don't care.  Now that that is out of the way, I can explain how this works.

 

It is very simple, this program runs through all of the TextBoxes and DropDownLists that you have within the input_container Panel and adds them as string columns to a DataTable dt.  Once that is done, each entry is simply added to the DataTable and rendered onto a GridView.  Then I use Matt Berseth's GridViewExportUtil to spit the spreadsheet out to the user.  Everything is taken care of real-time with no writing to the disk. Pretty simple.

 

I also included a way to edit as a normal method wouldn't work in this case, it just populates a DropDownList every time you add a new item and pops it back into the forms if you choose to edit it _but_ if you do not save, the record will be lost (there is a warning).

 

Another thing to note is that this is a drop-in-and-use application.  Everything is populated automatically, you need to do absolutely nothing to the code-behind in order to use this utility, just customize your fields in the default.aspx in the input_container and the rest of the work is done for you.  I used my method of parsing IDs of the input fields to make column names so ddlLets_Party turns in to a column "Lets Party", Last_Name becomes "Last Name", strFruit becomes "Fruit" and so on.   You could easily add another attribute as ColumnName or something like that if you please.

 

Here is the provided example: Excel Spreadsheet Builder In Action, and the code:



Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

asp.net | c# | excel | steal some code

Update/Fix for the BlogEngine.Net Syntax Highlighter

by naspinski 5/7/2008 2:57:00 PM

This is so awesome, I can finally use the [code][/code] feature of BlogEngine without the annoying problems!

For those of you that use BlogEngine, you have probably noticed that the [code] sytnax highlighter is extremely fickle and difficult to use.  For me, I could never get the code to format without actually seeing '[code]' on my site.  I was notified by Rickard Nilsson that a new version was out and available at CodePlex.  This is fantastic, all I can say is thank you!

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

asp.net | links

Cascading DropDowns using XML and LINQ

by naspinski 5/4/2008 3:12:00 PM

A simple alternative method to the Ajax Control Toolkit's

Don't get me wrong, the Ajax Control Toolkit (ACT) is great, but a couple of the controls leave something to be desired.  For one, the things required to integrate the cascading dropdowns is a bit excessive IMO.  No need ot require asmx files to do a simple lookup.  Also, if you are changing values in your dropdowns (as I needed to do), this gives you no simple way to do it.

 

Figuring that dropdowns are almost always relatively small collections of choices, and I would be editing them often for my purposes, an XML files seems to be the perfect fit for this situation.  On top of that, with the ease of LINQ, this would be extremely easy to make an interface for editing the properties so my users could edit them without knowing the first thing about XML. 

 

I am going to try to basically copy the ACT in terms of functionality as I really like it, but change it 'under the hood'.  First thing is to make a simple XML file with my options in it, I used old cars for an example:

<?xml version="1.0" encoding="utf-8" ?>
<dropdowns>
    <makes>
        <maker>-please select-</maker>
        <maker>Ford</maker>
        <maker>Chevy</maker>
        <maker>Dodge</maker>
    </makes>
    <cars>
        <car_maker name="Ford">
            <car>Bronco</car>
            <car>Galaxy</car>
            <car>Mustang</car>
        </car_maker>
        <car_maker name="Chevy">
            <car>Chevelle</car>
            <car>Corvette</car>
            <car>Nova</car>
        </car_maker>
        <car_maker name="Dodge">
            <car>Charger</car>
            <car>Ram</car>
        </car_maker>
    </cars>
</dropdowns>

 Now add the Dropdowns to yoru .aspx with a few more properies added (required for this to work) the properties are:

  1. cascadeTo : The dropDown you want to cascade to
  2. cascadeCategory : The category in XML your cascade properties lie
  3. cascadeDescendant : The final level in XML where your items lie
  4. cascadeBlank : [optional] What the cascading DropDown will display when it is awaiting a selection


Here is my .aspx, Notice I added "- Select Make -" to the ddlModel DropDownList as that will help give the user some guidance and it is the same as the 'cascadeBlank' I designated:

Make:<br />
<asp:DropDownList ID="ddlMake"  runat="server" cascadeTo="ddlModel" cascadeCategory="car_maker" cascadeDescendant="car" cascadeBlank="- Select Make -"  AutoPostBack="true" onselectedindexchanged="ddlMake_SelectedIndexChanged" />
<br /><br />
Model:<br />
<asp:DropDownList ID="ddlModel" runat="server" Enabled="false"  >
    <asp:ListItem>- Select Make -</asp:ListItem>
</asp:DropDownList>

Next, you need to access your XML document and fill your initial menu, so make sure to add something like this to your code-behind:

XElement x;
protected void Page_Load(object sender, EventArgs e)
{
    x = XElement.Load(Server.MapPath(".") + "\\App_Data\\dropdowns.xml");
    if (!IsPostBack)
        foreach (XElement elem in x.Descendants("maker")) addDdlItems(ddlMake, elem.Value);
}

public void addDdlItems(DropDownList ddl, string value)
{
    ListItem li = new ListItem();
    li.Value = value;
    ddl.Items.Add(li);
}

Now you simply need to call cascade.fromThisDropDown from your _SelectedIndexChange event.  This way you don't need to write any code, just place the cascade.cs fil into your App_Code folder:

protected void ddlMake_SelectedIndexChanged(object sender, EventArgs e)
 { cascade.fromThisDropDown(this.Page, (DropDownList)sender, x); }

And that's it.  You can place it inside an UpdatePanel for the same exact Ajax effect that you have with the ACT, but without those pesky asmx files. If you want to see the cascade.cs code, click here to view/hide.

 

Not completely dummy proof, but I think it's useful.  You can download just the cascade class, or the full working example:






 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , ,

ajax | asp.net | c# | linq | steal some code | tutorials | xml

Never write another RequiredFieldValidator again

by naspinski 4/30/2008 3:41:00 PM

A time saving class that writes them all for you

I don't know about you, but I seem to write RequiredFieldValidators (referred to as RFVs from here on out) on pretty much every project I work on.  You just can't count on the user to fill stuff out unless you make them do it.  On a recent project, I was going to have to write a TON of RFVs, and to top if off, this form was likely going to change a lot, so I didn't want to have to re-write them later over-and-over again.  So I figured out a way for .Net to do the work for me... isn't that the point of programming?  As long as you follow good naming conventions, all you need to do is call the function and blam, you have RFVs.

 

Generally, I just use RFVs for DropDownLists and TextBoxes (DDLs and TBs from here on out), so I came up with a class that finds DDLs and TBs and makes RFVs for them.  BUT, I soon realized that I don't want to have everything be required, so I made the class look for only those with '_req' (required) on the end of their ID property.  So, a TB with ID="txtFirst_Name" will not get a validator, but one with ID="txtFirst_Name_req" will.

 

With that out of the way, I wanted it to give you somewhat readable and clear error messages, so the validators will be very descriptive and readable if you use good naming conventions.  For example, the DDL with ID="ddlCity_and_State_req" or ID="City_and_State_req" will both have a validator with the message "Must select a City and State".  As you can see, the prefixes, if present, are trimmed (which you can specify if you want, the defaults are 'txt' and 'ddl') and underscores (_) are replaced by spaces ( ).

 

The function takes in:

  • Panel pnl  - Required - The Panel you want this to run on
  • string[] trimFromFront - optional - An array of prefixes you wanted trimmed off for the ErrorMessages; default is 'ddl' and 'txt'
  • string defaultDropDownValue - optional - a string that is considered 'empty' in a DDL; default is '-'
  • string validationGroup - optional - the ValidationGroup that you want these controls to validate to; default is null

 

Examples of how to call the code (remember to pass null if you are not specifying an optional value): 

  // all defaults, but you DO have to include the HtmlForm of your page
validators.setupValidators(pnl, null, null, null);
   // defaults, but sets the ValidationGroup
validators.setupValidators(pnl, null, null, "valGroup1");
   // sets the DropDown 'empty' state to 'select'
validators.setupValidators(pnl, null, "select", null);
   // trims off prefixes 'TextBox', and 'DropDown' in the ErrorMessage
validators.setupValidators(pnl, new string[] {"TextBox","DropDown"}, null, null);

*IMPORTANT this does require a ValidationSummary control on your page, otherwise you will not see the errors, though they will be working.  This was the only way to keep the output clean as teh RFVs are added to the bottom of the page. Also, I recommend calling this in your OnInit event.

 

Here is the code if anyone wants to check it out: Show/Hide


Download just the class here:


 

 

Full working example (see it in action): 



 

kick it on DotNetKicks.com

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

asp.net | c# | steal some code

allowing/disallowing asp:menu links based on user roles

by naspinski 4/14/2008 7:56:00 PM

The asp:menu control is pretty useful for making  menus and easy 'popout' links, but what if you don't want certain users to be able to navigate to some pages?

If you are using a menu control, it is likely because you want stuff to be easy.  But if you have certain links in there that you do not want a user to be able to click if they are not in certain roles, it is not that obvious what you can do to implement that.  First think you will notice is that MenuItems do not have IDs, so you can't access them in the 'normal' asp.net way.

 

What you have to do is to access them through Menu.FindItem(), and the then you can manipulate them.  But then there is the question, if they do not have IDs, how do I find the item?  The items are looked up by their Text property in a hierarchical manner.  To access things in a hierarchy, you need to first set your Menu's PathSeperator property; set this to a delimiter (I use a comma) that you will use to seperate levels.  Here is a sample menu with this implemented:

<asp:Menu ID="mnu" runat="server" PathSeparator=",">
    <Items>
        <asp:MenuItem Text="home" NavigateUrl="~/Default.aspx"  />
        <asp:MenuItem Text="A" NavigateUrl="#">
            <asp:MenuItem Text="A-1" NavigateUrl="#" />
            <asp:MenuItem Text="A-2" NavigateUrl="#" />
        </asp:MenuItem>
        <asp:MenuItem Text="B" NavigateUrl="#">
            <asp:MenuItem Text="B-1" NavigateUrl="#" />
            <asp:MenuItem Text="B-2" NavigateUrl="#" />
            <asp:MenuItem Text="B-3" NavigateUrl="#" />
        </asp:MenuItem>
    </Items>
</asp:Menu>

Once that is done, you now can simply iterate through the items (that you already put in a list, and disable those you do not want the non-admin user to have access to:

 string[] adminOnlyItems = {"A,A-1", "A,A-2", "B", "B-3"};
if (!User.IsInRole("admins"))
{
    foreach (string s in adminOnlyItems)
    {
        MenuItem mi = mnu.FindItem(s);
        mi.Enabled = false;
    }
}
Notice how the items are written out in a hierarchical string, written like this: <Level 1 Item> <delimeter> <Level 2 Item> <delimeter> <Level 3 Item> and so on with as many or as few levels as you are looking for.  Also notice that "B-3" is unnecessary in the adminOnlyItems array, as disabling "B" disables that whole path of links, anythign under "B" will now be unreachable.  Here is a working example (you must have roles enabled and an "admin" role for this to work):


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

asp.net | steal some code

Allowing users to change their own Active Directory properties

by naspinski 4/8/2008 6:42:00 PM

Sometimes it is very convenient to allow users to make their own changes

**This is almost completely stolen from Ryan Dunn's Blog with just a few modifications.  You should be able to take this, drop it into your application and run it, as long as you follow the directions it will work.

 

I had a problem with Ryan's code and for some (still unknown) reason, without the using (HostingEnvironment.Impersonate()) I had added, it would not work.  So you may, or may not need that, be sure to test both.  Also, as Ryan points out: This requires you to use Integrated Windows Authentication with impersonation and your IIS server must be set for delegation.

 

I edited it to make it a bit more friendly for the user by dumping out the info aligned as it was not originally, I also added the static string[] allowUserToEdit array that allows you to limit the attributes the users can edit themselves.  Keep in mind that this only allows users to edit SOME of the AD properties, the 'AllowedAttributes' set in AD.

 

Thanks a bunch to Joe Kaplan and the rest of the guys at http://directoryprogramming.net/ who were a huge help.  They also have a great book out that I just bought that is about the best resource you can find for asp.net LDAP programming.



Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

asp.net | c# | steal some code