Probably the greatest out-of-the-box offering from the SharePoint product is search. However, the U.I. for search within SharePoint sites leaves a bit to be desired. The various site templates place the search box in areas on the page, I felt, weren’t prominent enough. Plus, I wanted to offer things like suggestions when searching for people and tracking/trending search topics.

Based on my research in user behavior, I knew that having a robust search U.I. would be vital in providing a successful Intranet site using SharePoint.

So, I set out to create a fully-functional user control to enhance the experience for our users. This is the first in a series of posts that will cover how it all got implemented.

Creating the User Control

I felt like search should be a tool that is readily available throughout the entire Intranet experience. I decided to create one user control that could be placed on the master page of the Intranet site. All the code would be developed into the user control and data would be provided by a web service.

1. Open Visual Studio and create a new Web Site Project
2. Add a new user control to the project
3. Add References to Microsoft.SharePoint and System.DirectoryServices (The Microsoft.SharePoint.dll can be located on your front-end web server if you develop on a separate workstation)
4. You may create a masterpage and attach it to the Default.aspx in your project. Then you can add the user control to the Default.aspx page. This will create an environment similar to your SharePoint site.

Now we have an environment similar to our SharePoint site. We can build design elements on our user control and bring them into our SharePoint site experience.

That’s great. But how do I get the user control working across my entire SharePoint site?

Because the search is so fundamental in our design, I wanted to add the user control to the master page of the SharePoint site. This would make the search experience prominent within the site (think Google or Yahoo).

1. Create a folder called “usercontrols” so that you can put the user control design (.ascx) file in a location the SharePoint site can find. (\\\C$\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\CONTROLTEMPLATES\usercontrols)
2. In the usercontols folder, place your .ascx file (after you build the project of course)
3. In the bin file of your site (\\$\inetpub\wwwroot\wss\VirtualDirectories\sharepointsite.domain.com80\bin) copy the compiled .dll from your project.
4. Open up SharePoint Designer and navigate to your master page (in my case I’m using “_catalogs\masterpage\default.master”)
5. Register the user control on the master page: <%@ Register src="~/_controltemplates/usercontrols/.ascx” tagname=”” tagprefix=”uc1″ %>

Of course, for this to work we need to mark certain assemblies as “safe” in the web.config of our site if they have not been deployed to the GAC. For instance, if you are using a ScriptManager you may want to add

<SafeControl Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" Namespace="System.Web.UI" TypeName="*" Safe="True" AllowRemoteDesigner="True" />

to your web.config under “SafeControls”. Depending on any other assemblies (Telerik, Dundas, etc.) you may need to add those as well. There is plenty of information in Googleland to handle those types of questions.

You may also want to take a look at my post about controlling the styling of your master page. This will help you in getting your user control placed and designed exactly how you want it.

Next Part: SharePoint Search on Steroids Part 2 — Using JQuery and Web Services

I wish I could say that my code is always bug free.

Developing applications within the health care environment doesn’t afford myself or my users this luxury.
Often times, I test as much as I can and release my little baby into the wild.

Sure, I would love to implement a rigorous SDLC, but if I did that, my projects would take well over a year each.  I’m required to be far more agile than that.

So I would do what any other good programmer would do.  I wrote the best code I could and when users complained I’d pull out my box of Band-Aids (they have “try/catch” written on them).

Unfortunately, users aren’t always the best people to troubleshoot with.  It would go something like this:

User: “The program isn’t working.”
Me: “Okay, I’m sorry about that.  Can you describe the problem you’re having?”
User: “It won’t work when I click the button.”
Me: “Okay.  What page are you on?”
User: “It’s the blue one.  You know the button on the bottom of the blue page?”
Me: ” Well….They’re…kinda…all blue.”
User: “This program is slow…”

During my studies for the 70-562 exam I discovered the proper use of the Global.asax file and how to deal with unhandled exceptions globally within my applications.

I’m not above admitting that any ASP.NET developer, worth his/her salt, should know all about this.  But, then again, I’m not a developer worth my salt.

<shame>I was concerned about logging errors, but most often I would be doing it from code-behind files; storing errors in a database or the Event Viewer</shame>.

So I have now crafted some code to be used in the Application_Error event of the global.asax file.

This will generate a nice HTML and plain-text e-mail detailing all the information about the unhandled error.  In this case, I have these e-mails sent directly to me.

Finally, the code clears the server error so that it can redirect the user to a nice error page, telling them I screwed up.

Most often, the errors that I receive are minor.  It’s been fun to call users and let them know I fixed an error they had only moments ago.  Their reaction is, needless to say, positive.

Here is a sample of what the HTML version of the e-mail looks like:

Screenshot of the HTML e-mail

Screenshot of the HTML e-mail

And here is the code to be placed in the code-behind of your Global.asax file (I’ve omitted the other events for brevity):

using System;
using System.Net.Mail;
using System.Net.Mime;
using System.Web;

/// <summary>
/// Summary description for Global
/// </summary>
namespace YourProjectName
{
        protected void Application_Error(object sender, EventArgs e)
        {
            MailMessage iMsg = new MailMessage();
            SmtpClient SMTP = new System.Net.Mail.SmtpClient("<your Email Server>");
            iMsg.From = new MailAddress("<yourApplicationName>_500_Error@yourdomain.com");
            iMsg.Priority = MailPriority.High;
            iMsg.Subject = "There was a Error Message with <yourApplicationName>";
            //Create the plain text version of the e-mail
            iMsg.Body = "An Unhandled Exception Error occurred with <yourApplicationName> on: " + DateTime.Now.ToString() + "\n\n" +
                "====================\n" +
                "Inner Exception \n" +
                "====================\n\n" +
                 Server.GetLastError().InnerException + "\n\n" +
                "====================\n" +
                "Error Message \n" +
                "====================\n\n" +
                 Server.GetLastError().Message + "\n\n" +
                "====================\n" +
                "Source \n" +
                "====================\n\n" +
                 Server.GetLastError().Source + "\n\n" +
                "====================\n" +
                "Stack Trace \n" +
                "====================\n\n" +
                 Server.GetLastError().StackTrace + "\n\n" +
                "====================\n" +
                "Target Site \n" +
                "====================\n\n" +
                 Server.GetLastError().TargetSite;

            //Create the alternate HTML view
            String HTMLBody = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">" +
                "<html><head><meta http-equiv=Content-Type content=\"text/html; charset=iso-8859-1\">" +
                "</head><body style='font-family:Arial; background-color:#FFFEF5;'>" +
                "<table style='font-family:Arial'><tr><td style='color:Red; font-size:16pt;'>There was a 500 error with *YourApplicationName* on: <td>" + "<td><b>" + HttpUtility.HtmlEncode(DateTime.Now.ToString()) + "</b></td></tr></table><br />" +
                "<div style='font-weight:bold; font-size:14pt; font-family:Tahoma; width:100%; background-color:#077BAD; border-bottom:solid 2px #044062; border-top:solid 2px #044062; color:White'>Inner Exception</div><br />" +
                "<div style='font-family:Courier; font-size:11pt;'>" + HttpUtility.HtmlEncode(Server.GetLastError().InnerException.ToString()) + "</div><br />" +
                "<div style='font-weight:bold; font-size:14pt; font-family:Tahoma; width:100%; background-color:#077BAD; border-bottom:solid 2px #044062; border-top:solid 2px #044062; color:White'>Error Message</div><br />" +
                "<div style='font-family:Courier; font-size:11pt;'>" + HttpUtility.HtmlEncode(Server.GetLastError().Message.ToString()) + "</div><br />" +
                "<div style='font-weight:bold; font-size:14pt; font-family:Tahoma; width:100%; background-color:#077BAD; border-bottom:solid 2px #044062; border-top:solid 2px #044062; color:White'>Source</div><br />" +
                "<div style='font-family:Courier; font-size:11pt;'>" + HttpUtility.HtmlEncode(Server.GetLastError().Source.ToString()) + "</div><br />" +
                "<div style='font-weight:bold; font-size:14pt; font-family:Tahoma; width:100%; background-color:#077BAD; border-bottom:solid 2px #044062; border-top:solid 2px #044062; color:White'>Stack Trace</div><br />" +
                "<div style='font-family:Courier; font-size:11pt;'>" + HttpUtility.HtmlEncode(Server.GetLastError().StackTrace.ToString()) + "</div><br />" +
                "<div style='font-weight:bold; font-size:14pt; font-family:Tahoma; width:100%; background-color:#077BAD; border-bottom:solid 2px #044062; border-top:solid 2px #044062; color:White'>Target Site</div><br />" +
                "<div style='font-family:Courier; font-size:11pt;'>" + HttpUtility.HtmlEncode(Server.GetLastError().TargetSite.ToString()) + "</div><br />" +
                "</body></html>";

            //Add the alternate view
            iMsg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(HTMLBody, null, MediaTypeNames.Text.Html));

            //Finish sending the message
            iMsg.To.Add(new MailAddress("<your_email@your_domain.com>"));
            SMTP.Send(iMsg);
            //Clear the error so that you can redirect to your error page
            Server.ClearError();
            Response.Redirect("~/Error.aspx");
        }
    }
}

This is one of those ideas I wish I was smart enough to come up with myself.  But my hat is off to Alex Arkhipov who came up with a nifty solution to prevent the dreaded double-postback.

You might remember that this issue has been a common theme for me.

It seems that no matter how quick and well designed my UI is, users still find ways to insert multiple records into my database by double-clicking.  It never used to be an issue when the entire page would post back, however, with the latest AJAX tools and functionality, it happens more and more.

In any event, Alex came up with this simple solution that appears to be working great!

Essentially, he adds client-side page event handlers that disable the calling button during an initializeRequest event and re-enables it during an endRequest event.  Simply brilliant!

I modified the code a bit to remove the styling from CSS. I just needed the button to be disabled.
Then, I placed this code inside of my master page so all of my child pages could take advantage of this functionality.


<script type="text/javascript">
function pageLoad(sender, args) {
     var rm = Sys.WebForms.PageRequestManager.getInstance();
     rm.add_initializeRequest(initializeRequest);
     rm.add_endRequest(endRequest);
}
function initializeRequest(sender, args) {
     //Disable button to prevent double submit
     var btn = $get(args._postBackElement.id);
     if (btn) {
          btn.disabled = true;
     }
}
function endRequest(sender, args) {
     //Re-enable button
     var btn = $get(sender._postBackSettings.sourceElement.id);
     if (btn) {
          btn.disabled = false;
     }
}
</script>

I don’t know if you are like me, but I hate dealing with session variables. They look terrible in code, they are difficult to manage and organize, and overhauling them can be a nightmare.

I’m working on a nursing productivity tool here at work. It essentially assists nurse managers in scheduling resources to maintain ratios, provide superior care, and protect our financial bottom-line.

The challenge with this tool is that I’ve well over 20 session variables that I write to.  Additionally, I read from these variables in over seventy locations.

So, I did some Googling and discovered a blog post, written by raj, that details creating a SessionHandler class.

It’s a great way to manage and organize all of your session variables outside of your working code.  Plus, the class protects from NullReferenceException and type cast errors.

Here’s and example:

One of the session variables I’m using stores the user’s full name.  In this case, I create a SessionHandler class file (SessionHandler.cs) and add a public static property called “User Full Name”.

public static class SessionHandler

    {
        private static string _userfullnamekey = "UserFullName";

        // Gets or Sets the user's full name.
        public static string UserFullName
        {
            get
            {
                //Check for null first
                if (HttpContext.Current.Session[SessionHandler._userfullnamekey] == null)
                {
                    //Return an empty string if session variable is null
                    return string.Empty;
                }
                else
                {
                    return HttpContext.Current.Session[SessionHandler._userfullnamekey].ToString();
                }
            }
            set
            {
                HttpContext.Current.Session[SessionHandler._userfullnamekey] = value;
            }
        }

So now, if I want to access the value of this variable from my working code, I do this:


SessionHandler.UserFullName = "Travis Lowdermilk";

Label1.Text = SessionHandler.UserFullName;

You’ll notice that the SessionHandler class ensures that I do not get NullReferenceException or invalid cast errors.

No more repeatedly checking for null values or casting my session variables in working code.

Updated (9/2/2009): It appears that this is no longer an issue in the RadControls for ASP.NET AJAX Q2 2009 release. Read this post for a better solution to this problem.

An all too common situation us web developers face is the dreaded “double submit” issue.

Users, for some reason, love to double-click on every submit button you might create in your web application.  It’s like an impulse.  They MUST submit the record into the database twice.

Poor souls.  They just can’t help themselves.

There are a handful of ways to address this issue using javascript, SQL, and server-side code.

I wanted to use javascript because I felt it was the most “lightweight” way to handle this issue.

Plus, my submit button was nested inside of a FormView, that was nested inside of a ContentPanel, that was nested inside of a MasterPage.

Fun.

In any event, I created a javascript function to fire on the OnClientClick property of the submit button:

<asp:Button ID=”btnSubmit” runat=”server” Text=”Submit Assessment Form” ToolTip=”Submit the Assessment Form”

onclick=”btnSubmit_Click” OnClientClick=”DisableSubmit(this);” />

I then created a javascript function on the Masterpage:

<script type=”text/javascript”>

function DisableSubmit(buttonElement) {

document.getElementById(buttonElement.id).disabled = true;

}

</script>

Hmmmm, when I would click the button, nothing would happen.

So I put in an alert and discovered that the javascript would fire, but the button would not enter the “disabled” state.

Frustrating!

Long story longer, I discovered that this would not work if I was using the Telerik RadFormDecorator.

That’s because the RadFormDecorator renames the client id of each control that it skins.

Therefore, the javascript function DisableSubmit was receiving “ctl00_ContentPlaceHolder1_frmAssessment_btnSubmit”, but the actual id was “Skinnedctl00_ContentPlaceHolder1_frmAssessment_btnSubmit”.

The RadFormDecorator was placing “Skinned” at the front of the id.

So I amended the javascript function:

<script type=”text/javascript”>

function DisableSubmit(buttonElement) {

document.getElementById(‘Skinned’ + buttonElement.id).disabled = true;

}

</script>

Now, the button disables appropriately.  Yay me!

First, lets be clear.

I am, by far, the WORST test taker.  I have paralyzing anxiety when it comes to taking tests.  I have found, in my years in college, that the way I pass exams is by being prepared.  There really is no “short-cut” for me.

I am a bit embarrassed that after 3 months of intensive study for this exam, I received a passing score of 700.

That’s right.  I got just enough questions right to pass.

To be honest, I was a little dissapointed.  I believed that with the effort I put into my studies, I should’ve performed better.  But I digress.

Here are some things that DID help me prepare.

1.  Its a good idea to fully understand what you are studying for.  This page gives a pretty extensive overview of what to expect on the exam.

2. I purchased the MCTS Self-Paced Training Kit book by Tony Northrup, Shawn Wildermuth, and Bill Ryan.  This book has its flaws (which I’m sure you’ve seen in other forums).  Overall, its a comprehensive collection of what’s needed to pass.  I found the MeasureUp test, included with the book, to be absolutely useless.  The questions are poorly written and really just tell you what you didn’t memorize from the book.  It doesn’t focus on CONCEPTS.  Furthermore, if you select the wrong answer, MesureUp does not thoroughly explain why that is not the right answer.

3.  I purchased a Transcender practice exam.  There are different schools of thought on using “practice” exams.  I was a bit leary in using it, but Transcender did an AMAZING job of putting together practice questions.

I would recommend that you start with the book.  Read through each chapter and take notes.  I used Microsoft One Note to collect all of my notes.  This made it handy when I was finished.  I could print my entire notebook for review.  Plus, I could copy and paste elements from the ebook (diagrams, tables, etc.) that I wanted to remember.  The only problem I had was copying and pasting code from VS to One Note.  I had to paste it into Word first to keep the coloring and formatting.  C’mon Microsoft, can we fix this please!?

After completing the book, I went through and completed each lab in the book.  I think it was a better strategy to do it this way because, in a sense, it allows you to go through the book twice.

When I was finished with the book and the labs, I purchased the Transcender.  Each question that I got wrong, I printed out.  Then I would highlight the “keywords” or concepts that I was missing from that question.  Again, Transcender does such a GREAT job of really honing in on why the wrong answer is wrong.  I feel like I learned more about what I didn’t know from taking the Transcender and, upon taking the test, I found very few questions that were similar.  So, it didn’t feel like “cheating” to me.

Rinse and Repeat.

You can complete the exam in C#, Visual Basic, and (I think) C++?

I can write in both VB and C#, but I chose VB for readability.

I would say that if you are new to programming in general or haven’t developed a competincy for reading/writing code, this would be an ambitious starting point.

If you have any other questions, feel free to leave me a comment and I will do the best I can to answer.

My wife and I sporting SWEET T-Shirts from Telerik (Thanks Emily!)
My wife and I sporting SWEET T-Shirts from Telerik (Thanks Emily!)

My wife and family are happy.  That’s because I’m home in time for dinner.

Thanks to the hard working folks at Telerik, I can get things DONE.

Most importantly, I don’t have to sacrifice my design or UI strategies!

Let’s face it.  A lot of us developers (especially in health care) work on projects by ourselves.

We may be on a team of developers, but with so many projects coming in, we take one under our wing and run with it.

It becomes our baby.  We feed it, love it, and one day we let it leave our protection; hoping it does what we told it to do.

Having to work under these conditions means that we have to be the developer, tester, AND designer.

And it seems to me, the cool design elements always come last.  After we’ve ran out of time.

“Gee, I would really like to have this form AJAX-ifed, but I just don’t have the time.”

“It would be really cool to bring some color and design elements to this GridView, but alas, it’s due next week.”

“I spent all my time getting this INFERNAL thing to work; I don’t have time to make it pretty!”

Well, I am more than happy to suggest a FANTASTIC set of ASP.NET tools from Telerik.  I can’t tell you how much I love these tools.

Having these controls is like having a team of developers enhancing every aspect of your development.

For instance, the RadFormDecorator will allow you (with one line of code) to format all of your buttons, radio buttons, text boxes, list boxes, drop down lists, etc. to a skin of your choice.  Allowing you to instantly change the look and feel of your pages.

The RadEditor, with spell check, gives you a robust text editor that will make your boss think you SLAVED over the design.

The RadMenu, RadTabStrip, and RadPanel give you intuitive navigation with very little coding.

And the RadGrid?  RadGrid, alone, is worth the money spent.

I could go on and on.

Do not hesitate.  Download the trial today!

I have currently been tasked with the duty of providing a web part that displays patient satisfaction scores for the hospital. However, there was one stipulation:

“Can you make the web part reflect the unit that the nurse is working on?”.

In other words, could I create a web part that would observe the user’s login and display appropriate information based on where, in the hospital, that employee worked. In this case, the requester (ahem, my boss) wanted the scores to display for the nurse’s unit (think of a unit as a “wing” or “floor” in a hospital).

Provocative.

Right off the bat, I figured the best way to access the nurse’s unit was by pulling the “Department” property from our Active Directory schema.

But then I thought: “Why not build a function that would return any property I might want from Active Directory?” That way, from here on out, as I am building my web parts I could make decisions of the data to display based on a user’s department, job title, director, etc.

Essentially, creating web parts that are “user-aware”.

Good idea self!

Below is a namespace (ActiveDirectoryInfo) , class (UserInfo), and function (GetPropertyValue) that I created to do just this:

using Microsoft.Office.Server.Audience;

using Microsoft.SharePoint;

using Microsoft.SharePoint.WebControls;

using System;

using System.Collections.Generic;

using System.DirectoryServices;

using System.Text;

using System.Web;

namespace ActiveDirectoryInfo

{

class UserInfo

{

public String GetPropertyValue(string PropKey)

{

//Get user’s Department from Active Directory

SPWeb spw = SPControl.GetContextWeb(HttpContext.Current); //Establishes the current SharePoint site.

SPUser spu = spw.CurrentUser; //Grabs user information from the logged in state of the user.

DirectoryEntry dentry = new DirectoryEntry(@”LDAP://DC=<hidden>,DC=<hidden>”, “<domain_user>”, “<domain_user_password>”);

DirectorySearcher dsearch = new DirectorySearcher(dentry);

String retUserName= “”;

dsearch.Filter = “(objectSid=” + spu.Sid + “)”; //Filters the search result based on the user’s SID.

//dsearch.Filter = “(sAMAccountName=” + spu.LoginName.Replace(@”Domain\”, “”) + “)”; //Filters the search result based on the user’s login (without Domain\).

dsearch.PropertiesToLoad.Add(PropKey); //Loads the specific property to be viewed.

SearchResult result = dsearch.FindOne(); //Peforms the search for one matching record.

if (null == result)

{

//Nothing

}

else

{

retUserName = result.Properties[PropKey][0].ToString();

}

return retUserName;

}

}

}

So here is how we might call upon this function within a web part:

protected override void Render(System.Web.UI.HtmlTextWriter writer)

{

UserInfo ui = new ActiveDirectoryInfo.UserInfo();

writer.Write(ui.GetPropertyValue(“cn”)); //Returns user’s full name

writer.Write(ui.GetPropertyValue(“mail”)); //Returns user’s e-mail

writer.Write(ui.GetPropertyValue(“Department”)); //Returns user’s Department

}

Cisco Phone Photo Who cares that I don’t have a face? It’s still cool!

Below is the code I used to tap into the CIPIMAGE API and convert a .jpg image from our PeopleSoft database into a valid .cip image at runtime. Specifically it uses the “ImageProcessor” object to convert the image from a jpeg into XML data to be parsed by the phone.

This code will also require my Cisco Phone Object Class. The cipimage.dll is included in this post below. Be sure to register cipimage.dll on your web server!

 

 

Here’s the code:

Imports CiscoIPPhoneServices

Imports System.Data

Imports System.Data.SqlClient

Imports CIPIMAGE

Partial Class physdir_show_details

Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Response.ContentType = “text/xml”

Dim ImgProc As New ImageProcessor

‘Establish connection with database

Dim SQLConnect As New SqlConnection(ConfigurationManager.AppSettings(“ConnectionStringName”))

Dim SQLCommand_Info As New SqlCommand(“stored_procedure_to_receive_info_from_db”, SQLConnect)

SQLCommand_Info.CommandType = CommandType.StoredProcedure

SQLCommand_Info.Parameters.AddWithValue(“@empid”, Request.QueryString(“empid”).ToString)

‘Prepare the table

Dim Adapter As New SqlDataAdapter(SQLCommand_Info)

Dim DT As New DataTable

Adapter.Fill(DT)

Dim EmpPhoto As String = “”

Dim EmpName As String = DT.Rows(0).Item(“EmployeeName”)

Dim pWidth As Integer = 52

If DT.Rows(0).IsNull(“EmpPhoto”) = False Then

Dim bEmpPhoto As Byte() = DT.Rows(0).Item(“EmpPhoto”)

ImgProc.LoadJPGFromBuffer(bEmpPhoto)

ImgProc.SetLocation(-1, -1)

ImgProc.Resize(52, 65)

ImgProc.ColorToGray()

ImgProc.ReducePaletteColors(4)

EmpPhoto = ImgProc.SaveCIPDataToBuffer()

EmpPhoto = Left(EmpPhoto, EmpPhoto.Length – 6)

Else

‘No photo Hex ASCII string

EmpPhoto = “<Insert a valid ASCII string for a picture that will display when the employee does not have a photo>”

EmpName = “No Photo Available”

pWidth = 87

End If

Dim CIPPD As New CiscoIPPhoneImage(“”, EmpName, -1, -1, pWidth, 65, 2, EmpPhoto, “Back”, “SoftKey:Back”, 1)

Response.Write(CIPPD)

End Sub

End Class

Download – CipImage.dll

January 10th, 2008Yahoo! Weather Web Part

Weather Web Part ImageYeah, I know. You’re thinking this is frivolous; “What’s the point?”, you say. Well this is my first web part and I decided to go with something a little less “high profile”. However, I am still happy with it and think its got enough of that cool factor to warrant a post here.

It accesses the RSS feed from Yahoo! Weather and parses it for use within the web part. The code I provided is designed to retrieve the weather information for our location (Visalia, CA 93277) but could be easily modified for yours. Or, if you wanted, you could add a TextBox and have the user submit their own zip code!

There is A LOT of styling involved with making it look this way. I will include the styles as well as the plate graphics (which turns to gray after sunset). I would suggest, if you plan to use my styles, that you read my previous post on “Customizing the order of your stylesheets“. It’s a bit more work, but I like to have all the styles for the webparts I’ve developed in an independent stylesheet and not have those styles overwritten by the INFAMOUS core.css

I didn’t build this in a deployable package (still learning that), so this is just the C# code. You will have to build it into a .dll and deploy it to the GAC or place it into the bin folder. You will also have to set the web part namespace to be trusted in your web.config. Google will be your friend on all of that.

If all of this is just too daunting then I suggest trying Dustin Miller’s approach using SharePoint Designer (wuuuhhh!?) . The only problem I found with this, is that the datalist web part created in SharePoint Designer could not be shared easily between sites and users would not be able to add it to their own content pages (without my intervention).

Here are the source files: weather_webpart.zip


© 2007 travislowdermilk.com | iKon Wordpress Theme by TextNData | Powered by Wordpress | rakCha web directory