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.
{
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:
{
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.
{
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:
Adding a New List Item:
For adding a new item, I wanted to clear out my user control, so I added the following code:
{
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:
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:
{
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/" + 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:
{
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:
{
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”:
{
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:
{
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:
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.
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.