Thursday, April 30, 2009

Dynamic Charts for Free!!

Thanks to Google Chart API.
API will return the PNG format image in response to a URL, Advantage! Now you can render several types of images
Including Line charts, Bar charts, Pie charts, Venn diagrams, Scatter plots, Radar charts, Maps ,Google-o-meters & QR codes.

API URL must be in the following format:
http://chart.apis.google.com/chart?&&

Where:
http://chart.apis.google.com/chart? is the Chart API's location.
& separates parameters.
chs=250x100 is the chart's size in pixels.
chd=t:60,40 is the chart's data.
cht=p3 is the chart's type.
chl=HelloWorld is the chart's label.

Results:


Steps:
1. Choose the List
2. Create a Group By View on that List.
3. Now Create a new web part page
4. Add the List to this web part page (Selected List in step 1)
i. Set the current view to Group by new which we created in the step 2
ii. Then Under the Layouts choose/check the Hidden
5. Add the Content Editor web part to the same web part page.
6. Copy below code & you are done!!.


<div id="PieChart" class="content"><strong>Pie Chart Using Google Charting API</strong></div>
<script type="text/javascript">
if(typeof jQuery=="undefined")
{
var jQPath="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/";
document.write("<script src='",jQPath,"jquery.js' type='text/javascript'><\/script>");
}
</script>

<script type="text/javascript">
$("document").ready(function(){
var arrayList=$("td.ms-gb:contains(':')");
var cord= new Array();
var lblTxt= new Array();

$.each(arrayList, function(i,e)
{
var varIf= $(e).text();
var CordTxt= varIf.substring(varIf.indexOf('(')+1,varIf.length-1); // Extract the 'Y' coordinates
cord[i]=CordTxt;
var LabelTxt= varIf.substring(varIf.indexOf(':')+2,varIf.indexOf("(")-1); // Extract the labels
lblTxt[i]=LabelTxt+"("+CordTxt+")"; //add also coordinates for better read
});
var CordTxt= cord.join(",");
var LabelTxt= lblTxt.join("");
var APIurlWithValues= "<IMG src='http://chart.apis.google.com/chart?cht=p3&chs=750x200&chd=t:"+CordTxt+"&chl="+LabelTxt+"'/>";
$("#PieChart").append("<p>"+APIurlWithValues+"</p>")});

</script>

Monday, February 23, 2009

Hide View All Site Content Menu And Site Action Menu

Some time we need to hide View All Site Content & Site Action Menu from normal user so that they won't mess around.

Add Content Editor webpart, to the page and add below code to it.
<style>
/* TO REMOVE MY SITE LINK */
#ctl00_PlaceHolderGlobalNavigation_ctl08_hlMySite{display:none;}
/* TO REMOVE MY LINKS */
#ctl00_PlaceHolderGlobalNavigation_ctl09_MyLinksMenuMenu_t{display:none;}
/* TO REMOVE SEARCH */
.ms-sbrow{display:none;}

/* TO REMOVE SITE ACTION MENU */
.ms-siteactionsmenu{display:none;}

/* TO REMOVE VIEW All SITE CONTENT MENU */
.ms-quicklaunchheader{display: none;}

/* TO REMOVE RECYCLE BIN */
.ms-recyclebin{display:none;}
</style>
Boom you are done and results:


Hide Whole Master Page:
<style type="text/css">
.ms-globalbreadcrumb{display:none}
.ms-globalTitleArea {display:none}
.ms-bannerframe{display:none}
.ms-titlearealeft{display:none}
.onetidPageTitleAreaTable{display:none}
.ms-quickLaunch{display:none}
.ms-navframe{display:none}
.ms-titlearearight{display:none}
.ms-pagetitleareaframe{display:none}
.ms-pagemargin{display:none}
.ms-bodyareapagemargin{display:none}
.ms-pagebottommarginright{ display:none}
.ms-leftareacell{ display:none}
.ms-pagebottommargin{ display:none}
</style>

Sunday, December 7, 2008

Preserving/Updating CreatedBy and ModifiedBy

You might have a scenario where by you want to migrate the list data from one site another site list manually instead of .STP file
Or you use Run With Elevated Privileges ( with delegate()) to insert a record into library where by normal user don't have contribute rights but only READ access Or you need to update one or more fields in a library and you want to preserve Created By and Modified By data.

Here is the Pseudocode:
If Current User is Super user OR Preserver user details is false
Normal Insert
Else
Run the Code With Elevated Privileges to Insert
Then Restore User Details
End If

Code for Restore User Details (C#):

private void RestoreUserDetails(string sitename, string libname, int itemId, int sharePointUserID, string UserLoginName)
{
using (SPSite siteColl = new SPSite(sitename))
{
using (SPWeb web = siteColl.OpenWeb())
{
SPList Legal = web.Lists[libname];
SPListItem LegalItem = Legal.GetItemById(itemId);

//SPFieldUserValue oUser = new SPFieldUserValue(web, web.CurrentUser.ID, web.CurrentUser.LoginName);
SPFieldUserValue oUser = new SPFieldUserValue(web, sharePointUserID, UserLoginName);

LegalItem["Author"] = oUser.User.ID;
LegalItem["Editor"] = oUser.User.ID;
LegalItem.Update();

}
}
}

Tuesday, December 2, 2008

Deactivating the Multiple Documents Option for Upload

We had a business requirement to block the "Upload Multiple Documents" Option for the document library. So add "Content Editor Web Part" check the "Hide" under layouts section.
Then add below code under Source Editor and you are done!.

<script type="text/javascript">
function GetElementByText(tagName, title)
{
var a = document.getElementsByTagName(tagName);

for (var i=0; i < a.length; i++)
{
if (a[i].text)
{
if (a[i].text === title)
{
return a[i];
}
}
}
return null;
}

if (window.onload)
{
var oLoad = window.onload;
window.onload = function bodyLoad()
{
oLoad();
var oMenu = GetElementByText("ie:menuitem","Upload Multiple Documents");
if (oMenu )
{
oMenu .disabled = true;
}
}
}

</script>

Note: If you want to deactivate the Upload Document change the var oMenu ;
var oMenu = GetElementByText("ie:menuitem","Upload Documents");

Monday, November 24, 2008

Web Service (Data) Connection & Elevated Permissions

Let's Talk about Dynamically changing the web service's URL before executing and running with Elevated Permissions.

As we know very well by now, grabbing the settings from webconfig allows us seamlessly push code from Dev-QA-Staging-Production, Here I am showing sample code to change the Uri for the webservice as well as running the code with Elevated Privileges. Which allows to executes the specified method with Full Control rights even if the user does not have Full Control.

private void GetUserProfileByNameByChangingURI()
{
WebServiceConnection ws = (WebServiceConnection)this.DataConnections["GetUserProfileByName"];
Uri url = new Uri(ConfigurationManager.AppSettings["UserProfileWS"].ToString());
ws.ServiceUrl = url;
string accountName = "us9\\raja";
XPathNavigator nav = CreateNavigator();
try
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
//Create the Data Source.
XPathNavigator navDataSource = DataSources["GetUserProfileByName"].CreateNavigator();
//Set or Pass The Query Parameter.
navDataSource.SelectSingleNode("/dfs:myFields/dfs:queryFields/s0:GetUserProfileByName/s0:AccountName", NamespaceManager).SetValue(accountName);
//All Set For Execution.
ws.Execute();
nav = navDataSource;
});

//Grab the Results from the Result Set.
XPathNavigator navFirstName = nav.SelectSingleNode("/dfs:myFields/dfs:dataFields/s0:GetUserProfileByNameResponse/s0:GetUserProfileByNameResult/s0:PropertyData[s0:Name='FirstName']/s0:Values/s0:ValueData[1]/s0:Value", NamespaceManager);
string FirstName = navFirstName.Value;
}
catch { }
}

Note:
a. Add the using System.Configuration Name Space to your solution so that you can read the webconfig.
b. Add fallowing key under in web.config file:
<add key="UserProfileWS" value="http://<site>/<_vti_bin/userprofileservice.asmx>/" />

Dynamically Updating Data Connections:

Wondering how to change Data connections dynamically in InfoPath Forms so that you can deploy the solution seamlessly from DEV-QA-Staging-Production.

Here is Sample Code for MainSubmit()

private void MainSubmit(SubmitEventArgs e)
{
bool bSuccessful = false;
try
{
FileSubmitConnection fc = (FileSubmitConnection)this.DataConnections["MainSubmit"];
Uri url = new Uri(ConfigurationManager.AppSettings["Submit"].ToString());
fc.FolderUrl = url.AbsoluteUri;
fc.Execute();
bSuccessful = true;
}
catch
{
System.Diagnostics.EventLog.WriteEntry("MainSubmit", "MainSubmit: Failed to Submit();");
}
// If the submit operation is successful, set
// e.CancelableArgs.Cancel = false;
e.CancelableArgs.Cancel = !bSuccessful;
}

Note:
a. Add the using System.Configuration Name Space to your solution so that you can read the webconfig.
b. Add fallowing key under in web.config file:
<add key="Submit" value="http://<url>/<LibraryName>/" />

Sunday, July 20, 2008

Custom Activity For Windows Workflow

As you know Activity is a unit of work which could be simple or complex. Workflows use all these activities to finish its job, so we can say that Workflow is a collection of activities. In the design mode you see Base Activity Library in tool box those are all core collection of activities that come built in.

Why you need a Custom Activity!? As simple as you want to build once and reuse again and again the object or the way you process the data/flow. Simple Example Writing the status notifications back to DB over and over as the Workflow process moves/jumps the state. Or moving the files around workflow.


How to Build a Custom Activity!? Derive from Base Activity, Override Execute Method and Use Properties if needed. You can also use Dependency Properties.

What is a Dependency Properties!? Unlike normal properties, it won’t take up memory in the instance. It’s more of Centralized storage, Declarative binding at design time and also integrated with Workflow.

Code Snippet for DependencyProperty (<Shortcut>propdp</Shortcut>):
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets
xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
<Title>Define a DependencyProperty</Title>
<Shortcut>propdp</Shortcut>
<Description>
Code snippet for a property using DependencyProperty as the backing store.
</Description>
<Author>Raja Dandu</Author>
</Header>
<Snippet>
<Declarations>
<Literal Editable="true">
<ID>type</ID>
<ToolTip>Property Type</ToolTip>
<Default>int</Default>
<Function>
</Function>
</Literal>
<Literal Editable="true">
<ID>property</ID>
<ToolTip>Property Name</ToolTip>
<Default>MyProperty</Default>
<Function>
</Function>
</Literal>
<Literal Editable="false">
<ID>ownerclass</ID>
<ToolTip>
The owning class of this Property. Typically the class that it is declared in.
</ToolTip>
<Default>ClassNamePlaceholder</Default>
<Function>ClassName()</Function>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[
public $type$ $property$
{
get { return ($type$)GetValue($property$Property); }
set { SetValue($property$Property, value); }
}

//Using a DependencyProperty as the backing store for MyProperty.
//This Enables Animation, Styling, Binding.
public static readonly DependencyProperty $property$Property =
DependencyProperty.Register("$property$", typeof($type$), typeof
($ownerclass$), new UIPropertyMetadata(default($type$)));


$end$]]>

</Code>

</Snippet>

</CodeSnippet>

</CodeSnippets>

Choose the Activity Template in Visual Studio which will give you Design Surface whereby you can drag N drop built in Activities to build Custom Activity or build purely using code which can be active by implementing the “Activity” Interface. Then create your properties if needed and then override the “Execute” Method.

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
try
{
WriteStatus(Source, Connection, Message, Priority);
return ActivityExecutionStatus.Closed;
}
catch (Exception)
{
return ActivityExecutionStatus.Canceling;
}
}
Use the Try catch bolck to trap any failure, If failed return cancel. If needed you can use “componsation” for compensating the halfdone Work/Process.

If successful:
return ActivityExecutionStatus.Closed;

Once you sucessfully build the project Activity calss, Your Custom Activity will apper in yout Main Workflow toolbox.





After creating multiple custom Activities, you can combine them into one single Activity based on your requirement. This Activity called as Composit Activity.