Skip to main content
 
Go Search
Home
Categories
Bloggers
By: Amol Ajgaonkar | Posted: October 19, 2009 at 11:12 AM

To add a button to the ribbon in SharePoint 2010 we use the SPUserCustomAction class.

  1. Get  hold of the SPList object whose ribbon you want to customize.
  2. Access the UserCustomActions property and create a new instance of the SPUserCustomAction class.
  3. Set the appropriate properties of the new instance.
  4. Call update on the SPUserCustomAction instance.

There are different locations where the button will be added depending on the properties being set.

If you don’t set the CommandUIExtension property then the button gets added to the toolbar.

image

If you set the CommandUIExtension property the button shows up on the ribbon. The size of the button depends on the TemplateAlias attribute of the xml.

image

To set the CommandUIExtension property, an xml snippet needs to be created. Here is an example of the xml

<CommandUIExtension>
  <CommandUIDefinitions>
    <CommandUIDefinition
    Location='Ribbon.Library.Actions.Controls._children'>
      <Button Id='Ribbon.Library.Actions.NewRibbonButton'
      Command='NewRibbonButtonCommand'
      Image16by16='/_layouts/images/FILMSTRP.GIF'
      Image32by32='/_layouts/images/PPEOPLE.GIF'
      LabelText='Move Document'
      TemplateAlias='o2' />
    </CommandUIDefinition>
  </CommandUIDefinitions>
  <CommandUIHandlers>
    <CommandUIHandler
    Command='NewRibbonButtonCommand'
    CommandScript='javascript:alert('This is a new button!');' />
  </CommandUIHandlers>
</CommandUIExtension>
 

The TemplateAlias attribute in the xml defines how the button looks on the ribbon. Setting it to “o1” would use the 32x32 icon and setting it to “o2” would use the 16x16 icon.

Here is a code snippet.

 using (SPSite site = new SPSite("http://moss2010base:10522"))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    SPList list = web.Lists["test"];
                    SPUserCustomAction btnCustomRibbon =  list.UserCustomActions.Add();
                    btnCustomRibbon.CommandUIExtension = @"<CommandUIExtension>
  <CommandUIDefinitions>
    <CommandUIDefinition
    Location='Ribbon.Library.Actions.Controls._children'>
      <Button Id='Ribbon.Library.Actions.NewRibbonButton'
      Command='NewRibbonButtonCommand'
      Image16by16='/_layouts/images/FILMSTRP.GIF'
      Image32by32='/_layouts/images/PPEOPLE.GIF'
      LabelText='Move Document'
      TemplateAlias='o2' />
    </CommandUIDefinition>
  </CommandUIDefinitions>
  <CommandUIHandlers>
    <CommandUIHandler
    Command='NewRibbonButtonCommand'
    CommandScript='javascript:alert('This is a new button!');' />
  </CommandUIHandlers>
</CommandUIExtension>";
                    btnCustomRibbon.Name = "MoveDocument";
                    btnCustomRibbon.RegistrationType = SPUserCustomActionRegistrationType.List;
                    btnCustomRibbon.Title = "Move Document";
                    btnCustomRibbon.Location = Microsoft.SharePoint.WebControls.SPRibbon.CustomCommandsId;
                    btnCustomRibbon.Update();
                    list.Update();

                }
            }

The locations strings are defined in the SPRibbon class defined in the Microsoft.SharePoint.WebControls namespace.

This snippet will create the button on the ribbon. I will update the code snippet with a few changes to enhance the code.

By: Amol Ajgaonkar | Posted: October 19, 2009 at 11:09 AM

 

There are different ways of adding your own custom actions to the ribbon in SharePoint 2010. The ribbon is made up of tabs and groups. Each tab consists of Groups. So when we want to add a custom action we need to identify the correct tab and group.

This is referenced by Tab.Group ID.

 

image

1. SharePoint Designer

Using SPD 2010, open the list that you want to customize. You can see the Custom Actions section on the page.

In the Ribbon, click on Quick Step and you will get 5 options to choose from.

image

If you select Edit Form Ribbon, you will see a screen where you can specify the url for the icon, url for the application and the location.

image

If you scroll down,

image

Now if you refresh the list screen in the internet explorer.

image

 

2. Features

To add a button using a feature, create a feature file as specified below.

<?xml version="1.0" encoding="utf-8" ?>
<Feature Id="{a49bc1a4-e324-47fb-bdf2-3441117cd364}"
Title="My Own Action"
Description="Description of the Feature."
Version="1.0.0.0"
Scope="Web"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="manifest.xml" />
</ElementManifests>
</Feature>
Create a manifest file specifying the button and its location.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="Ribbon.ListForm.Edit" Location="ViewToolbar" RegistrationId="100" RegistrationType="List" Title="Add a Button">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition Location="Ribbon.Library.Actions.AddAButton.Controls._children">
          <Button Id="Ribbon.CustomCommands.NewRibbonButton" Command="NewRibbonButtonCommand" Image16by16="/_layouts/images/FILMSTRP.GIF" Image32by32="/_layouts/images/PPEOPLE.GIF" LabelText="New Button" TemplateAlias="o2" />
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler Command="NewRibbonButtonCommand" CommandScript="javascript:alert('This is a new button!');" />
      </CommandUIHandlers>
    </CommandUIExtension>
  </CustomAction>
</Elements>

Install and activate the feature. This will make a button appear on the Toolbar of a list. This approach has been explained in the technical documentation for SharePoint 2010.

 

In my next blog, I have some code snippets to add buttons to the Ribbon using code.

By: Amol Ajgaonkar | Posted: October 19, 2009 at 11:07 AM

Enterprise Content Types and Service Applications are interesting features of SharePoint 2010. Enterprise content types can be used to provide a consistent entity definition to different web applications. Consider an example of a textile company who has implemented an Extranet and an Intranet application.

Their clients can log on to their extranet site and order different products. To add a product the client needs to fill up a form. The form data will be stored in a list on the extranet. The list has an associated content type which defines all the fields that need to be filled in. After the data is filled in, the data is copied from the extranet web application to the intranet web application where the order will be processed.

To make this happen and to maintain it we would have to keep the two content types on the two different web applications in sync, manually. In SharePoint 2010, Enterprise content types would help elevate this problem. In SharePoint 2010, we can define content types in one web application and publish them to subscribing web applications. What this would mean to our textile company is that we could define the content type in the Intranet application and the extranet application could subscribe to it.

Any change in the content type on the Intranet would be published to the extranet application. This would always keep the data model in sync. SharePoint 2010 does this using Metadata service application and timer jobs. The timer job which runs daily and sync’s up the content types. We can either run the timer job when needed or change the frequency.

image image

So how do we set this up?  We need to create a Metadata Service Application and connect both the web applications to it. The meta data service application handles the publishing of content types.

Once you have the metadata service application connected to the web application, we go to the settings of the content type and click on “Manage Publishing for this content type”. Here we can control whether we want to publish/unpublish/republish the content type.

image image

You can check for errors while publishing content types by going to site settings and clicking on “Content type publishing error log”.

image

By: Amol Ajgaonkar | Posted: January 18, 2009 at 10:06 PM

 

Professional Microsoft SharePoint 2007 Development Using Microsoft Silverlight 2

Authors: Steve Fox, Paul Stubbs

A few days back I had the pleasure of interviewing Steve Fox, author of "Professional Microsoft SharePoint 2007 Development Using Microsoft Silverlight 2" . This interview gives an overview of the book and what all will be covered in it.

QBut Tell us a little about yourself?

I am a Sr. Technical Evangelist with Microsoft. I’ve worked in the IT industry for 15 years, 10 of which has been spent here at Microsoft. My main area is Office and SharePoint development, but I’ve also spent time in the areas of search, natural language and developer tools. I enjoy writing, reading, movies, and of course the occasional geek-out with new technology.

Q:  What does the book focus on?

We’re at the beginning of a convergence of two major technologies, Silverlight and SharePoint, and there is not much out there in the way of showing developers how to integrate the two. Thus, this book focuses on integrating Silverlight applications with SharePoint. The book provides a ramp-up approach, from easy to more difficult, and provides walkthrough-style chapters covering what we thought were the major integration areas.

Q:  What audience is this book meant to address?

Developers who have an intermediate understanding of SharePoint and Silverlight and want to learn how to enhance SharePoint with Silverlight. The audience should also be familiar with .NET.

Q:  What topics from the book do you think a SharePoint developer would find interesting?

Hopefully all of them.  Seriously, I think the developer will be most interested in the different types of integrations that are possible. Silverlight is a powerful technology, and when applied to SharePoint it can really take SharePoint to the next level. There are a number of things, such as embedding rich Internet applications in web parts to custom field types to custom navigation, that should really appeal to the developer.

Q:  Do the examples in the book cover Expression Blend and Visual Studio? Which programming language do these examples use? C#?

Where appropriate, we cover some Expression Blend; however, the book is less about design and more for the developer. We primarily use VS 2008 (with VSeWSS 1.2) as our development toolset. We do show examples of Expression and SharePoint Designer as well though. The book has sample code that is expressed in both VB and C#, and we’ve shipped some sample source code along with the book for most chapters.

Q:  How familiar does one need to be with SharePoint to read this book?

I would say you’d want to be at least a little familiar with SharePoint. SharePoint is a very big product that cuts across a few areas. We’ve tried to deal with some of the common artifacts within SharePoint, such as the web part, field type, navigation, and the like.

Q:  In your opinion what are the best practices in consuming SharePoint data in Silverlight Controls? Does the book cover them?

We do cover some of this, yes. For the most part you’re going to be dealing with services when consuming data within SharePoint from a Silverlight control. So, we walk the developer through a couple of scenarios where they are consuming custom data within SharePoint and then using that data within the Silverlight application.

Q:  Does the book explain how to create web parts, Field controls, navigation controls, etc using Silverlight in the form of examples?

Yes, it does.

Q:  Would you like to share the topics that are covered in the book?

Sure. There are eight chapters in the book, which runs just over 300 pages. Each chapter was written in a practical way, so we walk you through how to do each of the integrations we discuss. That said, the eight chapters cover the following:

1. An introduction to Silverlight

2. Building your first SharePoint and Silverlight integration

3. Creating a custom field type using Silverlight

4. Branding your SharePoint site using Silverlight

5. Creating custom web parts using Silverlight

6. Advanced web part topics

7. Data connectivity to SharePoint in Silverlight

8. Overview of an end-to-end SharePoint and Silverlight application

Given the fact that there’s not too much out there today on this subject, I think this book will get developers excited and started on integrating SharePoint and Silverlight. Hopefully, it’s also stimulate some ideas for further integrations.

Q:  Does the book explain how to deploy these Silverlight web parts, controls and the best possible approaches to develop and deploy these solutions?

Yes, we cover some deployment as well. There will be different deployment scenarios depending on the infrastructure/architecture, but we talk about common ways of deploying the applications.


Thank you Steve, for your time. I think this book would really help us understand how we could use Silverlight in SharePoint to enhance the user experience. Looking forward to the release.

By: Amol Ajgaonkar | Posted: December 21, 2008 at 11:06 PM

Last week we came across a very interesting problem. A routine deployment made some of the web parts throw an exception whenever you made a change to its properties and tried to save the changes. This exception was also seen when we tried to add a web part to a page. It was not only for custom web parts but also for OOTB (Out of the box) web parts.

Now what could have possibly happen that would make the OOTB web parts break and throw an exception. Looking into the issue, I found that the culprit was actually the disposable of the SPWeb objects in one of the custom web parts. And since these web parts were on the master page, the exceptions occurred irrespective of the site that user was on.

Here is the code that caused the exception:

   1: SPSite site = SPContext.Current.Site;
   2: SPWeb rootWeb = site.RootWeb;
   3: ...
   4: rootWeb.Dispose();

There is specific condition when you are supposed to dispose it and when you are supposed to leave it alone. The condition is that when the contextual site is the root site then the RootWeb object should not be disposed. As disposing this object implies that the current root web object which is getting shared has been disposed of and thus the web parts which access this property will not get the Root Web SPWeb object and will throw an exception.

So the code needed the following change:

   1: if (!SPContext.Current.Web.IsRootWeb)
   2:     rootWeb.Dispose();

Checking if the current web is the root web and if it is not then only disposing the root web object.

This did the trick. I have read that this happens only when you are on the root site. But in our case it was happening irrespective of the site that the user was on. I believe that this was because the problematic web parts were on the master page.

Share this post :
By: Amol Ajgaonkar | Posted: December 21, 2008 at 11:04 PM

I don't know how or why but sometimes the fields in a content type can get hidden. And you wont get an option of un-hiding the field using the UI. Actually if you try and un-hide the field using the object model, it wont let you. The CanToggleHidden property will be false. And the object model does not allow you to reset this property.

There is a way to reset this property.

The following code uses reflection to invoke the right method and reset the property. After the code executes the field (SPField) can be be made visible.

   1: //field is an object of the class SPField.
   2: Type type = field.GetType();
   3: MethodInfo mi = type.GetMethod("SetFieldBoolValue", BindingFlags.NonPublic | BindingFlags.Instance);
   4: //Invoke the SetFieldBoolValue on the property CanToggleHidden
   5: mi.Invoke(field, new object[] { "CanToggleHidden", true });
   6: //Now the field's Hidden property can be toggled.
   7: field.Hidden = false;
   8: //Update the field.
   9: field.Update(true);

Similarly sometimes there could be a requirement to toggle the CanBeDeleted property on a SPField object. If you cannot do it using the OB then the code below can be used.

   1: // field is an object of SPField class.
   2: if (!field.CanBeDeleted)
   3: {
   4:     Type type = field.GetType();
   5:     MethodInfo mi = type.GetMethod("SetFieldBoolValue", BindingFlags.NonPublic | BindingFlags.Instance);
   6:     //Invoke the SetFieldBoolValue on CanBeDeleted property.
   7:     mi.Invoke(field, new object[] { "CanBeDeleted", true });
   8:     // Now the field can be deleted.
   9: }                                  
  10: field.Delete();
Share this post :
By: Amol Ajgaonkar | Posted: December 21, 2008 at 11:00 PM

I saw some applications making use of the carosel to display their products and that made me think. What if I had a set of products related to each other. Like if I was displaying Vaccum cleaners then clicking on of the vaccum cleaners would show me another carousel which would display different accessories for that vaccum cleaner.

We can architect this by creating different entities.

1. Carousel - This class handles the items in it and rotates them at the set speed.

2. Carousel Controller - The controller is responsible for creating and controlling the carousels in addition to fetching the data and maintaining their relations.

3. Carousel Item - This class defines the object that will rotated in the carousel.

Carousel:

This class will rotate the carousel items clockwise and each item will be clickable. The click event will be captured and a custom event will be invoked so that the subscribers (Carousel controller) will be notified of the click and will swap the current visible carousel with the next related carousel.

To rotate the items we can use the following formula:

Angle is calculated using : Angle = (((2*Math.PI) / (ItemCount)) * currentItemIndex);

Carousel Item's X Co-ordinate = XRADIUS * Math.Cos(angle);
Carousel Item's Y Co-ordinate = YRADIUS * Math.Sin(angle);

image

By changing the XRadius and the YRadius values the rotation path can be changed from a circle to a ellipse.

Now these co-ordinates are in reference to the origin so we scale these co-ordinates so that we get the right values.

X = X + OrigX;

Y = Y + OrigY;

We define an event called ItemSelected which the carousel controller can subscribe to.

 

Carousel Controller:

This class will be responsible for creating the carousel based on the relationships defined by the data source. It will also be responsible for swapping out the carousels.The data can retrieved from a SharePoint list or a database.

Every time the user clicks on an item in the carousel, the carousel invokes an event which the controller captures and runs through the data source to find the related data items. These items are then added to a carousel and this carousel is initialized and activated. This way all related entities can be displayed in a form of a carousel.

The Carousel and the carousel item will be implemented as silverlight user controls. These controls will be self sufficient in how they display what needs to be displayed but its actions will be controlled by the carousel controller.

I intend to blog about the detailed design and implementation once its over. Watch this space to read about the detailed design and implementation details.

Share this post :
By: Amol Ajgaonkar | Posted: September 7, 2008 at 9:15 PM

 

To implement a search UI quickly, we can use the content editor web part to generate the UI.  After you get the UI on track, how do you get the search working.

1. Add the search core results web part to the page.

2. Configure the search core results web part:

image

 

 

 

 

  1.  a) Set the number of results to display.
  2.  b) Set the selected columns that you want to display. These columns are basically managed properties which can be changed/added in the shared service provider. Once you add the columns that you want, they can be rendered using the XSL for the search results web part.
  3.  c). Set the Cross-Web Part Query ID property to “User Query”. This value tells the web part to pick up the search criteria from the query string.

d) Change the XSL, so that it renders the results as you require. I have mentioned an easy way of generating the XSL at the end of this blog.

 

 

 

 

 

 

 

The search results web part works on query string parameters.

1. The parameter “K”: This parameter can be used to specify keyword or any other managed properties that you want to include and search for. For example: if you have a managed property called “StoreLocation”, then you include the following in the value of the K parameter. http://server/pages/default.aspx?k=StoreLocation:Illinois

You could add the keywords to the K parameter in addition to any managed property.

Now that you know what the search results web part expects, all we have to do is to write a small javascript in our Content Editor Web Part which will gather the values from all the controls and generate this query string. Once this query string is generated, add the following statement to the end of the javascript, window.location = window.location.pathname  + strGeneratedQueryString;

This will redirect to the same page with the correct parameters and the search results will come up.

You could add another button to clear the search results, all you have to do on the click event of the button is to clear the query string and redirect to the same page.

window.location = window.location.pathname;

* You will have to write some additional script to make sure the controls in the Content Editor Web Part retain the values that the user has searched for.

 

XSL Generation:

I learnt this technique from one of Patrick Tisseghem’s books. 

1. Edit the XSL from the search core results web part.

2. At the end of XSL, where you find a match for the root element (“/”), add the following statement : <xsl:copy-of select=”*”/>

3. Save and let the search component render.

4. Right click on the page and hit View Source.

5. Locate the XML that is generated by the search results web part.

5. Save this XML as results.XML ( File name is irrelevant)

6. Open Sharepoint Designer, and open any aspx page that you could use for your temporary work.

7. In the data source library, add a new data source for XML. Import the results.xml.

8. Now drop a Data View web part,  and drag and drop the columns from the xml data source that we just defined.

9. You can now edit the xsl as you would for any data view web part. Add grouping, sorting etc.

10. Once your done, go to the source view and copy the XSL style sheet element from the data view web part and paste it in your search results web part xsl editor window.

Now you have a brand new rendering of the search results.

By: Amol Ajgaonkar | Posted: August 17, 2008 at 1:03 PM

 

Handling RichText Fields while saving the form content back to the SharePoint List Item is a little tricky.

blog6

If you try and save the value from this field in the following manner, you won’t see your text in the item.

if (objValue is Microsoft.SharePoint.Publishing.WebControls.RichTextField)
{
    Microsoft.SharePoint.Publishing.WebControls.RichTextField richText = (objValue as Microsoft.SharePoint.Publishing.WebControls.RichTextField);
    item[richText.Field.Title] = richText.Value;
  
}

….

item.Update();

Note: objValue is an object in the SPContext.Current.FormContext.FieldControlCollection. This collection contains all the values for all the fields that are rendered.

If you take a look at the Request.Forms collection you will notice a hidden field which has the actual value that you entered in the Rich textbox. This implies that the RichTextField renders  a hidden field where it stores the value. If you want your code to be dynamic/efficient, you really don’t want to hard code the hidden fields name to access the value.

Digging a little deeper I found out that the value was not getting assigned to the public variable which is generally used to retrieve the value from the control.

The workaround:

Well, I love OOP, so I tend to find the solution in it.

public class MyRichTextField : RichTextField
{
    public MyRichTextField ()  : base()
    { }
    public string TxtValue
    {
        get
        {
            this.OnLoad(new EventArgs());
            return this.textBox.Text;
        }
    }
}

I inherit from RichTextField, create a new property called TxtValue. In the accessor, you call the OnLoad function. This is because the OnLoad function assigns the value of the hidden field to the textBox. We use this so that we don’t have to go after the hidden input field.  Once you have called the OnLoad, the value becomes available in the textbox.Text property and so now all we have to do is return the Text property from the TextBox control.

To use this workaround, while rendering our form, we have to check if the field is a RichTextField and if so, we have to render it using our class rather than the FormField class.

Now to access the value, we change the code a little.

if (objValue is MyRichTextField)
{
    MyRichTextField richText = (objValue as MyRichTextField);
    item[richText.Field.Title] = richText.TxtValue;

}

….

item.Update();

Now the form will save the RichText fields also.

By: Amol Ajgaonkar | Posted: August 13, 2008 at 11:23 AM

 

According to the current implementation you will get an error when you click on Attach File link. I guess most of you have seen this dialog box some time or the other after customizing the edit or new forms for a list.

 

blog5

 

The problem:

The JavaScript is trying to find the element “part1” (which is the ID of the table which has all the field controls) and though we have set the ID of that table to “part1”, the JavaScript does not find the element.

The cause:

Since we have rendered the input table (Table which holds all the field controls) as a server control, the rendered table has the ID which consists of all the container ID’s and then the ID “part1” that we have set.

The ID is in the format ctl0$ctl1$part1 and so the JavaScript does not find the required element.

The solution:

* This solution applies to a custom ASPX page SharePoint list form.

Since you cannot set the ClientID property of the server control, we create a new class inheriting from Table class. In the new class we override the ClientID property and in its accessor we return the value of the ID property.

public override string ClientID
{
    get
    {
        return base.ID;
    }
}

Do the same for the TableRow class.

The next step is to use these classes where ever you are using the Table and TableRow classes. This will ensure that the ID you set in your code, is the ID that is set in the output Html element. But there is an added responsibility while coding, and that is to ensure the ID’s that you set are unique.

This will get rid of that dialog box.

By: Amol Ajgaonkar | Posted: August 12, 2008 at 10:21 PM

 

To develop an edit/new/display form for a SharePoint list we have to implement the following steps:

  1. Get the list.
  2. Get the collection of all the columns
  3. If the form is in EDIT mode, get the item which is being edited.
  4. Render the columns that you want according to your requirements.
  5. Add the Save, Cancel buttons to the form and add the handler to it.

 

The first 3 steps are pretty straightforward. All of this information is available in the query string and SPContext.

The fourth step is interesting, because you have render the right UI component for each column. There are a couple of approaches to doing this.

Depending on the type of each column, you create the control that would go with the column. For example: if the column is a PeoplePicker, then you render a UserField control. If the column is of the type “URL” then you would render a UrlField control and so on…

Here you would write a lot of code to determine what type of control is needed for each column and to render it. A better approach is to use the FormField class.

This class works like a charm. All you have to do is set a few properties on the class and it renders the right UI for you.

The following properties need to be set on FormField class for it to render the control correctly.

  • ListId
  • ItemId ( If in edit mode)
  • ItemContext – This is the current SPContext
  • FieldName – Set the name of the field to render.
  • ControlMode – SPControlMode enumeration.
    • Edit
    • New
    • Display

image

Once these properties are set, add the formField object to your controls collection of your container.

This will render the right UI component for you.  If you need any custom UI elements for your fields, just dont render those fields using the FormField class and add them directly like you would for any other ASPX page.

Part 2 explains how to access the values and handle attachments.

By: Amol Ajgaonkar | Posted: August 12, 2008 at 10:21 PM

 

Accessing the values of the controls is actually very easy. All the controls that you render using the FormField class are collected and stored in a collection. This collection resides in the current FormContext.

To access the collection use the following statement:  SPContext.Current.FormContext.FieldControlCollection

This collection has all the fields that were rendered using the FormField class. The FormField class when instantiated registers itself in the FieldControl collection.

Toolbar and Attachments:

To make the UI look as close to the Out-Of-The-Box (OOTB)  form, you might want to use the FormToolBar class. This will render the form tool bar.

To use the OOTB attachments functionality, there are few things that you need to do.

1. ID of your Field control table should be “part1”

2. Write a small javascript which will hide the element with the id “idAttachmentsTable” on page load.

 

blog1

 

The javascript should hide the following component which is displayed when the user clicks “Attach File”.

blog2

 

To complete the functionality we have to implement two actions:

1. Adding a new Attachment to the item.

2. Deleting attachments from the item.

The posted files collection is stored in the Request.Files collection. Here is a code snapshot that could be used to add the posted files to the attachments collection of an item.

blog3

To delete the attachments from the server, we have to get hold of all the GUIDS of files which the user have marked for deletion. They are stored in a form variable called “attachmentsToBeRemovedFromServer”.

This variable has the list of UniqueId’s seperated by semicolon. The question now is how to delete an attachment based on just its guid. The trick is to get hold of the sub folder which contains all the attachments.

if (_currentList.RootFolder.SubFolders.Count > 0)
           {
               if (_currentList.RootFolder.SubFolders[“Attachments”] != null)
               {
                   SPFolder itemFolder = _currentList.RootFolder.SubFolders[“Attachments”];
                   if (itemFolder.SubFolders[_currentItem.ID.ToString()] != null)
                       return itemFolder.SubFolders[_currentItem.ID.ToString()].Files;
               }
           }

Once you get the file collection just iterate over and compare the UniqueID property with the ID’s that you get from the form variable.

If there is a match, just call Delete on the file object.

*Delete the attachments after you have called update on the item to save the other field values, else you will get a save conflict error.

The next part will explain some workarounds for  attachment errors that you might see and how to access values for fields like RichHtml.

By: Amol Ajgaonkar | Posted: July 27, 2008 at 11:07 PM

 

Often we need to add more tabs to the global navigation of a MySite. By default, you get to see "My Site" and "My Profile" and even if you add more links using the Top Link Bar tool in Settings page, they wont show up in the Top navigation.This is because the provider specified in the web.config for the MySites Navigation ignores the Global navigation nodes specified by the user.

 

This is the provider for the mySites in the web.config.

<add name="MySiteMapProvider" description="MySite provider that returns areas and based on the current user context" type="Microsoft.SharePoint.Portal.MySiteMapProvider, Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

 

Just change this to the provider which is used to pull in data for the top navigation of your Publishing Site -  "GlobalNavSiteMapProvider".

This is how your changed entry will look like:

<add name="MySiteMapProvider" description="" type="Microsoft.SharePoint.Publishing.Navigation.PortalSiteMapProvider, Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" NavigationType="Global" EncodeOutput="true" />

This will now look for links that the user has entered using the Top Link Bar tool in the settings page. (http://moss/personal/administrator/_layouts/topnav.aspx) and display them in the global navigation.

These links though wont show up when user's profile (http://moss/MySite/Person.aspx?accountname=MOSS\Administrator) is accessed by some other user. My colleague, Bob and I worked on this and found a solution to this using which you don't have to modify OOTB files and still have the tabs displayed when accessing profile's other than yours.

Here is a link to Bob's Blog. He will blog about it soon.

By: Amol Ajgaonkar | Posted: February 16, 2008 at 7:12 PM

Sometimes when you delete a column from a list, it does not get deleted completely. If this happens, you don't see the column in the list settings, but if you try and create a column with the same name, Sharepoint throws an error saying that a column already exists with that name.

If you try and add a site column to the list, it creates the column in the list with the Display name as what is required, but the internal column name is the column name + 0

e.g region0, budget0

 

To delete this column, I have written a small utility which goes over all the columns and prompts the user if they want to delete the column. When you use the OM to list out all the columns you will find the column that you deleted in fact exists.

 

I will post the utility in a short while.

But  in brief the overall steps are:

  1. Get the fields collection
  2. Get the required field
  3. Set the AllowDeletion property to True
  4. Update the list.
  5. Now go over the fields collection again.
  6. Get the required field
  7. Delete the field.
By: Amol Ajgaonkar | Posted: February 16, 2008 at 10:45 AM

 

If you want to try and modify the Display Form of a document library using SPD, you should be aware of the following problems:

  1. Deleting the existing web part on the page and adding new content might break the document library. (When you click on View Properties of an item, it redirects the user to the root site)
  2. Modifying the existing web part, might work but it could break the edit forms functionality.

To understand what is breaking the document library, do the following:

  1. Change the display form.This is most probably going to break the DisplayForm functionality.
  2. If it does, save the document library as a template.
  3. Download the template and rename the file as [name].cab
  4. Open up the schema.xml and find  the "Forms" tag.
  5. Here you will notice that the URL for the DisplayForm is missing. This is why the user is redirected to the root site.

Some how, SPD, while saving the document library, does not save the DisplayForm URL correctly.

 

The workaround I have  found to this is to hide the existing content in the Dispform.aspx and add your own content to the form. By not deleting the existing webparts and not creating a new aspx file, it works fine.

By: Amol Ajgaonkar | Posted: October 22, 2007 at 4:45 PM

Dynamic controls & Post back Problem: Managing an array of Controls.

 

Problem:

When you create an array of controls dynamically there are chances that you would notice the following behavior:

1.       When you click on one of the controls a post back will be triggered for some other control in the array of controls.

2.       When you click on the same control again then the post back will occur for the selected/clicked control.

Reason:

When a web request is received, a series of objects are created by the ASP.NET framework. The control hierarchy is again built up from scratch. Each control is assigned a unique client ID by the framework. Since each click on the control will trigger a post back (Request), there is a possibility that the each control in the array of controls will get a different  Client ID assigned to them when they are rendered. This implies that the control’s client ID in the post back request might actually be assigned to some other control and thus invoking a different event handler or executing a different path of code.

Solution:

The solution is simple, to pin down the Client ID of the controls while creating them. Simply assign a unique client ID to each of the controls in the array while creating them.

For example:

for(int iControlIndex =0; iControlIndex < iArrayLength; iControlIndex++)

{

                oControlArray[iControlIndex] = new ….

                oControlArray[iControlIndex].ClientID = “YourUniqueName_” + iControlIndex;

}

 

By: Amol Ajgaonkar | Posted: July 16, 2007 at 9:26 AM
 
 
To add an item to the Welcome menu in MOSS.
 
Create a feature.
 
Feature xml should like:
 
<?xml version="1.0" encoding="utf-8"?>
<Feature Id="GUID"
    Title="Welcome menu Item"
    Description=""
    Version="1.0.0.0"
    Scope="Site"
    xmlns="http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest Location="elements.xml"/>
  </ElementManifests>
</Feature>
 
Elements.xml should look like:
 
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="PersonalActionsMenu_UniqueName"
    GroupId="PersonalActions"
    Location="Microsoft.SharePoint.StandardMenu"
    Sequence="101"
    Title="YOUR TITLE "
    Description="DESCRIPTION"
    ImageUrl="YourImageURL">
    <UrlAction Url="YOUR_URL"/>
  </CustomAction>
</Elements>
 
Now use stsadm to install and activate the feature.
 
Voila!
 
The location attribute of CustomAction element is the key for the item to show up. If you have filled up the xml correctly, then you should be able to see the menu rendered correctly.
By: Amol Ajgaonkar | Posted: April 26, 2007 at 11:52 AM
Scenario: Workflow is waiting on the OnItemChanged event of a SP list. We need to update the same item from the workflow.
 
Solution:
Do not use the Update method of SPListItem. This will surely make the workflow go into recursion.
 
Instead add a CallExternalMethod Activity.
Select the interface type as IListItemService
Method : UpdateListItem
 
Bind the following properties:
1. ListId : Bind to the workflowproperties.ListID
2. ItemId : Bind to the workflowproperties.ItemID
3. Id. : To a new GUID
4. itemProperties: This is an important property. This property holds the Column,Value pair that needs to be updated.
 
Once you bind the itemProperties to a field, you can add columns and the their values like any other ArrayList/Dictionary.
 
Once this activity executes the list item gets updated.
 
NOTE: This solution does sometime make the workflow go into recursion. But this recursive behaviour is not consistent.
By: Amol Ajgaonkar | Posted: April 26, 2007 at 11:49 AM

Assume you have mapped a URL to a Sharepoint Site and are accessing the site from the extranet. This sharepoint site gets accessed locally from a port other than 80.
If you develop a custom aspx page then you would generally put the page in the _layouts folder and the dll in the Bin folder of the Site:port Virtual directory.
The page would work fine if the user accesses the site from the Intranet using the local url i.e http://site:port

But try accessing the page using the mapped URL. It wont work.

What I had to do was to put the Dll of custom page in the Bin directory of site at port 80. This got the page working.

By: Amol Ajgaonkar | Posted: April 26, 2007 at 11:46 AM

To catch the onItemChanged event of any Sharepoint list in a workflow, the following needs to be done:

  • Add a CallExternalMethod Activity, set the interface to Microsoft.SharePoint.Workflow.IListItemService
  • Set the method name to InitializeForEvents
  • Bind the ItemId, ListId to ItemID and ListId in the workflow properties.
  • Add a HandleExternalEvent activity and specify the following properties:
    InterfaceType to Microsoft.SharePoint.Workflow.IListItemService
    Event Name : OnItemChanged
    NOTE: The correlationToken should be the same as the correlation token specified for CallExternalMethod activity.
    Method Name. This method will be called whenever there is a change in the list item.
  • Bind the ID property to a field. Initialize this field to a new GUID.
  • This will capture the onItemChanged event.

By: Aaron Steele | Posted: September 5, 2006 at 12:17 AM

Before I start with my articles, I would like to explain why I have named my blog as Axon.

  The nervous system consists of a large number of cells, called neurons. Each neuron has numerous extensions called dendrites. These extensions receive chemical signals from other neurons. An Axon is a little different from dendrites. It is responsible for transmitting signals to other neurons over considerable distance.

Now compare this with our work environment. Each individual is a processing unit, a potential neuron. And each blog of his can be considered as an Axon which propogates his knowledge, views, information to other neurons.... ( other individuals).

 

 About

 [more]

 Tag Cloud

 External Links