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...

 

C-Sharpener.com - Programming is Easy!  Learn Asp.Net & C# in just days, Guaranteed!

Extend an existing or custom class

by naspinski 10/31/2008 6:32:00 AM

Writing a extension for an existing class such as string.DoSomethingHere()

I usually run my database logic through Linq and a dbi.cs class for my database interaction. The dbml file will produce all of my custom classes which is great, but, I wanted to add some custom extensions. Looking at that code created by the dbml is overwhelming and I would rather not go poking around in there, so, I decided to make my own extensions, it's not a difficult process.


I had a class named ticket and I wanted to add an extension IEnumerable<ticket>.open() which would list all open tickets. Now, to get in to my calss structure and all of that would be a waste of time, so I will show how to do this with something that is a bit more familiar and likely useful, I am going to extend the string class with string.capitalizeFirstLetter() which would turn:

a senTENCE like this ONE hErE

into one like this

A Sentence Like This One Here

And yes, I know there is the CSS text-transform, but that isn't the point, it is the method I am showing.


First thing is first, make a new class called MyCustomExtensions.cs or something like that. Next, make sure to declare the class as a public static class. Now make a public static string method. normally in a method you would take a string input like this:

methodName(string someString)

For extensions, you do them slightly different like this:

methodName(this string someString)

Notice that this is now ahead of string, that will tell you program to 'look' for this extension whever a single string is used; it will also populate your intellisense in Visual Studio.


That is really the only big difference, now you just treat it like any other method. This is my full example class:

using System.Collections.Generic;
using System.Text;

/// <summary>
/// Custom Class Extensions
/// </summary>

public static class custom_extensions
{
  public static string CapitalizeFirstLetters(this string s)
  {
    string[] splitString = s.Split(new char[] { ' ' });
    List capitalized = new List();
    foreach (string word in splitString)
    {
      string add;
      if (word.Length == 1) add = word.ToUpper();
      else if (word.Length == 0) add = string.Empty;
      else add = word.Substring(0, 1).ToUpper() + word.Substring(1, word.Length - 1);
      capitalized.Add(add);
    }
    StringBuilder sb = new StringBuilder();
    foreach (string word in capitalized) sb.Append(word + " ");
    sb.Remove(sb.Length - 1, 1); return sb.ToString();
  }
}

Be the first to rate this post

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

Tags: ,

c# | tutorials

Packaging and Deploying a SharePoint 2007 Web Part

by naspinski 9/1/2008 7:47:00 AM

You know how to make a web part, but do you know how to get it to your production environment in the proper way?

In a past post, I did a WSS 3.0/MOSS 2007 Web Part Tutorial that showed how to make a web part.  That's all great and grand, but I did not cover how to actually get it to your production environment (truth is I didn't know how at the time).  Technically, you could install VS 2008 and the extension package on your production farm, but that isn't necessarily a good idea or 'best practice' by a long shot.  What you want is one nice neat file that you can take to your server and upload as a feature, that is what this tutorial is all about (most of this info was deciphered from the SharePoint 2007 SDK.)

 

We are going to assume that you already made your web part, and I am going to use the one from my past tutorial as the example for simplicity's sake.

 

Setup your Solution Structure

In order for this to compile correctly, your web part and cab projects must be inside the same solution.

 

  • Here we go: Open Visual Studio and Choose File > New Project, once in that dialogue, click on Other Project Types > Visual Studio Solutions and choose Blank Solution. Name it something, I am going to use TestSolution for mine.
  • This is a tricky part, but it is to keep the solution folder open and not go to a smaller project when we import one: In the Solution Explorer, right click on the solution and choose Add > New Solution Folder and name it dummy -- we will delete this later, but we need it for a moment.
  • In the Solution Explorer, right click on the solution and choose Add > Existing Project now navigate to your existing csproj (in my case, WPs.csproj) and click OK.
  • Now, in the Solution Explorer, right click on the solution and choose Add > New Project click on Other Project Types > Setup and Deployment and choose CAB Project name it and click OK (I named mine TestCab).
  • Now go back and delete the dummy folder.

 

Now you have the proper setup and structure to your folder.  Only a couple more steps and we will have a nice portable web part.  Your Solution Explorer should now look like this:

 

Prepare your Manifast and dwp files

These are required in order for your cab to be properly set up and used by SharePoint.

 

  • Right click on the Web Part Project inside the Solution and add an XML File, name it Manifest.xml, insert the following text into the file (notice the noly changes you might need to make are to the Namespace, which is used in your .cs file of the webpart, and FileName attributes):

<?xml version="1.0"?>
<!-- You need only one manifest per CAB project for Web Part Deployment.-->
<!-- This manifest file can have multiple assembly nodes.-->
<WebPartManifest xmlns="http://schemas.microsoft.com/WebPart/v2/Manifest">
    <Assemblies>
        <Assembly FileName="WPs.dll">
            <!-- Use the <ClassResource> tag to specify resources like image files or Microsoft JScript files that your Web Parts use. -->
            <!-- Note that you must use relative paths when specifying resource files. -->

            <ClassResources></ClassResources>

            <SafeControls>
                <SafeControl
                  Namespace="WPs"
                  TypeName="*"
                />
            </SafeControls>
        </Assembly>
    </Assemblies>
    <DwpFiles>
        <DwpFile FileName="WPs.dwp"/>
    </DwpFiles>
</WebPartManifest>

 

  •  Now right click on the sameProject and add another xml file, name this one your_web_part_name.dwp, for my example I am using WPs.dwp.  Notice that it is the same as specified in the FileName attribute in the xml file above -- add this text to your dwp file:

<?xml version="1.0" encoding="utf-8"?>
<WebPart xmlns="http://schemas.microsoft.com/WebPart/v2" >
    <Title>Title goes here</Title>
    <Description>Put your description here.</Description>
    <Assembly>WPs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5</Assembly>
    <TypeName>WPs.Test</TypeName>
    <!-- Specify initial values for any additional base class or custom properties here. -->
</WebPart>

 

The only part that may be a snag for some people is populating the <Assembly>'s PublicKeyToken and  <TypeName> tags in the above XML file.  Let me try and explain what and how to get these values:

  • To get the <Assembly>'s PublicKeyToken you need to go to your test machine, where the code was compiled and get the PublicKeyToken - that is the value you enter there.
  • As for the <TypeName> that is simply the Namespace.WebPartName of the web part itself.
  • Now right-click on your CAB Project and choose Add > Project Output once in that dialogue, choose Primary Output and Content Files, Click OK.
  • Right-click again on the CAB Project and Choose Add > File then browse you your dwp file you just made (mine is WPs.dwp), click Open and save your Solution.

 

You should now have everything set up correctly, your Solution Explorer should look like this:

 

Build and Deploy

All the hard work is done, now just build and deploy.

 

  • Right click on the solution and choose Build Solution - this makes your portable web part, just look in your solution folder, in my example it is located at TestSolution\TestCab\Debug\TestCab.CAB - if you will notice, that is just: Solution_Name\Cab_Project_Name\Debug\CabFile.CAB.
  • Now that you have your file, copy it to your production environment to the folder: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\bin\
  • Then run the command (from that directory):

     

    stsadm -o addwppack -filename Time_Zones.CAB -url http://your_url_here -globalinstall -force

     

  • And run an iisreset.


You are all done.  You should have your web part available to all of your users on the farm now.  And you can pass out the .CAB file to whoever wants it without any messy code to worry about!

Currently rated 4.0 by 2 people

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

Tags: , ,

sharepoint | tutorials

Simple Gantt Chart with Asp.net

by naspinski 6/27/2008 12:33:00 PM

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!

 


Currently rated 5.0 by 1 people

  • Currently 5/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/17/2008 2:21:00 AM

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