Thursday, July 31, 2008
Life is what happens to you when you are busy making plans
This not only applies to one's personal schedule, but generates a ripple effect, bringing in unplanned change in peoples lives. This unplanned change which influence people directly or indirectly is what I call "controlled chaos". At times, I get amazed as I see, how changes in my life, make other people alter their plans. By people, I not only mean people who are close to me, but also those who I do not interact with in day-to-day basis.
Lets just say, I recent time, I planned out something for myself. From no where came 'a change' which forced me to deviate from my well planned activity and alter my path. Am at my wits end, when I start to think, would have I walked on planned path all the way if that change haven't come by, or has it given me an excuse to console myself with.
One of my close friend, had an accident recently (I pray he recuperate soon). Call it chance, it so happens, the day he received offer letter from his favorite company, the very same night it happened. He was going through a rough phase and was in need of that job desperately. My entire group, was on the hunt for him. Seems to me fate had other plans. Its ironic to see, how a sudden change can make your life go topsy-turvy .
DataForm WebPart [escape from hardcoded List GUIDs]
SharePoint Designer is undoubtedly, an impeccable tool when it comes to quick and dirty UI creation. Quick drag and drop approach of Lists/Libraries allow easy readable access at UI level. However it has certain limitations. For say, we created a new page and added new DataForm webpart using drag and drop in our development environment. Once our development is complete, it is required to move changes to staging environment. So, as a developer I have numerous options to achieve this by using feature deployment, wsp deployment or simply move aspx page to target Site Collection. Doing so, I see my page containing DataForm webpart does not work.
This is due to the fact that, by default, SharePointDesigner binds the control to the list instance using the list instance GUID. To resolve this we need to replace the GUIDs by the list name. The steps to do this are:
1) On the attributes of the DataFormWebPart element replace the attribute ListName="{GUID}" by ListName="LIST_NAME" where LIST_NAME is the name of the list that you are binding to.
2) Go through all of the DataFormParameter elements and replace:
<WebPartPages:
With:
<WebPartPages:
3) Go to the ParameterBindings element and replace
<ParameterBinding Name="ListID" Location="None" DefaultValue="{GUID}"/>
With:
<ParameterBinding Name="ListName" Location="None" DefaultValue="LIST_NAME"/>
This should give you a GUID free DataForm webpart that can be placed on a page layout used by multiple sites on your site collection (as long as the name of the list is the same on all sites).
Cheers
Disposing SharePoint site and web objects
There are several different ways of retrieving an SPWeb object.
Take the following 3 examples:
1) SPContext
SPWeb web = SPContext.Current.Web
2) OpenWeb
SPSite site = new Site("http://myserver/");
SPWeb web = site.OpenWeb("");
3) Site "RootWeb"
SPSite site = new Site("http://myserver/");
SPWeb web = site.RootWeb;
Thumb rule:
- Never dispose SPContext.Current.Web or SPSite.RootWeb
- Make sure you dispose of [OpenWeb("")] objects and [new Site("")/new Web("")] objects
As for [OpenWeb("")] and [new Site("")/new Web("")]objects, if not disposed, applies heavy penalty on system memory.
Hope this helps.
Cheers
Customising Sharepoint Alerts (SPAlert)
Alerts[Info: MSDN SPAlert] can be created based on context of a SPWeb or of SPUser. Take a look at the snipped below.
From SharePoint User
SPAlert user = //fetch SPUser
SPAlert alert = user.Alerts.Add();
From SharePoint Web
SPWeb web = //fetch web
SPAlert alert = web.Alerts.Add();
Bare in mind alerts are user/group centric. When an alerts is created based on web alert object does not have user associated to it. It is imperative that we supply SPUser object. Code below does exactly that.
alert.User = user;
There are other properties one can associate with alters, such as,
* frequency of alters
* alert template
* alert type [based on List or ListItem]
- Custom
- List
- Item
- Add
- All
- Delete
- Discussion
- Modify
Filters is one tricky part when comes CAML. CAML can easily be generated using tools such as
* CAML Viewer [Links]
* CAML builder [Links]
CAML generated by these tools include "Query" and "Where" XML element tags, which in my opinion makes perfect sense. As it turns out these tags do not play well when passed in to alert.Filters properties. Remove these tags and pass the inner content and it works like a charm.
Take a look at the code below.
alert.Filter = "<Eq><FieldRef Name=\"ContentType\"/><Value type=\"string\">" + "Item" + "</Value></Eq>";
What we are doing here is applying filters on Field Type "ContentType" having value "Item".
Code Dump
[Code]
SPSite site = null;
SPWeb web = null;
try
{
site = new SPSite("http://server/");
web = site.RootWeb;
web.AllowUnsafeUpdates = true;
SPList list = web.Lists["TestList"];
foreach (SPUser user in web.SiteUsers)
{
if (user.Name.ToUpper().Contains("user name"))
{
SPAlert alert = user.Alerts.Add();
alert.Filter = "<Eq><FieldRef Name=\"ContentType\"/><Value type=\"string\">" + "Item" + "</Value></Eq>";
alert.Title = "My Alert";
alert.AlertType = SPAlertType.List;
alert.EventType = SPEventType.All;
alert.List = list;
alert.AlertFrequency = SPAlertFrequency.Immediate;
alert.AlwaysNotify = true;
alert.Update(true);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine("================");
Console.WriteLine(ex.Source);
Console.WriteLine("================");
Console.WriteLine(ex.StackTrace);
}
finally
{
if (site != null)
site.Dispose();
if (web != null)
web.Dispose();
}
[/Code]
Make sure you dispose of site & web objects, if not a heavy penatly will be applied on memory usage.
Alternatively, if you are using SPContext to get site and web object do not dispose then
Hope this helps.
Cheers
Wednesday, July 30, 2008
Custom WebPart connections and Custom WebPart Properties
[WebBrowsable(true)]
[Personalizable(false)]
[WebPartStorage(Storage.Shared)]
[WebDisplayName("User Name(Domain\\username)")]
[WebDescription("User to display in the WebPart.")]
[SPWebCategoryName("Options")]
Creating a custom WebPart connection is quiet easy. Simply follow the steps below:
a) Create an interface IStringConnection
public interface IStringConnection
{
string ProvidedString { get; }
}
b) Implement System.Web.UI.WebControls.WebParts.WebPart and IStringConnection in connection provider webpart
[ConnectionProvider("String Provider")]
public IStringConnection ConnectionInterface()
{
return this;
}
public string ProvidedString
{
get { return m_string; }
}
c) On connection receiver webpart add following code
IStringConnection m_providerPart = null;
[ConnectionConsumer("String Consumer")]
public void GetConnectionInterface(IStringConnection providerPart)
{
m_providerPart = providerPart;
}
=> However, this technique will not allow you to connect to default/out-of-box lists and libraries. For that, one needs to implement IwebPartField, IWebPartRow, and IWebPartTable on receiver webpart.
That's about it.
Snippet below adds a textbox to Web Part propery view.
// Assign the default value.
[DefaultValue(c_MyStringDefault)]
// Property is available in both Personalization
// and Customization mode.
[WebPartStorage(Storage.Personal)]
// The caption that appears in the property sheet.
[FriendlyNameAttribute("Custom String")]
// The tool tip that appears when pausing the mouse pointer over the friendly name in the property pane.
[Description("Type a string value.")]
// Display the property in the property pane.
[Browsable(true)]
[XmlElement(ElementName="MyString")]
// The accessor for this property.
public string MyString
{
get
{
return _myString;
}
set
{
_myString = value;
}
}
Hope this helps!!