Adding Drop-Down Menu Items to SPGridView Using SPMenuField Control

http://sharepointmalaya.blogspot.com/2009/07/adding-drop-down-menu-items-to.html

protected override void CreateChildControls()
{
    // Why UseDefaultStyles = false?
    // See http://sharepointmalaya.blogspot.com/2009/07/how-to-make-spgridview-to-have-same.html for details
    this.UseDefaultStyles = false;

    // ObjectDataSource
    ObjectDataSource dataSource = new ObjectDataSource();
    dataSource.ID = “dataSource”;
    dataSource.SelectMethod = “SelectData”;
    dataSource.TypeName = this.GetType().AssemblyQualifiedName;
    dataSource.ObjectCreating += new ObjectDataSourceObjectEventHandler(objectCreating);
    this.Controls.Add(dataSource);

    // SPGridView
    spGridView = new SPGridView();
    spGridView.ID = “spGridView”;
    spGridView.DataSourceID = dataSource.ID;
    spGridView.AutoGenerateColumns = false;
    spGridView.AllowPaging = true;
    spGridView.PageSize = 10;
    spGridView.AllowSorting = true;
    spGridView.EmptyDataText = string.Empty;
    this.Controls.Add(spGridView);

    // SPGridViewPager
    pager = new SPGridViewPager();
    pager.GridViewId = spGridView.ID;
    this.Controls.Add(pager);

    // SPMenuField – Name field
    SPMenuField nameCol1 = new SPMenuField();
    nameCol1.HeaderText = “Name”;
    nameCol1.TextFields = “Name”;
    nameCol1.NavigateUrlFields = “Name,Email,WebSite”;
    nameCol1.NavigateUrlFormat = “/_layouts/sharepointmalaya/DispDetails.aspx?WebPartID=” + this.ID + “&FilterName={0}&ReturnUrl=” + Page.Request.Url.ToString();
    nameCol1.TokenNameAndValueFields = “KEYNAME=Name,KEYEMAIL=Email,KEYWEBSITE=WebSite”;
    nameCol1.SortExpression = “Name”;
    nameCol1.MenuTemplateId = “menuTemplate”;

    // MenuTemplate
    MenuTemplate menuTemplate = new MenuTemplate();
    menuTemplate.ID = “menuTemplate”;
    this.Controls.Add(menuTemplate);
    spGridView.Columns.Add(nameCol1);

    // MenuTemplate – View Item
    MenuItemTemplate menuItemTemplate0 = new MenuItemTemplate(“View Item”, “~/_layouts/images/LIST.GIF”);
    menuItemTemplate0.ClientOnClickNavigateUrl = “/_layouts/sharepointmalaya/DispDetails.aspx?WebPartID=” + this.ID + “&FilterName={%KEYNAME%}&ReturnUrl=” + Page.Request.Url.ToString();
    menuTemplate.Controls.Add(menuItemTemplate0);

    // MenuTemplate – Seperator
    MenuSeparatorTemplate menuSepTemplate = new MenuSeparatorTemplate();
    menuTemplate.Controls.Add(menuSepTemplate);

    // MenuTemplate – Open WebSite
    MenuItemTemplate menuItemTemplate1 = new MenuItemTemplate(“Open WebSite”, “~/_layouts/images/ASP16.GIF”);
    menuItemTemplate1.ClientOnClickNavigateUrl = “javascript:window.open(‘%KEYWEBSITE%’);”;
    menuTemplate.Controls.Add(menuItemTemplate1);

    // MenuTemplate – Send Email
    MenuItemTemplate menuItemTemplate2 = new MenuItemTemplate(“Send Email”, “~/_layouts/images/EML16.GIF”);
    menuItemTemplate2.ClientOnClickScript = “javascript:document.location.href=’MailTo:%KEYEMAIL%;'”;
    menuTemplate.Controls.Add(menuItemTemplate2);

    // BoundField – Email field
    BoundField nameCol2 = new BoundField();
    nameCol2.DataField = “Email”;
    nameCol2.SortExpression = “Email”;
    nameCol2.HeaderText = “Email”;
    spGridView.Columns.Add(nameCol2);

    // BoundField – WebSite field
    BoundField nameCol3 = new BoundField();
    nameCol3.DataField = “WebSite”;
    nameCol3.SortExpression = “WebSite”;
    nameCol3.HeaderText = “WebSite”;
    spGridView.Columns.Add(nameCol3);

    this.ChildControlsCreated = true;
}

  • Code above create three (3) drop-down menu items and a separator menu as shown below:

image

Creating Custom Workflow Activities for SharePoint Server 2007 Using Visual Studio 2008

http://msdn.microsoft.com/en-us/library/cc627284.aspx

 
OverviewIn Microsoft Visual Studio 2008, you can create custom activities that can be consumed in workflows. Creating custom activities lets you encapsulate business logic that applies to different scenarios and that can be used in different workflows. This Microsoft Office Visual How To demonstrates how to create a custom activity to send an e-mail message with an attachment.

Code ItFirst, you must create your custom activity. Then, you can add that to a workflow project and use it to send an e-mail message with an attachment.

Creating a Custom Activity Project

First, create a Visual Studio 2008 Workflow Activity Library project.

To create a Visual Studio 2008 Workflow Activity Library project

  1. Open Visual Studio 2008.
  2. On the File menu, point to New, and then click Project.
  3. Under the Workflow Project Type, select the Workflow Activity Library project template.
  4. In the Name box, type SendMailWithAttachmentActivity, and then click OK.
  5. Rename Activity1 to SendMailWithAttachmentActivity.

Coding Custom Activity

Now that you have a Custom Activity project, you must add code to send an e-mail message with an attachment.

To add code to send an e-mail message with an attachment

  1. The first thing you must do is change your class declaration to inherit directly from Activity instead of SequenceActivity.

    Open your activity in code view, and change SequenceActivity to Activity. Your class definition should look like the following.

    public partial class SendMailWithAttachmentActivity : Activity
    { …

  2. Now you must create some Dependency Properties. Add the following fields inside your class definition.

        public static DependencyProperty ToProperty 
          = DependencyProperty.Register(
              "To", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty FromProperty 
          = DependencyProperty.Register(
              "From", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty CCProperty 
          = DependencyProperty.Register(
              "CC", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty SubjectProperty 
          = DependencyProperty.Register(
              "Subject", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty BodyProperty 
          = DependencyProperty.Register(
              "Body", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty AttachmentProperty 
          = DependencyProperty.Register(
              "Attachment", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty SmtpServerProperty 
          = DependencyProperty.Register(
              "SmtpServer", typeof(string), typeof(SendMailWithAttachmentsTest));
    
        public static DependencyProperty InvokeEvent 
          = DependencyProperty.Register(
              "Invoke", typeof(EventHandler), typeof(SendMailWithAttachmentsTest));

    Notice that the last field, InvokeEvent, is of type EventHandler. This enables you to add custom code to your activity when it is used in a workflow.

  3. Now, you must add properties for your fields. Add the following code under the fields you just added.

       [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
         [ValidationOption(ValidationOption.Required)]
         [Browsable(true)]
         [Description("Enter any e-mail recipients, separated by semicolons")]
         public string To
         {
            get { return ((string)(base.GetValue(SendMailWithAttachmentsTest.ToProperty))); }
            set { base.SetValue(SendMailWithAttachmentsTest.ToProperty, value); }
         }
    
          [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
         [ValidationOption(ValidationOption.Required)]
         [Browsable(true)]
         [Description("Enter the e-mail sender")]
         public string From
         {
            get { return ((string)(base.GetValue(SendMailWithAttachmentsTest.FromProperty))); }
            set { base.SetValue(SendMailWithAttachmentsTest.FromProperty, value); }
         }
    
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Optional)]
        [Browsable(true)]
        [Description("Enter any carbon copy recipients, separated by semicolons")]
        public string CC
        {
           get { return ((string)(base.GetValue(SendMailWithAttachmentsTest.CCProperty))); }
           set { base.SetValue(SendMailWithAttachmentsTest.CCProperty, value); }
        }
    
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Required)]
        [Browsable(true)]
        [Description("Enter the e-mail subject")]
        public string Subject
        {
           get { return ((string)(base.GetValue(SendMailWithAttachmentsTest.SubjectProperty))); }
           set { base.SetValue(SendMailWithAttachmentsTest.SubjectProperty, value); }
        }
    
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
         [ValidationOption(ValidationOption.Optional)]
         [Browsable(true)]
         [Description("Enter the body text of the e-mail")]
         public string Body
         {
            get { return ((string)(base.GetValue(SendMailWithAttachmentsTest.BodyProperty))); }
            set { base.SetValue(SendMailWithAttachmentsTest.BodyProperty, value); }
         }
    
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
         [ValidationOption(ValidationOption.Optional)]
         [Browsable(true)]
         [Description("Enter an attachment file path")]
         public string Attachment
         {
            get { return ((string)(base.GetValue
              (SendMailWithAttachmentsTest.AttachmentProperty))); }
            set { base.SetValue(SendMailWithAttachmentsTest.AttachmentProperty, value); }
         }
    
         [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
         [ValidationOption(ValidationOption.Required)]
         [Browsable(true)]
         [Description("Enter the Smtp Server for the email")]
         [DisplayName("Smtp Server")]
         public string SmtpServer
         {
            get { return ((string)(base.GetValue
              (SendMailWithAttachmentsTest.SmtpServerProperty))); }
            set { base.SetValue(SendMailWithAttachmentsTest.SmtpServerProperty, value); }
         }

  4. Now, you must add a property for your InvokeEvent field. This EventHandler property lets you add code in a workflow to interact with this activity programmatically. Add this code under the Properties you just added.

       [DescriptionAttribute("Invoke")]
       [CategoryAttribute("Invoke Category")]
       [BrowsableAttribute(true)]
    [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
       public event EventHandler Invoke
       {
          add
          {
             base.AddHandler(SendMailWithAttachmentsTest.InvokeEvent, value);
          }
          remove
          {
             base.RemoveHandler(SendMailWithAttachmentsTest.InvokeEvent, value);
          }
       }

  5. Add a using statement at the top of the class. This enables you to access the ASP.NET 2.0 Mail namespace for sending your e-mail message. Add the following code.

    using System.Net.Mail;

  6. The last thing you must do here is override the Execute method. Add the following method inside your class definition.

        Protected override ActivityExecutionStatus 
          Execute(ActivityExecutionContext executionContext)
        {
            // Raise Invoke Event to execute custom code in the workflow.
            this.RaiseEvent(SendMailWithAttachmentsTest.InvokeEvent, 
              this, EventArgs.Empty);
    
            // Set reference to Smtp Server.
            SmtpClient smtp = new SmtpClient(SmtpServer);
    
            // Create mail message.
            MailMessage msg = new MailMessage();
            msg.To.Add(To);
            msg.From = new MailAddress(From);
            if (!String.IsNullOrEmpty(CC))
            {
                msg.CC.Add(CC);
            }
            if (!String.IsNullOrEmpty(Subject))
            {
                msg.Subject = Subject;
            }
            if (!String.IsNullOrEmpty(Body))
            {
                msg.Body = Body;
            }
            if (!String.IsNullOrEmpty(Attachment))
            {
                msg.Attachments.Add(new Attachment(Attachment));
            }
    
            // Send the e-mail.
            smtp.Send(msg);
    
            // Indicate that the activity has completed.
            return ActivityExecutionStatus.Closed;
    }

Installing a Custom Activity

Before you can use your custom activity, you must install it in the global assembly cache (GAC). For an assembly to be installed in the GAC, you must give it a strong name.

To install the custom activity to the GAC

  1. First, give your assembly a strong name. In Solution Explorer, right-click the project, and then select Properties.
  2. Select the Signing tab.
  3. Select the Sign the assembly check box.
  4. In the Choose a strong name key file list, select New.
  5. In the Key file name text box, type Key.
  6. In this demonstration, we are not concerned with security, so clear the Protect my key file with a password check box. Click OK.

    Now your assembly is strong named, and all you have to do is install it to the global assembly cache.

  7. Save and build the project.
  8. Open a Visual Studio 2008 command prompt.
  9. Navigate to the Activity solution directory, and run the following command:

    gacutil /if SendMailWithAttachmentActivity.dll

Now, that you have successfully installed your activity, you can use it from a workflow project.

Creating a Workflow Project

Next, you create a Sequential Workflow project to use your custom activity.

To create a Visual Studio 2008 Sequential Workflow project

  1. Start Visual Studio 2008.
  2. On the File menu, point to New, and then click Project.
  3. Under the Office Project Type, select the SharePoint 2007 Sequential Workflow project template.
  4. In the Name box, type SendEmailWithAttachmentWF. Click OK.
  5. Type a valid SharePoint Web URL. The example uses http://moss.litware.com. Click Next.
  6. Select a library or list to associate with your workflow, and click Next.
  7. Leave the default options for how a workflow can be started, Manually by users and When an Item is created. Click Finish.

Adding a Custom Activity to the Toolbox

Now that you have created your Sequential Workflow project, you must add your custom activity to your Toolbox before you can use it.

To add the custom activity to the Visual Studio 2008 Toolbox

  1. On the Tools menu, select Toolbox items.
  2. Select the Activities tab.
  3. Click Browse, and browse to the SendMailWithAttachmentActivity.dll in your Activity solution directory. Click Open.
  4. Click OK.
  5. Your activity is now available in the Toolbox.

    Figure 1. Toolbox with new activity available

    Toolbox with activity available

    Note Note:

    If you have a toolbox category selected, the activity is added to that category by default. You can drag the activity to another category if you want.

Adding a Custom Activity to the Workflow

Now, you must add your custom activity to your simple workflow.

To add the custom activity to the workflow

  1. From the Toolbox, drag the SendMailWithAttachmentActivity to be under the onWorkflowActivated1 activity.
  2. Open the Properties window, and rename it to sendMailWithAttachmentActivity.
  3. You can set the activity properties from within the Properties window. Instead, you will do that in code. Select the Event view in the Properties window.
  4. You should see a single event, Invoke. Double-click this property.

    Figure 2. Properties window

    Properties window 

    This takes you to the code-behind class, and you will see that a method stub has been auto-generated for you.

  5. Add the following code inside this method.

        SendMailWithAttachmentActivity.To = "nicolec@litwareinc.com";
        SendMailWithAttachmentActivity.From = "willisj@litwareinc.com";
        SendMailWithAttachmentActivity.CC = "willisj@litwareinc.com";
        SendMailWithAttachmentActivity.Subject = "Email with Attachment Testing.";
        SendMailWithAttachmentActivity.Body = "This email should have an attachment.";
        SendMailWithAttachmentActivity.Attachment 
          = @"C:\Documents and Settings\Administrator\Desktop\code snippets.txt"; 
    
        SendMailWithAttachmentActivity.SmtpServer = 
          workflowProperties.Site.WebApplication.OutboundMailServiceInstance.Server.Address;

  6.  
Note Note:

The purpose of this demonstration is to show you how to create and consume a custom activity. In a real-world scenario, you would never hard-code these values. You would retrieve them programmatically, or possibly through an Initiation form or a Task form.

Running the Workflow Project from Visual Studio 2008

Press F5 to run your workflow. When you activate this workflow on a document in a document library, an e-mail message is generated and sent with the attachment you specified.

Figure 3. E-mail message with attachment

E-mail with attachment

Using SPCalendarView to show items in a calendar

http://www.tonstegeman.com/Blog/Lists/Posts/Post.aspx?List=70640fe5%2D28d9%2D464f%2Db1c9%2D91e07c8f7e47&ID=60

In the new version of the Content By Type webpart, I added the option to rollup items into a calendar. In a later post I will describe how you can do that using the webpart. In this post I will show you how I did it in the code. When you start it all seems very easy, but there were a few things that caused me some headaches. I hope you don’t run into them as well after reading this item.

Step 1 – Setting up the controls

I implemented all the calendar specific code in a special control:

public class SharePointCalendar : Control

In the CreateChildControls of my webpart, I just add this control to the collection:

protected override void CreateChildControls()
{
    base.CreateChildControls();
    SharePointCalendar calendar = new SharePointCalendar();
    Controls.Add(calendar);
}

In the CreateChildControls of my SharePointCalendar class, I setup the SPCalendarView and add it to the controls collection:

private SPCalendarView _view;

/// <summary>
/// Create the SharePoint calendar. Uses the SharePoint SPCalendarView object.
/// </summary>
protected override void CreateChildControls()
{
    base.CreateChildControls();
    _view = new SPCalendarView();
    _view.EnableViewState = true;
    _view.Width = Unit.Percentage(100);
    _view.DataSource = GetCalendarItems();
    DataBind();
    Controls.Add(_view);
}

You can find SPCalendarView in the Microsoft.SharePoint.WebControls namespace.

Step 2 – Adding data and testing

The data that will be displayed in the calendar is loaded in GetCalendarItems. In this case it is dummy data, but you will get the idea:

private SPCalendarItemCollection GetCalendarItems()
{
    // Create a new collection for the calendar items
    // This is an item with a start and end date.
    SPCalendarItemCollection items = new SPCalendarItemCollection();

    // Add the first dummy item
    SPCalendarItem item = new SPCalendarItem();
    item.StartDate = DateTime.Now;
    item.EndDate = DateTime.Now.AddHours(1);
    item.hasEndDate = true;
    item.Title = "First calendar item";
    item.DisplayFormUrl = "/News";
    item.Location = "Utrecht";
    item.Description = "This is the first test item in the calendar rollup";
    item.IsAllDayEvent = false;
    item.IsRecurrence = false;
    item.CalendarType = Convert.ToInt32(SPCalendarType.Gregorian);
    items.Add(item);

    // Add the second item. This is an all day event.
    SPCalendarItem item2 = new SPCalendarItem();
    item2.StartDate = DateTime.Now.AddDays(-1);
    item.hasEndDate = true;
    item2.Title = "Second calendar item";
    item2.DisplayFormUrl = "/News";
    item2.Location = "Utrecht";
    item2.Description = "This is the second test item in the calendar rollup";
    item2.IsAllDayEvent = true;
    item2.IsRecurrence = false;
    item2.CalendarType = Convert.ToInt32(SPCalendarType.Gregorian);
    items.Add(item2);

    // return the collection
    return items;
}

If you now build your webpart and add it to a page, it should look like this:

calendar01

Step 3 – The ViewType

Looks nice and it indeed it very simple to do. But now you click one of the links “Week” or “Day” to switch to the daily or weekly view. That doesn’t work. The webpart simply does what it does and it shows you the monthly view. If you look at the url however, you will see that the calendar view added a querystring parameter called “CalendarPeriod“.

Add the following snippet to the CreateChildControls of the SharePointCalendar to make it work:

if (Page.Request.QueryString["CalendarPeriod"] != null)
{
    switch (Page.Request.QueryString["CalendarPeriod"].ToString().ToLower())
    {
        case "day":
            _view.ViewType = "day";
            break;
        case "week":
            _view.ViewType = "week";
            break;
        case "timeline":
            _view.ViewType = "timeline";
            break;
        default:
            _view.ViewType = "month";
            break;
    }
}

The documentation for the ViewType property shows you the possible values, but please notice that you need to set them in lower case!. Not sure what the option “timeline” does. It looks like a normal monthly view if you use it.

Step 4 – The DisplayFormUrl problem

The property DisplayFormUrl expects are relative url to the item that you added to the calendar. In the sample above, I added a url to the News site. If you look at the properties of the hyperlink, you will see this link:

http://cbt/News?ID=

The calendar view automatically adds a querystring parameter ID to your urls. In this case this is not a problem. In the Content By Type webpart however, I add the same links that are generated by the out of the box ContentQuery webpart. These urls look like this:

http://cbt/_layouts/CopyUtil.aspx?Use=id&Action=dispform&ItemId=1&ListId={70fbb8db-c7b8-4b32-bf77-f61a13b3e0fc}&WebId={087c3dd8-b0a9-4960-9509-da8887d979b6}&SiteId={9fb94730-cc85-4924-957f-7504f415fe0f}

When you add “?ID=” to that url (that is what the calendar view does), your link will not work and the page will display an “Unknown error“:

calendar02

In the first approach I tried to fix the urls in javascript, but that didn’t work. I was able to trim the “?ID=” bit, but something else kept on adding it back in. I ended up creating a page like the CopyUtil page. When I set the DisplayFormUrl property, I encode the Url that I want to redirect to and add that as a querystring parameter to my redirect page called “tstredirect.aspx”:

string link = /_layouts/CopyUtil.aspx?Use=id&Action=dispform&ItemId=1&ListId={70fbb8db-c7b8-4b32-bf77-f61a13b3e0fc}&WebId={087c3dd8-b0a9-4960-9509-da8887d979b6}&SiteId={9fb94730-cc85-4924-957f-7504f415fe0f}
string urlStart = SPContext.Current.Site.ServerRelativeUrl;
if (urlStart == "/")
    urlStart = string.Empty;
link = string.Format("{0}/_layouts/tst/tstredirect.aspx?GoTo={1}", urlStart, System.Web.HttpUtility.UrlEncode(link));

item.DisplayFormUrl = link;

In that tstredirect page, I decode the querystring GoTo parameter and redirect to that url.

I am not very happy with that last approach, there should be a better way. If you have a suggestion, please let me know. So after all, it still is pretty easy to use the SPCalendarView in your webparts, if you are aware of these things. In the next post I will show you how I exactly implemented it in the Content By Type webpart.

Check User Permission with DoesUserHavePermissions In Site, Web, List, ListItem ..

Check permission with:

Name Description
SPSite.DoesUserHavePermissions (SPReusableAcl, SPBasePermissions)
Returns a Boolean value indicates whether the user has permissions for the specified set of rights.
SPSite.DoesUserHavePermissions (SPReusableAcl, SPBasePermissions, SPWeb)
Returns a Boolean value that indicates whether the user has permissions for the specified Web site and set of rights.
Name Description
SPWeb.DoesUserHavePermissions (SPBasePermissions)
Checks permissions of the current user for a specified set of rights and returns a Boolean value.
SPWeb.DoesUserHavePermissions (String, SPBasePermissions)
Checks permissions of the specified user for a specified set of rights and returns a Boolean value.
Name Description
SPList.DoesUserHavePermissions (SPBasePermissions)
Checks the permissions of the current user on the list.
SPList.DoesUserHavePermissions (SPBasePermissions, Boolean)
Checks the permissions of the list, and, optionally. checks the folder permissions.
SPList.DoesUserHavePermissions (SPUser, SPBasePermissions)
Checks the permissions of a specified user on the list.
Name Description
SPListItem.DoesUserHavePermissions (SPBasePermissions)
Checks whether the current user has the specified permissions to an item.
SPListItem.DoesUserHavePermissions (SPUser, SPBasePermissions)
Checks whether a specified user has the specified permissions to an item.

Using SPPermissionCollection

http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.sppermissioncollection.aspx

SPSite oSiteCollection = SPContext.Current.Site;
using(SPWeb oWebsite = oSiteCollection.AllWebs["Site_Name"])
{
    SPList oList = oWebsite.Lists["List_Name"];
    SPPermissionCollection collPermissions = oList.Permissions;
    SPUserCollection collUsers = oWebsite.Users;

    foreach (SPUser oUser in collUsers)
    {

        foreach (SPPermission oPermission in collPermissions)
        {

            if (oUser.ID == oPermission.Member.ID)
            {
                 Response.Write("User: " + 
                    SPEncode.HtmlEncode(oUser.Name) + 
                    " Permissions: " +   
                    oPermission.PermissionMask.ToString() + 
                    "<BR>");
            }
        }
    }
}