Get the port number of your Web Application Zone using server side object model

Although it seems pretty easy to get your web application’s port number from IIS or Central Admin, I didn’t find enough info on how to get the port number from server side object model. I was trying to customize the Authenticate.aspx application page where I had already written code to check users permission in a specific group of another web application. In the end, I was able to get a really simple method which is the following piece of code:

int webPort=SPContext.Current.Site.WebApplication.IisSettings[Microsoft.SharePoint.Administration.SPUrlZone.Default].ServerBindings[0].Port; if (webPort==80) { //check user permission for a site collection which is using the web app on port 80 ... ... }

else { //check the user permission for rest of the web apps SPUtility.EnsureAuthentication(); SPUtility.Redirect(spWeb.Url, SPRedirectFlags.UseSource, Context); }

If you look at the code, you’ll easily understand I was actually trying to check the user permission for the web application which is using Port 80 and you can write your server side code there to check any user’s permission or group permission etc. Notice that, here I am actually checking the default zone’s port number for the web application. If you have multiple zones, or else if you have extended your web application on other zones which have different ports, then you have to specify  one from the below under WebPpplications.IisSettings property:

SPUrlZone.Custom,
SPUrlZOne.Default,
SPURlZone.Internet,
SPUrlZone.Intranet
SPUrlZOne.Extranet

Now, what if you want to create a method, which will get the port number of web application and later on you can call that method from anywhere; you can do that too. The code is given below:

int GetPortNumber(Microsoft.SharePoint.Administration.SPWebApplication application)
{
int result = 0;
Microsoft.SharePoint.Administration.SPIisSettings setting=null;
if (application.IisSettings.TryGetValue(Microsoft.SharePoint.Administration.SPUrlZone.Default, out setting))
{
if (null != setting)
{
var serverBindings = setting.ServerBindings;
if (0 < serverBindings.Count)
{
Microsoft.SharePoint.Administration.SPServerBinding serverBinding = serverBindings[0];
result = serverBinding.Port;
}
}
}
return result;
}
Advertisements

Use SPMetal Extender to overcome LINQ to SharePoint 2010 limitations

Many of us are not aware of the fact that SPMetal only runs against the field type provided by SharePoint Foundation. So, if you use Taxonomy, Publishing HTML, Publishing Image in your list, you will not be able to generate an entity class with these fields by running SPMetal command as it will skip those fields. You can easily overcome this problem by using one plugin from codeplex, “SPMetal Extender”.

LINQ to SharePoint has several limitations; there are various techniques to improve SPMetal code generation. This project provides a Visual Studio extension to allow developers to easily work with list fields that are not covered by SPMetal’s code generation. The extension provides additional functionality to the server explorer to allow the developer to generate code to extend LINQ to SharePoint’s functionality. For example, SPMetal does not generate strongly typed properties for lists fields based on “Publishing HTML” or “Taxonomy” site columns. You can download SPMetal Extender from Here

Create Dynamic Visual Web Part in SharePoint

After a long time, I am going to discuss about creating a  dynamic visual web part in SharePoint 2010. Suppose, a company needs to create a sales forecasting web part on monthly basis. They want to display information in a web part of a page where the data will come from different lists from a web site and hence the result will be shown visually to highlight information based on conditions.

Objective:

Select a month from the drop down list of all months and based on the selected month, the grid view should change automatically. A LINQ will be executed in the background whenever you change a month from the drop down list and the data displayed inside the grid view should match the query results.

Solution:

First of all, Create a  visual studio project and select Visual Web Part from the SharePoint 2010 templates. This automatically adds a Feature with a Default Visual Web Part in your solution. Please note that, while creating a visual web part, you must choose as Farm Solution as the files of visual web parts (ASCX Files) need to be deployed physically inside 14 hive.

You will need to write LINQ to query your SharePoint Lists. So, create a Entity Class using SPMetal.exe. To know more about how to use SPMetal, go here. Create and add the entity class in your project. For my example; I named the class as MyEntity.cs.

To start off with the solution, let us drag and drop a drop down box and create SPGridView object. The ASCX code is given below:

  1. <%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
  2. <%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  3. <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  4. <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  5. <%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
  6. <%@ Import Namespace="Microsoft.SharePoint" %>
  7. <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  8. <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="VisualWebPart1UserControl.ascx.cs" Inherits="SalesForecastWebPart.VisualWebPart1.VisualWebPart1UserControl" %>
  9.  
  10. <asp:dropdownlist runat="server" ID="MonthList" AutoPostBack="True" onselectedindexchanged="MonthList_SelectedIndexChanged"
  11.     >
  12.     <asp:ListItem Selected="True">–Select Month–</asp:ListItem>
  13.     <asp:ListItem Value="1">January</asp:ListItem>
  14.     <asp:ListItem Value="2">February</asp:ListItem>
  15.     <asp:ListItem Value="3">March</asp:ListItem>
  16.     <asp:ListItem Value="4">April</asp:ListItem>
  17.     <asp:ListItem Value="5">May</asp:ListItem>
  18.     <asp:ListItem Value="6">June</asp:ListItem>
  19.     <asp:ListItem Value="7">July</asp:ListItem>
  20.     <asp:ListItem Value="8">August</asp:ListItem>
  21.     <asp:ListItem Value="9">September</asp:ListItem>
  22.     <asp:ListItem Value="10">October</asp:ListItem>
  23.     <asp:ListItem Value="11">November</asp:ListItem>
  24.     <asp:ListItem Value="12">December</asp:ListItem>
  25. </asp:dropdownlist>
  26.  
  27. &nbsp;&nbsp;<b>Monthly Forecast</b>
  28. <SharePoint:SPGridView ID="spGridView" runat="server"
  29.     AutoGenerateColumns="false"
  30.     onprerender="spGridView_PreRender" ondatabound="spGridView_DataBound" onrowdatabound="spGridView_RowDataBound">
  31.     <HeaderStyle HorizontalAlign="Left" ForeColor="Navy" Font-Bold="true" />
  32.     <Columns>
  33.         <SharePoint:SPBoundField DataField="Title" HeaderText="Consultant">
  34.         </SharePoint:SPBoundField>
  35.           <asp:TemplateField HeaderText="Total ITS Ricoh Lab Revenue">
  36.             <ItemTemplate>
  37.         <asp:Label ID="lblSales" runat="server" Text='<%# String.Format("{0:f2}",DataBinder.Eval(Container.DataItem,"TotalSales")) %>' ></asp:Label>
  38.         </ItemTemplate>
  39.         </asp:TemplateField>
  40.          <asp:TemplateField HeaderText="Total ITS Ricoh Lab Revenue Quota">
  41.             <ItemTemplate>
  42.         <asp:Label ID="lblQuota" runat="server" Text='<%# String.Format("{0:f2}",DataBinder.Eval(Container.DataItem,"ITSRicLabRev")) %>' ></asp:Label>
  43.         </ItemTemplate>
  44.         </asp:TemplateField>
  45.         <asp:TemplateField HeaderText="Status">
  46.             <ItemTemplate>
  47.                 <asp:Label ID="Status" runat="server" Text='<%# Eval("Status") %>' />
  48.             </ItemTemplate>
  49.              
  50.         </asp:TemplateField>
  51.       
  52.         
  53.     </Columns>
  54. </SharePoint:SPGridView>

If you look inside the above code, you will find that I have created four columns inside the grid view to display Employee (Consultant) Name, Total Revenue, Total Revenue Quota and Status and a drop down box containing all months. Now, create the entity object for the lists inside your ascx.cs file. For my scenario, I had to query two different lists and I created the entity and data context object as below:

EntityList<SCTXPSITSVCsForecastingItem> SCTXPSITSVCsForecasting;

EntityList<SolnConsultantsItem> SolnConsultants;

protected void Page_Load(object sender, EventArgs e)

{

    string spWebUrl = SPContext.Current.Web.Url;

    MyEntitiesDataContext dc = new MyEntitiesDataContext(spWebUrl);

    SCTXPSITSVCsForecasting = dc.GetList<SCTXPSITSVCsForecastingItem>(@"SCTX PS / ITSVCs Forecasting");

    SolnConsultants = dc.GetList<SolnConsultantsItem>("SolnConsultants");

 

}

 

From the above code, you can see I created two data context object where my entity class was “MyEntities”. I then called the two lists in the page load event by the GetList() Method.

Inside the SelectedIndexChanged() method of the drop down list for month, I called a method to create the LINQ and passed the selected item as the parameter. If you notice the LINQ below, you will see that I have used a join query to select data from two different lists. For my scenario, I had a list called “SCTXPSITSVCsForecasting” where there was a column named “ITSRicohLaborRevenue” in which all the employees (consultants) monthly forecast had to be summed up. So, I used an aggregated function (SUM) to sum up all the employees monthly forecast and divided by the standard monthly forecast to determine their status (if greater than 90%, “Green”, if greater than or equal to 75%, “Yellow” and if below 75%, “Red”).

  1. protected void MonthList_SelectedIndexChanged(object sender, EventArgs e)
  2.         {
  3.             var selected = MonthList.SelectedValue;
  4.             getConsultants(Convert.ToInt32(selected));
  5.            
  6.         }
  7.         private void getConsultants(int mo)
  8.         {
  9.  
  10.             var ConsultantQuery = from c in SolnConsultants.ToList()
  11.                                   join s in SCTXPSITSVCsForecasting.ToList()
  12.  
  13.                                on c.Title equals s.Consultant
  14.                                   where s.CloseDate.Value.Month.Equals(mo)
  15.                                   group s by new { s.Consultant, c.ITSRicLabRev } into result
  16.                                   select new
  17.                                   {
  18.                                       Title = result.Key.Consultant,
  19.                                       TotalSales = result.Sum(s => s.ITSRicohLaborRevenue),
  20.                                       ITSRicLabRev = result.Key.ITSRicLabRev / 12,
  21.                                       Status = (((result.Sum(s => s.ITSRicohLaborRevenue)) / (result.Key.ITSRicLabRev / 12) * 100) > 90 ? "Green" :
  22.                                       (((result.Sum(s => s.ITSRicohLaborRevenue)) / (result.Key.ITSRicLabRev / 12) * 100) >= 75 ? "Yellow" : "Red"))
  23.  
  24.                                   };
  25.  
  26.             spGridView.DataSource = ConsultantQuery;
  27.             spGridView.DataBind();
  28.  
  29.  
  30.         }

To display the status of the forecast visually, I had to add another method for the grid view on RowDataBound():

  1.  
  2.         protected void spGridView_RowDataBound(object sender, GridViewRowEventArgs e)
  3.         {
  4.             if (e.Row.RowType == DataControlRowType.DataRow)
  5.             {
  6.                 Label lblStatus = e.Row.FindControl("Status") as Label;
  7.                 string status = Convert.ToString(DataBinder.Eval(e.Row.DataItem, "Status"));
  8.                 if (status == "Red")
  9.                 {
  10.                     DataControlFieldCell d = lblStatus.Parent as DataControlFieldCell;
  11.                     // change the backcolor like this
  12.                     d.BackColor = System.Drawing.Color.Red;
  13.                     // change the row color like this
  14.                     e.Row.BackColor = System.Drawing.Color.LightBlue;
  15.                     // change the text color like this
  16.                     lblStatus.ForeColor = System.Drawing.Color.White;
  17.                 }
  18.                 else if (status == "Yellow")
  19.                 {
  20.                     DataControlFieldCell d1 = lblStatus.Parent as DataControlFieldCell;
  21.                     d1.BackColor = System.Drawing.Color.Yellow;
  22.                     e.Row.BackColor = System.Drawing.Color.Aqua;
  23.                     lblStatus.ForeColor = System.Drawing.Color.Blue;
  24.                 }
  25.                 else
  26.                 {
  27.                     DataControlFieldCell d2 = lblStatus.Parent as DataControlFieldCell;
  28.                     d2.BackColor = System.Drawing.Color.Green;
  29.                     e.Row.BackColor = System.Drawing.Color.LightCyan;
  30.                     lblStatus.ForeColor = System.Drawing.Color.WhiteSmoke;
  31.                 }
  32.             }
  33.         }

You can see from the above code that I am changing the Background color , Foreground color of the row based on the Status column’s value.

After deploying and adding the web part on a page, you will get a following screen:

ricohsaleswebpart

ricohsaleswebpart1

You can see from the above screenshots that the gird view is changing dynamically based on the selected month. Following this basic example, you can create more complex dynamic visual web parts in SharePoint.

Resolve issues while updating People Picker Column of a List in Event Handler

Let’s say, you have a List with a People Picker column (Person or Group) on your site. Now, you need to add an event handler for new item add/update. Normally, if you go by the conventional way, you would get the following error:

Invalid data has been used to update the list item . The field you are trying to update may be read only.

I tried to figure out what exactly caused this error while I trying to set a people picker column property in my event handler programmatically. Afterwards, I found out that People Picker Column in a List is a read-only field. By Default, the read-only mode of this field remains true while we try to add/update it for a list item. So, how to overcome this problem? Well, it’s not that difficult. You just need to set the read-only mode of the people picker column to be “False” at first and after that,  update the property of the people picker. After finishing everything, set the read-only mode of the field again to “True”. Here is an example how you can achieve this:


using (SPSite mySite = new SPSite(properties.SiteId))
 {
 using (SPWeb myWeb = mySite.OpenWeb(properties.RelativeWebUrl))
 {
 SPList currentList = myWeb.Lists[properties.ListId];
 SPListItem currentitem = currentList.GetItemById(properties.ListItem.ID);

 myWeb.AllowUnsafeUpdates = true;
 ServerContext ospServerContext = ServerContext.GetContext(mySite);

//Create a new UserProfileManager
 UserProfileManager pManager = new UserProfileManager(ospServerContext);

//Get the User Profile for the current user
 UserProfile uProfile = pManager.GetUserProfile(currentitem["Title"].ToString());

 //Set the read only mode of people picker column to FALSE
 currentitem.Fields["Direct Supervisor"].ReadOnlyField = false;

 if (uProfile["Manager"].Value != null)
 {
 string temp = @""+uProfile["Manager"].Value.ToString();
 string temp1=temp.Replace("\\",@"\");
 //Setting the property of people picker column
 currentitem["Direct Supervisor"] = myWeb.AllUsers[temp1].ID;

 }

//Update List Item
 currentitem.Update();
 //Update List
 currentList.Update();

//Set the read only mode to TRUE
 currentitem.Fields["Direct Supervisor"].ReadOnlyField = true;

//Update the List item again
 currentitem.Update();
 //update the List again
 currentList.Update();

}
}

Inside the above code, you can see that first of all, I set the property of current site’s allowUnsafeUpdates to True which will allow you to change the read-only mode of a field. I have used the User Profile service to set the value of People Picker Control (in this case, the field name is “Direct Supervisor”). After setting the value of the field, I updated the List item and the list before changing back the read-only mode to be “True” again. Afterwards, I updated the current item and current list once again which ensures that the update will take place without any such error which happened previously.


			

Create a Dynamic User Control using Silverlight Client Object Model –upload Image, Add, Create, Delete both List and List items and populate current items [Part 2]

In my last post, I talked about how we can create new list, delete a list using Client Object Model. In this part, I am going to talk about how to create new List Items, retrieve those, update and delete items. I will also talk about how to upload an image directly to an Image Column of a list from the same Silverlight user control.

Retrieving List Items:

If you read the previous post, I had one column called “category” from the six fields that I created for the List “TechnoProducts”. In order to populate the drop down box “Category”, in this particular example, I click on “Get List Items” button to populate my user control fields. If there is no existing item in the list, it will only populate the drop down box with some predefined categories that I mentioned while creating the list.

Here, I wanted to show the titles of each List Items once you click “Get List Items” button and then after clicking on each item, I wanted to show the details.

For this to happen, I added the following code inside my event handler for clicking on Get Items Button.

private void txtGetItems_Click(object sender, RoutedEventArgs e)
{
    if (listProducts.Items.IsReadOnly)
        listProducts.ItemsSource = null;
    else
        listProducts.Items.Clear();
    CreateProgressBar("Getting Product Items..");
    GetItems();
}

Here, as you can see first of all, I am clearing the existing values of Products List and then creating a progress bar to let the user know about what is going to happen and then I am calling a method to get the items which is as below:

private void GetItems()
{
    var web = context.Web;
    getList = web.Lists.GetByTitle("TechnoProducts");
    context.Load(getList);

    techItems = getList.GetItems(CamlQuery.CreateAllItemsQuery());
    context.Load(techItems);
    context.ExecuteQueryAsync(getItemSuccess, failedCallback);
}
private void getItemSuccess(object sender, ClientRequestSucceededEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        foreach (var item in techItems)
        {
            item.Tag = item["Title"].ToString();
        }
      
        if (listProducts.Items.IsReadOnly)
            listProducts.ItemsSource = null;
        else
            listProducts.Items.Clear();
      
        listProducts.ItemsSource = techItems;
        cbCategory.ItemsSource = new string[] { "Electronics", "Desktop Pc", "Laptop", "Mobile", "PC Accessories" };
        
    });
}

In this above code, I have called my List and then stored the values of the List items in a ListItemCollection object which I declared globally. Inside the successfulcallback event handler, at first, I have stored the Title of each list item inside the Tag property which I used to display the names inside Products ListBox. I set the data source of my ListBox as this ListItemCollection object and populated the drop down box with the string array.

Displaying the details of each List Item:

After retrieving the list items, I now wanted to show the details of each items. So if there is any list item, I am going to show it inside the user control. I will talk about how I added these items shortly after this.

   private void listProducts_SelectionChanged(object sender, SelectionChangedEventArgs e)
   {
       lblImageStatus.Content = string.Empty;
       if (listProducts.SelectedIndex == -1)
       {
           txtTitle.Text = string.Empty;
           txtModel.Text = string.Empty;
           txtStock.Text = string.Empty;
           txtUnitPrice.Text = string.Empty;
           cbCategory.SelectedIndex = 0;
           chkDiscontinued.IsChecked = false;
           productImg.Source = null;
           txtTitle.Focus();
       }
       else
       {
           var item = (ListItem)listProducts.SelectedItem;
           txtTitle.Text = item["Title"].ToString();
           txtModel.Text = item["ModelNo"].ToString();
           txtStock.Text = item["InStock"].ToString();
           txtUnitPrice.Text = item["UnitPrice"].ToString();
           var chk = (bool)item["Discontinued"];
           chkDiscontinued.IsChecked = chk;
           
           BitmapImage img = new BitmapImage();
           var url=(FieldUrlValue)item["Image"];
           if (url != null)
           {
               string urlvalue = url.Url.ToString();
               productImgUrl = urlvalue;

               Uri uri = new Uri(urlvalue);
               img.UriSource = uri;
           }
           if (img != null)
               productImg.Source = img;
       
           var cbItems = cbCategory.Items;
           for (int i = 0; i < cbItems.Count; i++)
           {
               string cbItem = cbItems[i].ToString();
               if (cbItem == item["Category"].ToString())
               {
                   cbCategory.SelectedIndex = i;
                   break;
               }
           }

       }

   }

I added the code inside the Selection Changed Event handler and what I did was checked the Mode of the current state whether it is in Add Items state or not. If not, then I went with showing each property of a selected list item. Notice that, to show the Image of an specific item, I created a BitmapImage object to get the property and display inside my user control where I set the source as current item’s Image. Lastly, I set the current category for that item which I tried to match using a for loop (There are better ways to do it though!).

This is a screenshot of how it looks like once I selected a List item from the ListBox:

image

Adding a New List Item:

For adding a new item, I wanted to clear out my user control, so I added the following code:

private void txtAddItems_Click(object sender, RoutedEventArgs e)
{
    listProducts.SelectedIndex = -1;
    productImgUrl = string.Empty;
}

And after filling out each field inside the user control and clicking the save button, I get the following screen:

image

After adding an item, I also added a notification message whether or not the item was added in the list. Now, here comes the big part: To save the list item based on its mode whether adding or editing an item.

Saving and Updating a List Item:

Below is the code for event handler of Save button:

private void btnSave_Click(object sender, RoutedEventArgs e)
{
    ListItem item = null;
    if (listProducts.SelectedIndex == -1)
    {                        
        ListItemCreationInformation lci = new ListItemCreationInformation();
        item = getList.AddItem(lci);
    }
    else
    {       
        item = (ListItem)listProducts.SelectedItem;   
    }
   
    if (imgFile != null)
    {
        context.Load(web);
        List picLib = web.Lists.GetByTitle("RadiantProducts");
        context.Load(picLib);

        byte[] bFile = ReadFully(imgFile.OpenRead());
        FileCreationInformation file = new FileCreationInformation();
        file.Content = bFile;
        string picUrl = imgFile.Name.ToString();
        file.Url = "http://www.teamradiant.net/RadiantProducts/&quot; + picUrl;
        productImgUrl = file.Url;
        file.Overwrite = true;
        Microsoft.SharePoint.Client.File newFile = picLib.RootFolder.Files.Add(file);
        context.Load(newFile);
        context.ExecuteQueryAsync(succeedCallback, failedCallback);
    }

    item["Title"] = txtTitle.Text;
    item["Category"] = cbCategory.SelectedItem;
    item["ModelNo"] = txtModel.Text;
    item["UnitPrice"] = txtUnitPrice.Text;
    item["InStock"] = txtStock.Text;
    item["Discontinued"] = chkDiscontinued.IsChecked;
    item["Image"] = productImgUrl;
    item.Update();
    if(listProducts.SelectedIndex == -1)
        CreateProgressBar("Adding Product Item..");
    else
        CreateProgressBar("Updating Product..");
    context.ExecuteQueryAsync(saveSuccess, failedCallback);

}
private void saveSuccess(object sender, ClientRequestSucceededEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        GetItems();
        lblImageStatus.Content = "Saved Successfully";
    });
}

As you can see here, I checked the mode whether I am adding or updating an Item. If it is in Add mode, I created a ListItemCreationInformation object and adding this info to my existing List getList which I got from calling GetItems method and assigned it to a new List item object.

To add a new image, I declared a FileInfo variable imgFile which I used to check the mode of adding or updating. To add an image directly to my List TechnoProducts, I have created an Picture Library List named RadiantProducts. As you might know that, in SharePoint, we can only add an existing Image URL to an Image Column of a list; so, behind the scene, first of all, I added the selected image using an Open File Window, read the file as Bytes and after that, I set the URL of this image using the name of the Image File. Then, I stored the image directly to the root folder of the Picture Library. Here is the code to read the image as a binary file:

public static byte[] ReadFully(Stream input)
  {
      byte[] buffer = new byte[16 * 1024];
      using (MemoryStream ms = new MemoryStream())
      {
          int read;
          while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
          {
              ms.Write(buffer, 0, read);
          }
          return ms.ToArray();
      }
  }

After that, it is pretty simple as I just assigned the current property of the List item with the values from the user control and updated it. Notice that, for the image I now can set the Image Url as I stored it beforehand.

Here is the code for selecting an image which opens up a Open File Dialog window:

private void btnSelect_Click(object sender, RoutedEventArgs e)
{
    OpenFileDialog ofd = new OpenFileDialog();
    ofd.Filter = "JPEG Files (*.jpg)|*.jpg|PNG Files (*.png)|*.png";
    ofd.Multiselect = false;
    ofd.ShowDialog();
    imgFile = ofd.File as FileInfo;
    if (imgFile != null)
    {
        image = new BitmapImage();
        image.SetSource(imgFile.OpenRead());
        productImg.Source = image;
    }
    
}

In this above code, it will just open up a window to select a File of JPG/PNG type and after selecting it will display in the Image control as I set the source after reading the file. After saving a list item, I called the previously defined GetItems method to retrieve the updated List where it will also show if there is any newly added item.

Deleting a List Item:

Following is the code by which I can delete a selected list item after clicking on “Delete Item”:

private void btnDeleteItem_Click(object sender, RoutedEventArgs e)
{
    var web = context.Web;
    var item1 = (ListItem)listProducts.SelectedItem;
    string delTitle = item1["Title"].ToString();
    var delList = web.Lists.GetByTitle("TechnoProducts");
    var query=new CamlQuery();
    query.ViewXml = "<View>" +
        "<Query>" +
        "<Where><Eq>" +
        "<FieldRef Name='Title'/>" +
        "<Value Type='Text'>" + delTitle + "</Value>" +
        "</Eq></Where>" +
        "</Query>" +
        "<ViewFields>" +
        "<FieldRef Name='ID'/>" +
        "<FieldRef Name='Title'/>" +
        "</ViewFields>" +
        "</View>";
     

     techItems = delList.GetItems(query);
     context.Load(techItems);
     context.ExecuteQueryAsync(delCallSuccess, failedCallback);
   
}

 

In this above code, I am getting the current web from current client context. Then, I created a variable to get Selected List Item from the List Box. After that, I stored the Title of that item in a string variable which I used inside the CAML query later. The CAML query will retrieve ID and Title of an item from the List which matches the Title of the selected item. I then stored in inside a globally defined ListItemCollection which I used before and then called ExecuteQueryAsync . Following is the code for the successful callback of this action:

private void delCallSuccess(object sender, ClientRequestSucceededEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        foreach (ListItem item in techItems)
        {
            item.DeleteObject();
        }
        context.ExecuteQueryAsync(deleteItemSuccess, failedCallback);
    });
}
private void deleteItemSuccess(object sender, ClientRequestSucceededEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        GetItems();
        lblImageStatus.Content = "Item Deleted Successfully";
    });
}

In this above code, I deleted the item using DeleteObject method from SharePoint’s Client Object Model API. As I am only deleting one item, the for loop here will only get executed once. After that, I have another callback where for the successful handler, I am calling GetItems  method to show the updated List Items with a message that the item was deleted successfully. Here is the screenshot:

image

Here, I am deleting the product Samsung and right after that I get the following screen I don’t see this item anymore inside my List Box.

image

As you can see, after deleting the item, I can see the updated items Title inside the List Box.

That’s all for today. Next time, I will talk about how you can use Client Object Model using Javascript/ECMAscript. Thanks for reading and I will always appreciate if you can come up with a better solution and technique.

Create a Dynamic User Control using Silverlight Client Object Model –upload Image, Add, Create, Delete both List and List items and populate current items [Part 1]

Today, I am going to discuss about using the Silverlight Client Object Model in SharePoint 2010. You can actually develop scintillating user controls using Silverlight in SharePoint 2010. I am going to discuss the development work in two phases. In this part, I am going to show you how you can create and delete a List.

Alright, to begin with, let me clarify few things: Silverlight Client Object Model almost works in the same way as .NET Managed mode except in few areas, one of them is executing the request. In .NET Managed mode, the actual request and response happens synchronously whereas in Silverlight, it is Asynchronous. Therefore, we have to use ExecuteQueryAsync instead of ExecuteQuery. ExecuteQueryAsync must have two event handlers as parameters: one for a successful callback and another for a failed callback. Another big difference is that in .NET Managed mode, you code set the Authentication mode to default, form based, windows. But, here you do not have such option. We have two options to test our Silverlight user control in COM:

First method: To upload the build "XAP” file in SharePoint’s document library and then add a Silverlight Web Part and define the URL there.

Second method: To test the user control right from the VS2010, we need to create an XML file inside the Web Application Root (inside Intepub\wwwroot\…[Your Port No. for Web App] Directory] and name that file as ClientAccessPolicy.xml as by default SharePoint does not allow cross domain access [When you test your user control using VS2010, it uses localhost to test and it is considered as Cross Domain against your SharePoint web app].

Let me begin with explaining the demo:

First of all, I created a new Silverlight Project from Visual Studio 2010. While creating the project, VS will prompt you whether you want to add an ASP.NET test web page to test your user control; choose ‘Yes’ and always remember to select ASP.NET 3.5 version as SharePoint does not support framework 4 as of now. After that, your solution explorer should look like this:

image

You can see that I named my project as “DynamicListSilver”. The upper one shows my XAML file and at the bottom you can see the Test Page with a web.config which was automatically created by VS.

Now, I have designed my User Control as below:

image

Here, at the top, you can see some buttons which are self-explanatory. Beneath those buttons, I have one List Box to show my current List items and a dynamic Progress Bar. At the right side, the details of a particular list item will be shown once an item is selected from the List Box. Below the Product Image label, there is a status bar label which will show the messages from successful and failed callback and also display the actual happening of a list item and the list. Beneath that, right above the Save button, I have added an Image control which will be displayed for the current Item if any image exists for that and after selecting an Image locally to upload using “Select” button which will open up a File Browser Dialogue.

Here is the code for this particular user control:

<UserControl x:Class="DynamicListSilver.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008&quot;
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
    mc:Ignorable="d"
    d:DesignHeight="483" d:DesignWidth="604" xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input" Loaded="UserControl_Loaded">

    <Grid x:Name="LayoutRoot" Background="White" Height="488" Width="577">
        <StackPanel Height="485" HorizontalAlignment="Left" Margin="10,0,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="561"></StackPanel>
        <Canvas Name="canvas1" Margin="10,0,0,12" HorizontalAlignment="Left" Width="555">
            <Button Content="Get List Items" Height="23" Name="txtGetItems" Width="87" IsTabStop="True" VerticalContentAlignment="Bottom" HorizontalContentAlignment="Center" IsEnabled="True" IsHitTestVisible="True" Canvas.Left="81" Canvas.Top="0" Click="txtGetItems_Click" />
            <Button Content="Create List" Height="23" Name="txtCreate" Width="75" Canvas.Left="0" Canvas.Top="0" Click="txtCreate_Click" />
            <Button Canvas.Left="383" Canvas.Top="0" Content="Delete List" Height="23" Name="btnDelete" Width="75" Click="btnDelete_Click" />
            <ListBox Canvas.Left="6" Canvas.Top="29" Height="401" Name="listProducts" ItemsSource="{Binding}" Width="162" SelectionChanged="listProducts_SelectionChanged" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Text="{Binding Tag}" />
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>

            </ListBox>
            <dataInput:Label Canvas.Left="259" Canvas.Top="29" Height="26" Name="label1" Width="139" Content="List item Details" FontWeight="ExtraBlack" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="62" Height="24" Name="label2" Width="66" Content="Title" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="92" Height="24" Name="label3" Width="66" Content="Category" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="122" Height="24" Name="label4" Width="66" Content="Unit Price" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="155" Height="24" Name="label5" Width="66" Content="Stock" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="214" Height="24" Name="label6" Width="74" Content="Discontinued" />
            <TextBox Canvas.Left="259" Canvas.Top="62" Height="23" Name="txtTitle" Width="189" />
            <ComboBox Canvas.Left="261" Canvas.Top="92" Height="23" Name="cbCategory" Width="137" />
            <TextBox Canvas.Left="261" Canvas.Top="122" Height="23" Name="txtUnitPrice" Width="120" />
            <TextBox Canvas.Left="261" Canvas.Top="151" Height="23" Name="txtStock" Width="89" />
            <CheckBox Canvas.Left="261" Canvas.Top="214" Content="Yes/No" Height="24" Name="chkDiscontinued" Width="69" />
            <Button Canvas.Left="261" Canvas.Top="436" Content="Save" Height="23" Name="btnSave" Width="75" Click="btnSave_Click" />
            <Button Canvas.Left="174" Canvas.Top="0" Content="Add Item" Height="23" Name="txtAddItems" Width="104" Click="txtAddItems_Click" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="241" Height="20" Name="label7" Width="84" Content="Product Image" />
            <Button Canvas.Left="261" Canvas.Top="241" Content="Select.." Height="23" Name="btnSelect" Width="75" Click="btnSelect_Click" />
            <Image Canvas.Left="259" Canvas.Top="293" Height="137" Name="productImg" Stretch="Fill" Width="237" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="185" Height="24" Name="label8" Width="74" Content="Model No." />
            <TextBox Canvas.Left="261" Canvas.Top="185" Height="23" Name="txtModel" Width="120" />
            <dataInput:Label Canvas.Left="174" Canvas.Top="267" Content="" Height="20" Name="lblImageStatus" Width="375" />
            <Button Canvas.Left="283" Canvas.Top="0" Content="Delete Item" Height="23" Name="btnDeleteItem" Width="94" Click="btnDeleteItem_Click" />
        </Canvas>
    </Grid>
</UserControl>

Let me now go through with each segment of this solution:

CREATING A LIST

To create a list in Client Object Model, there is few differences than Server Object Model as we define the List Columns and fields inside XML directly. In this demo, on my User Control Load event, I added the following code the load the current Client Context:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            context = ClientContext.Current;
            if (context == null)
                context = new ClientContext("http://www.teamradiant.net/&quot;); ;
            web = context.Web;
        }

Obviously, context and web objects were declared globally to access it from any method. As you can see, the code here is exactly as we write in .NET Managed mode. Now, when I wanted to create the list in the event handler of the Button “Create List” as below:

Creating List Snippet
listProducts.Items.Clear();
CreateProgressBar("List is getting created");

var lci = new ListCreationInformation();
lci.Title = "TechnoProducts";
lci.Description = "A List of Electronics & Techno Products";
lci.QuickLaunchOption = QuickLaunchOptions.On;
lci.TemplateType = (int)ListTemplateType.GenericList;
list=web.Lists.Add(lci);
var fields = list.Fields;

var titleField = fields.GetByTitle("Title");
titleField.Title = "ProductName";
titleField.Update();

As you can see from the above code that first of all, I cleared the List Box (on the left side). Then, I created a Progress Bar which will be populated dynamically inside the list box.

When you create a custom List in SharePoint, by default, it creates the “Title” field automatically. So here, I changed the column name “Title” to “ProductName”. Now, updating the field won’t actually happen unless we call the executequeryasync method. I have not done that yet as I need to some more fields for my List.

Here is the code for the progress bar:

public void CreateProgressBar(string progressContent)
{
    
    if (listProducts.Items.IsReadOnly)
        listProducts.ItemsSource = null;
    else
        listProducts.Items.Clear();

    listProgress = new ProgressBar();
    listProgress.Width = 100;
    listProgress.Height = 15;
    listProgress.Value = 10;
    listProgress.Maximum = 100;
    listProgress.Background = new SolidColorBrush(Colors.Gray);
    listProgress.Foreground = new SolidColorBrush(Colors.White);
    _timer.Duration = TimeSpan.FromMilliseconds(10);
    _timer.Completed += new EventHandler(_timer_Completed);
    _timer.Begin();

    Label lblProgress = new Label();
    lblProgress.Content = progressContent;
    listProducts.Items.Add(lblProgress);
    listProducts.Items.Add(listProgress);
}

And, here is the code for the Timer Event Handler:

void _timer_Completed(object sender, EventArgs e)
      {
          if (listProgress.Value < listProgress.Maximum)
          {
              listProgress.Value++;
              _timer.Begin();
          }
      }

As I used the progress bar on various occasions, I declared the following objects globally:

Storyboard _timer = new Storyboard();
 ProgressBar listProgress;

Next, I need to add the other columns or fields for my list. Now, to do that I will also need to pass a schema for each field that I add. As the schema is pretty big and hard to memorize, what I did was created a copy of exact same list in SharePoint web front end and got the values for schema using Server Explorer. [Open Server Explorer-> Go to your Web App-> Site Collection –> Site –> Fields and from the properties window, get the schema xml]

Then, I added the fields as below:

var categoryField = fields.AddFieldAsXml(@"<Field Type='Choice' DisplayName='Category' Required='TRUE' EnforceUniqueValues='FALSE' Indexed='FALSE' Format='Dropdown' FillInChoice='FALSE' StaticName='Category' Name='Category'><Default>Electronics</Default><CHOICES><CHOICE>Electronics</CHOICE><CHOICE>Desktop PC</CHOICE><CHOICE>Laptop</CHOICE><CHOICE>Mobile</CHOICE><CHOICE>PC Accessories</CHOICE></CHOICES></Field>", true, AddFieldOptions.DefaultValue);
var unitPriceField = fields.AddFieldAsXml(@"<Field Type='Currency' DisplayName='UnitPrice' Required='TRUE' EnforceUniqueValues='FALSE' Indexed='FALSE' Decimals='2' LCID='1033' StaticName='UnitPrice' Name='UnitPrice' />", true, AddFieldOptions.DefaultValue);
var stockField = fields.AddFieldAsXml(@"<Field Type='Number' DisplayName='InStock' Required='FALSE' EnforceUniqueValues='FALSE' Indexed='FALSE' Decimals='0' StaticName='InStock' Name='InStock' />", true, AddFieldOptions.DefaultValue);
var modelField = fields.AddFieldAsXml(@"<Field Type='Text' DisplayName='ModelNo' Required='TRUE' EnforceUniqueValues='FALSE' Indexed='FALSE' MaxLength='255' StaticName='ModelNo' Name='ModelNo' />", true, AddFieldOptions.DefaultValue);
var discontinuedField = fields.AddFieldAsXml(@"<Field Type='Boolean' DisplayName='Discontinued' EnforceUniqueValues='FALSE' Indexed='FALSE' StaticName='Discontinued' Name='Discontinued'><Default>0</Default></Field>", true, AddFieldOptions.DefaultValue);
var imageField = fields.AddFieldAsXml(@"<Field Type='URL' DisplayName='Image' Required='FALSE' EnforceUniqueValues='FALSE' Indexed='FALSE' Format='Image' StaticName='Image' Name='Image' />", true, AddFieldOptions.DefaultValue);
context.ExecuteQueryAsync(listcreatesuccess, failedCallback);

Now, when you add the Schema XML from the existing fields of a List there are some extra things which you should delete (generated IDs) and keep stuff clean which looks similar to the above code. I have added 6 more fields in this list which are: Category (Drop Down Choice Type), Unit Price (Currency type), InStock (Number type), ModelNo (Number Type), Discontinued (Yes/No Checkbox type) and an Image (Image type) which will hold the Image url for list item.

As you can see at the bottom of the code, I have called ExecuteQueryAsync which will call the server asynchronously and also passed two event handlers as parameters. Below is the code for successful callback event handler:

private void listcreatesuccess(object sender, ClientRequestSucceededEventArgs e)
 {
     this.Dispatcher.BeginInvoke(() =>
     {

         listProducts.Items.Clear();
         var msg = string.Format("{0} List was created at: {1}", list.Title, DateTime.Now.ToLongTimeString());
         lblImageStatus.Content = msg;
     });
 }

and here is for the failed callback:

private void failedCallback(object sender, ClientRequestFailedEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        var msg = "Error: " + e.Exception.ToString();
        listProducts.Items.Clear();
        listProducts.ItemsSource = null;
        listProducts.Items.Add(msg);

    });
}

That’s it. Now, if you click on “Create List”, your list should be created and you should see the progress bar and a message whether or not the list was created successfully with current time.

listcreated

Above one is a screenshot while creating the list and after completion, a message will be displayed if the creation was successful.

Let me now go through with deleting this list when I will click on “Delete List”.

The code for deleting this list is much simpler than creating it. Here it is:

private void btnDelete_Click(object sender, RoutedEventArgs e)
{
    CreateProgressBar("Deleting List…");
    context.Load(web, w => w.Title);
    context.Load(web.Lists);
    deleteList = web.Lists.GetByTitle("TechnoProducts");
    deleteList.DeleteObject();
    context.ExecuteQueryAsync(listdeletesuccess, listdeletefailure);
}
private void listdeletesuccess(object sender, ClientRequestSucceededEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        listProducts.Items.Clear();
        var msg = string.Format("List was Deleted at: {0}", DateTime.Now.ToLongTimeString());
        lblImageStatus.Content = msg;
    });
}
private void listdeletefailure(object sender, ClientRequestFailedEventArgs e)
{
    this.Dispatcher.BeginInvoke(() =>
    {
        listProducts.Items.Clear();
        var msg = "Error: " + e.Exception.ToString();
        lblImageStatus.Content = msg;

    });
}

As you can see I just called the List using web.Lists.GetByTitle  and then deleted the object from the List deleteList which I declared previously.

Here is a screenshot for deleting this list:

deletelist

You can see the message here after the successful callback for deleting the List. That’s it for this part. In the next part, I am going to discuss about adding, modifying and deleting a List item and also adding an Image directly to this List.  [To Be Continued…]