This blog is moved to
http://amalhashim.wordpress.com

Monday, January 24, 2011

Color Coding SharePoint List – With or Without Grouping

Using jQuery we can easily color code lists in SharePoint 2007.

Try using the following script

<script type="text/javascript" src="/_layouts/jquery-1.4.4/jquery-1.4.4.min.js"></script>

<style type="text/css">
.MyStyle
{
font-size: 11px;
background-color: red;
}
</style>
<script type="text/javascript">

$(document).ready(function(){

$(".ms-vb2:contains('Completed')").each(function(){
$(this).addClass(MyStyle);
});
});

</script>


Problem with this approach is, it won’t work in views with grouping. The problem is, on grouping, collapsed group data is not rendered on page load. To tackle this we need to tweak scripts in INIT.js, but directly modifying is not a good practice. To overcome this we can override the method which is rendering the data as shown in the below script block.



<style type="text/css">
.MyStyle
{
font-size: 11px;
background-color: red;
}
</style>

<script type="text/javascript" src="/_layouts/jquery-1.4.4/jquery-1.4.4.min.js"></script>

<script type="text/javascript">

//wait until all of the SharePoint stuff is loaded...
_spBodyOnLoadFunctionNames.push("CustomExpGroupByFix");

function CustomExpGroupByFix()
{
//Replace the function in INIT.JS with our custom function
window.ExpGroupReceiveData=function(x,y){ExpGroupReceiveDataC(x,y)}

}

//This is the exact replica of INIT.JS "ExpGroupReceiveData", we have added color coding code at the end
function ExpGroupReceiveDataC(htmlToRender, groupName)
{
var ctxId="ctx"+groupName.substring(0, groupName.indexOf("-"));
var indexBeginCTXName=htmlToRender.indexOf("CTXName=\"");
if (indexBeginCTXName !=-1)
{
if (ctxId !="ctx1")
{
htmlToRender=htmlToRender.replace(/ CTXName=\"ctx1\" /g, " CTXName=\""+ctxId+"\" ");
}
}
var needOuterWrap=false;
if (htmlToRender.length < 4)
{
needOuterWrap=true;
}
else if (htmlToRender.substring(0,3) !="<tr")
{
needOuterWrap=true;
}
if (needOuterWrap)
{
htmlToRender="<TR><TD>"+htmlToRender+"</TD></TR>";
}
ExpGroupRenderData(htmlToRender, groupName, "true");
g_ExpGroupInProgress=false;
if (g_ExpGroupQueue.length > 0)
{
ExpGroupFetchData(g_ExpGroupQueue.shift());
}

//Color coding the cells
$(".ms-vb2:contains('Completed')").each(function(){
$(this).addClass(MyStyle);
});
}
</script>


To use this script, edit the page –> add a content editor webpart.

Friday, October 22, 2010

MOSS | Using WSPBuilder for Creating a List Instance

In this post I am going to explain how we can make use of WSPBuilder for creating a List instance.
First we need to install SharePoint Solution Generator. You can download the same from here
http://download.microsoft.com/download/4/0/b/40b62080-6295-4d63-b396-d779fb9b4449/VSeWSSv12.exe
Now follow the steps for generating List Definition. Here I am going to create a List Definition of a List named “Configurations”
Start SharePoint solution generator
image
Select List Definition and click on Next button
image
Specify the Site Url where the list is present and click Next
image
Select the List and click Next
image
Provide a project name and path, then click Next
image
Click Finish
 image
Before clicking Exit, click “Click here to open the generated solution” and click Exit
image
You can see the “Configurations” folder. Let it be opened. Now open visual studio and create a WSPBuilder project
image
Once the project is created, add a new blank feature
image
Now, copy the folder “Configurations” and paste it under the feature folder as shown below
image
Open the ListDefinition.xml file and copy the following content
image
Once the content is copied, paste it in the elements.xml file as shown below and delete the file "ListDefinition.xml" from visual studion project
image
You can also see ListInstance, make a similar entry in your elements.xml file. Also replace the FeatureId with the FeatureId specified in the feature.xml file
Now build the wsp, deploy it and activate the feature. This will add the list to the site.
Hope this was helpful!!!

Thursday, October 21, 2010

MOSS | Using People Editor Control


People editor can be used whenever we want the user to select user, AD groups or SharePoint groups. For using the control, 1st we need to register the assembly as shown below
<%@ register tagprefix="SharePointWebControls" namespace="Microsoft.SharePoint.WebControls"
assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
Once this is done, we can use the following tag for placing the control
<SharePointWebControls:PeopleEditor ID="ppeUser" runat="server" Rows="1" 
CheckButtonImageName = "/_layouts/Images/user.png" 
BrowseButtonImageName = "/_layouts/Images/addressbook.png"                                   
PlaceButtonsUnderEntityEditor="false" MultiSelect="false" AutoPostBack="true"/>

In C#, the following code demonstrate the usage

this.ppeUser.CommaSeparatedAccounts;

Using the above code we can get information user has selected/entered in the people editor control.

public static void UpdatePeoplePicker(string login, PeopleEditor editor)
{
ArrayList list = new ArrayList();
PickerEntity entity = new PickerEntity();
entity.Key = login;
entity = editor.ValidateEntity(entity);
list.Add(entity);
editor.UpdateEntities(list);
}

The above code can be used to update the People Editor control using code.


We can restrict the selection of the People Editor using the SelectionSet property. It accepts the following values

User – In case the selection to be restricted only for users
AD – In case the selection to be restricted only for AD groups
SPGroup – In case the selection to be restricted only for SharePoint Groups

Hope this was helpful!!!

Friday, October 8, 2010

MOSS 2007 | Enumerate User Profile Properties

Below is the code to enumerate the User Profile Properties

using System;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
using (SPSite site = new SPSite("http://server:port/"))
{
ServerContext context =
ServerContext.GetContext(site);
UserProfileManager profileManager = new UserProfileManager(context);
string sAccount = "domain\\user";
UserProfile u = profileManager.GetUserProfile(sAccount);
PropertyCollection props = profileManager.Properties;

foreach (Property prop in props)
{
Console.WriteLine(prop.DisplayName + ">>" + prop.Name );
}
}
}
}
}

Friday, September 24, 2010

C# | Automating Facebook Login using WebBrowser Control

Create a new windows forms application project.

Add two button and place the web browser control as shown below. Rename the button as “btnShowPage” and “btnLogin”.

image

On form load event use the following code

private void Form1_Load(object sender, EventArgs e)
{
btnLogin.Enabled = false;
}



Now on button btnShowPage use the following code



private void btnShowPage_Click(object sender, EventArgs e)
{
webBrowser1.Navigate("https://login.facebook.com/login.php?login_attempt=1");
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
}


void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
string s = webBrowser1.DocumentText;
btnLogin.Enabled = true;
}



On btnLogin click event use the following code



private void btnLogin_Click(object sender, EventArgs e)
{
HtmlElement ele = webBrowser1.Document.GetElementById("email");
if (ele != null)
ele.InnerText = "amalhashim@gmail.com";

ele = webBrowser1.Document.GetElementById("pass");
if (ele != null)
ele.InnerText = "password";

ele = webBrowser1.Document.GetElementById("Login");
if (ele != null)
ele.InvokeMember("click");
}



That’s it :-)

Monday, August 30, 2010

Custom Application MasterPage | Sharepoint 2007

Recently I have involved in branding one of our clients sharepoint portal. As part of the branding process we needed to modify the application.master file, so even the layout pages  will have the same look and feel. As part of the investigation, we come up with the best approach for doing this.

1. Create a custom master page, with all the placeholders which are available in the original application.master file. Its better to take a copy of the application.master file and add the styles/images etc as you wish

2. Create a custom HttpModule which will set the new custom master page if the current page is having the master page “application.master”. We preferred HttpModule on top of HttpHandler because HttpModule can be deployed only to the web applications we wants, while HttpHandler will hit across all web applications.

Below is the code i have created for the http module.

using System;
using System.Web;
using System.Web.UI;
using Microsoft.SharePoint;

namespace Company.HttpModules
{
/// <summary>
///
All the layout pages will be using application.master
/// inorder to make the application consistent. we have created a custom application master page
/// this module will check whether the current request is having the master page as application.master
/// then change it to our custom page
/// </summary>
public class ApplicationMasterModule : IHttpModule
{
public void Init(HttpApplication context)
{
if (context == null)
throw new ArgumentNullException("context");

context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
}

void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
Page page = HttpContext.Current.CurrentHandler as Page;
if (page != null)
{
page.PreInit += new EventHandler(page_PreInit);
}
}

void page_PreInit(object sender, EventArgs e)
{
Page page = sender as Page;
if (page != null)
{
if (page.MasterPageFile != null)
{
if (page.MasterPageFile.Contains("application.master"))
{


using (SPSite connectSite = new SPSite(SPContext.Current.Site.Url))
{
using (SPWeb currentWeb = connectSite.RootWeb)
{
string url = currentWeb.ServerRelativeUrl + "/_catalogs/masterpage/our_custom_app.master";
page.MasterPageFile = url;
}
}
}
}
}
}

public void Dispose()
{
}
}
}



Now comes the important aspect of deployment. Its better to create the master page as well as http module to be deployed as a feature. See the feature.xml



<?xml version="1.0" encoding="utf-8"?>
<
Feature Id="b1531032-19b5-4fb1-87a6-6892b280c90d"
Title="Custom Application Master Page"
Description="Custom Application Master Page"
Version="12.0.0.0"
Hidden="FALSE"
Scope="Site"
DefaultResourceFile="core"
ReceiverAssembly="Company.MasterPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6c27a5016ad8e167"
ReceiverClass="Company.MasterPages.CustomAppMasterPage"
xmlns="http://schemas.microsoft.com/sharepoint/">
<
ElementManifests>
<
ElementManifest Location="elements.xml"/>
<
ElementFile Location="our_custom_app.master" />
</
ElementManifests>
</
Feature>



and elements.xml file



<?xml version="1.0" encoding="utf-8" ?>
<
Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<
Module Name="CustomApplicationMasterPage"
Url="_catalogs/masterpage"
Path=""
RootWebOnly="False">
<
File Url="our_custom_app.master"
Type="GhostableInLibrary" IgnoreIfAlreadyExists="FALSE">
<
Property Name="ContentType"
Value="$Resources:cmscore,contenttype_-9masterpage_name;" />
<
Property Name="PublishingPreviewImage"
Value="" />
<
Property Name="Description"
Value="Custom Application Master Page"/>
</
File>
</
Module>
</
Elements>



See the Feature Receiver assembly which will add the web.config entries so the HttpModule will work without manually modifying the web configuration file



using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Globalization;
using System.Diagnostics;

namespace Company.UIUpdates
{
/// <summary>
///
On Feature Activation => Add HttpModule Entry in Web.Config file
/// On Feature DeActivation => Remove the HttpModule Entry from Web.Config file
/// </summary>
class CustomAppMasterPage : SPFeatureReceiver
{
static SPWebConfigModification CreateModification(string Name, string XPath, string Value)
{
SPWebConfigModification modification = new SPWebConfigModification(Name, XPath);
modification.Owner = "Custom Application Master Page.wsp";
modification.Sequence = 0;
modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
modification.Value = Value;
return modification;
}

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
try
{
using (SPSite site = properties.Feature.Parent as SPSite)
{
SPWebApplication webApp = site.WebApplication;
string name = "add[@name='ApplicationMasterModule']";
string path = "configuration/system.web/httpModules";
string value = @"<add name=""ApplicationMasterModule"" type=""Company.HttpModules.ApplicationMasterModule,Company.HttpModules, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f2391931b556f037"" />";
if (webApp != null)
{
SPWebConfigModification modification = CreateModification(name, path, value);
webApp.WebConfigModifications.Add(modification);
webApp.Update();
SPWebService.ContentService.ApplyWebConfigModifications();
SPWebService.ContentService.WebApplications[webApp.Id].Update();
//Applies the web config settings in all the web application in the farm
SPWebService.ContentService.WebApplications[webApp.Id].WebService.ApplyWebConfigModifications();
}
}
}
catch (Exception ex)
{
WriteMessageToEventLog(ex.ToString());
}
}

static private void WriteMessageToEventLog(string message)
{
string EVENT_SOURCE = "CustomAppMasterPage Feature Receiver";
SPSecurity.RunWithElevatedPrivileges(delegate()
{
if (!EventLog.SourceExists(EVENT_SOURCE))
{
EventLog.CreateEventSource(EVENT_SOURCE, "Application");
}

EventLog.WriteEntry(EVENT_SOURCE, message);
});
}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
try
{
using (SPSite site = properties.Feature.Parent as SPSite)
{
SPWebApplication webApp = site.WebApplication;
string name = "add[@name='ApplicationMasterModule']";
string path = "configuration/system.web/httpModules";
string value = @"<add name=""ApplicationMasterModule"" type=""Company.HttpModules.ApplicationMasterModule,Company.HttpModules, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f2391931b556f037"" />";
if (webApp != null)
{
SPWebConfigModification modification = CreateModification(name, path, value);
webApp.WebConfigModifications.Remove(modification);
webApp.Update();
SPWebService.ContentService.ApplyWebConfigModifications();
SPWebService.ContentService.WebApplications[webApp.Id].Update();
//Applies the web config settings in all the web application in the farm
SPWebService.ContentService.WebApplications[webApp.Id].WebService.ApplyWebConfigModifications();
}
}
}
catch (Exception ex)
{
WriteMessageToEventLog(ex.ToString());
}
}

public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{

}

public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{

}
}
}


As part of the WSP, we included the following



1. Custom Master Page



2. Http Module dll which will go into GAC



3. Feature Receiver



Hope this helps. Feel free to contact me if you have any queries.

Thursday, August 19, 2010

Microsoft Sync Framework 2.1 Software Development Kit (SDK) Released

Microsoft Sync Framework is a comprehensive synchronization platform that enables collaboration and offline scenarios for applications, services, and devices. Using Microsoft Sync Framework, developers can build applications that synchronize data from any source using any protocol over any network.

Sync Framework 2.1 introduces new features that let you synchronize a SQL Server or SQL Server Compact database on your computer with a SQL Azure database. This release also introduces parameter-based filtering, the ability to remove synchronization scopes and templates from a database, and performance enhancements to make synchronization faster and easier.

SQL Azure Synchronization


With Sync Framework 2.1, you can extend the reach of your data to the web by leveraging the Windows Azure Platform and SQL Azure Database. By synchronizing a SQL Server database on your business premises to SQL Azure, you make some or all of your data available on the web without the need to provide your customers with a connection to your on premises SQL Server database. After you configure your SQL Azure database for synchronization, users can take the data offline and store it in a client database, such as SQL Server Compact or SQL Server Express, so that your applications operate while disconnected and your customers can stay productive without the need for a reliable network connection. Changes made to data in the field can be synchronized back to the SQL Azure database and ultimately back to the on premises SQL Server database. Sync Framework 2.1 also includes features to interact well with the shared environment of Windows Azure and SQL Azure. These features include performance enhancements, the ability to define the maximum size of a transaction to avoid throttling, and automatic retries of a transaction if it is throttled by Windows Azure. Sync Framework gives you flexibility in the way you structure your synchronization community, but two typical ways are to use a 2-tier architecture or an N-tier architecture.

  • 2-tier architecture: Sync Framework runs on the local computer and uses a SqlSyncProvider object to connect directly to the SQL Azure database without going through a middle tier or a web server, such as Internet Information Services (IIS).
  • N-tier architecture: A Sync Framework database provider runs in a Windows Azure hosted service and communicates with a proxy provider that runs on the local computer.

Bulk Application of Changes


Sync Framework 2.1 takes advantage of the table-valued parameter feature of SQL Server 2008 and SQL Azure to apply multiple inserts, updates, and deletes by using a single stored procedure call, instead of requiring a stored procedure call to apply each change. This greatly increases performance of these operations and reduces the number of round trips between client and server during change application. Bulk procedures are created by default when a SQL Server 2008 or SQL Azure database is provisioned.


Parameter-based Filtering


ync Framework 2.1 enables you to create parameter-based filters that control what data is synchronized. Parameter-based filters are particularly useful when users want to filter data based on a field that can have many different values, such as user ID or region, or a combination of two or more fields. Parameter-based filters are created in two steps. First, filter and scope templates are defined. Then, a filtered scope is created that has specific values for the filter parameters. This two-step process has the following advantages:

  • Easy to set up. A filter template is defined one time. Creating a filter template is the only action that requires permission to create stored procedures in the database server. This step is typically performed by a database administrator.
  • Easy to subscribe. Clients specify parameter values to create and subscribe to filtered scopes on an as-needed basis. This step requires only permission to insert rows in synchronization tables in the database server. This step can be performed by a user.
  • Easy to maintain. Even when several parameters are combined and lots of filtered scopes are created, maintenance is simple because a single, parameter-based procedure is used to enumerate changes.


Removing Scopes and Templates


Sync Framework 2.1 adds the SqlSyncScopeDeprovisioning and SqlCeSyncScopeDeprovisioning classes to enable you to easily remove synchronization elements from databases that have been provisioned for synchronization. By using these classes you can remove scopes, filter templates, and the associated metadata tables, triggers, and stored procedures from your databases.


Upgrading the Metadata Format


The metadata format for the database providers changed in Sync Framework 2.1. The new metadata format is incompatible with previous versions of the database providers. The upgrade to the new metadata format cannot be undone, and when you try to use an earlier version of the database providers to synchronize a database that is in the 2.1 format, Sync Framework throws an exception. However, the SqlSyncProvider class in Sync Framework 2.1 detects whether the metadata is in the 2.0 or 2.1 format, and operates in a backward compatibility mode to synchronize a database that contains metadata in the 2.0 format. Sync Framework can synchronize a database in the 2.0 format with a database in either the 2.0 or the 2.1 format. Therefore, it is not necessary to upgrade all of the databases in your synchronization community at the same time. For example, in an N-tier architecture you can upgrade the server Sync Framework components and database metadata format and continue to synchronize with clients that use Sync Framework 2.0. Clients can then upgrade when it is convenient for them to do so.


SQL Server Compact 3.5 SP2 Compatibility


The Sync Framework 2.1 SqlCeSyncProvider database provider object uses SQL Server Compact 3.5 SP2. Existing SQL Server Compact databases are automatically upgraded when Sync Framework connects to them. Among other new features, SQL Server Compact 3.5 SP2 makes available a change tracking API that provides the ability to configure, enable, and disable change tracking on a table, and to access the change tracking data for the table. SQL Server Compact 3.5 SP2 can be downloaded here.


Sync Framework 2.1 Redistributable Package


To download the Microsoft Sync Framework 2.1 redistributables, rather than the SDK package, click on the link: Microsoft Sync Framework 2.1 Redistributable Package