Friday, 30 March 2012

Add web part to page programmatically

From
http://www.habaneros.com/blog/posts/Programmatically_change_content_on_a_Wiki_Page_in_SharePoint_2010.aspx

Adjusted slightly to work for me



protected void lblAddWP_Click(object sender, EventArgs e)
{
AddWebPartToPage(SPContext.Current.Site.OpenWeb(), lblInfo.Text + "/SitePages/Home.aspx", "ActionSubjectGridy", "Top", 0);
lblAdd.Text = "Added WP ";
}

public void AddWebPartToPage(SPWeb web, string pageUrl, string webPartName, string zoneID, int zoneIndex)
{

InsertWebPartIntoWikiPage("TopWebPart");

InsertWebPartIntoWikiPage("ActionSubjectGridy");


}



public void InsertWebPartIntoWikiPage(string webPartName)
{
string replaceToken = "{{1}}";
using (SPSite site = new SPSite(lblInfo.Text))
{
using (SPWeb web = site.OpenWeb())
{
using (SPLimitedWebPartManager manager = web.GetLimitedWebPartManager(web.Url + "/SitePages/Home.aspx", PersonalizationScope.Shared))
{
using (System.Web.UI.WebControls.WebParts.WebPart webPart = CreateWebPart(web, webPartName, manager))
{
SPFile wikiFile = web.GetFile("SitePages/Home.aspx");
string str = (string)wikiFile.Item["WikiField"];

SPLimitedWebPartManager limitedWebPartManager = wikiFile.GetLimitedWebPartManager(PersonalizationScope.Shared);

Guid storageKey = Guid.NewGuid();

string str2 = StorageKeyToID(storageKey);
webPart.ID = str2;

limitedWebPartManager.AddWebPart(webPart, "wpz", 0);

string str3 = string.Format(CultureInfo.InvariantCulture, "<div class='ms-rtestate-read ms-rte-wpbox' contentEditable='false'><div class='ms-rtestate-read {0}' id='div_{0}'></div><div style='display:none' id='vid_{0}'/></div>", new object[] { storageKey.ToString("D") });
if (str == null)
{
str = str3;
}
else
{
if (!str.Contains(replaceToken)) { str = str + str3; } else { str = str.Replace(replaceToken, str3); }
}
wikiFile.Item["WikiField"] = str;
wikiFile.Item.Update();
}
}
}
}



}

public static string StorageKeyToID(Guid storageKey) { if (!(Guid.Empty == storageKey)) { return ("g_" + storageKey.ToString().Replace('-', '_')); } return string.Empty; }

public static System.Web.UI.WebControls.WebParts.WebPart CreateWebPart(SPWeb web, string webPartName, SPLimitedWebPartManager manager)
{
SPQuery query = new SPQuery();
query.Query = String.Format(CultureInfo.CurrentCulture,
"<Where><Eq><FieldRef Name='Title'/><Value Type='Text'>{0}</Value></Eq></Where>",
webPartName);

SPList webPartGallery = null;

if (null == web.ParentWeb)
{
webPartGallery = web.GetCatalog(
SPListTemplateType.WebPartCatalog);
}
else
{
webPartGallery = web.Site.RootWeb.GetCatalog(
SPListTemplateType.WebPartCatalog);
}

SPListItemCollection webParts = webPartGallery.GetItems(query);

XmlReader xmlReader = new XmlTextReader(webParts[0].File.OpenBinaryStream());
string errorMessage;
System.Web.UI.WebControls.WebParts.WebPart webPart = manager.ImportWebPart(xmlReader, out errorMessage);

return webPart;
}

Working List Defination (Without Content Type)

schema.xml


<?xml version="1.0" encoding="utf-8"?>
<List xmlns:ows="Microsoft SharePoint" Title="MomListDefination" FolderCreation="FALSE" Direction="$Resources:Direction;" Url="Lists/MomListDefination" BaseType="0" xmlns="http://schemas.microsoft.com/sharepoint/">
<MetaData>

<Fields>
<Field ID="" Name="LinkTitle" Type="Text" DisplayName="Title" Required="TRUE"></Field>
<Field ID="" Name="Attendees" Type="UserMulti" DisplayName="Attendees" Required="False"></Field>
<Field ID="" Name="URL" Type="Text" DisplayName="URL" Required="False"></Field>
<Field ID="" Name="Start_x0020_Date_x0020_Time" Type="DateTime" Format="DateTime" DisplayName="InitiatedDate" Required="TRUE">
<Default>[today]</Default>
</Field>

</Fields>
<Views>
<View BaseViewID="0" Type="HTML" MobileView="TRUE" TabularView="FALSE">
<Toolbar Type="Standard" />
<XslLink Default="TRUE">main.xsl</XslLink>
<RowLimit Paged="TRUE">30</RowLimit>
<ViewFields>
<FieldRef Name="LinkTitleNoMenu"></FieldRef>
</ViewFields>
<Query>
<OrderBy>
<FieldRef Name="Modified" Ascending="FALSE"></FieldRef>
</OrderBy>
</Query>
<ParameterBindings>
<ParameterBinding Name="AddNewAnnouncement" Location="Resource(wss,addnewitem)" />
<ParameterBinding Name="NoAnnouncements" Location="Resource(wss,noXinviewofY_LIST)" />
<ParameterBinding Name="NoAnnouncementsHowTo" Location="Resource(wss,noXinviewofY_ONET_HOME)" />
</ParameterBindings>
</View>
<View BaseViewID="1" Type="HTML" WebPartZoneID="Main" DisplayName="$Resources:core,objectiv_schema_mwsidcamlidC24;" DefaultView="TRUE" MobileView="TRUE" MobileDefaultView="TRUE" SetupPath="pages\viewpage.aspx" ImageUrl="/_layouts/images/generic.png" Url="AllItems.aspx">
<Toolbar Type="Standard" />
<XslLink Default="TRUE">main.xsl</XslLink>
<RowLimit Paged="TRUE">30</RowLimit>
<ViewFields>
<FieldRef Name="LinkTitle"></FieldRef>
<FieldRef Name="Attendees"></FieldRef>
<FieldRef Name="URL"></FieldRef>
<FieldRef Name="Start_x0020_Date_x0020_Time"></FieldRef>
</ViewFields>
<Query>
<OrderBy>
<FieldRef Name="ID"></FieldRef>
</OrderBy>
</Query>
<ParameterBindings>
<ParameterBinding Name="NoAnnouncements" Location="Resource(wss,noXinviewofY_LIST)" />
<ParameterBinding Name="NoAnnouncementsHowTo" Location="Resource(wss,noXinviewofY_DEFAULT)" />
</ParameterBindings>
</View>
</Views>
<Forms>
<Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
</Forms>
</MetaData>
</List>




Thursday, 29 March 2012

Check if user field is multiple or single user



Type fieldType = sliAction.Fields[fieldName].FieldValueType;
if (fieldType.Name.Equals("SPFieldUserValue"))
{
if (sliAction[fieldName] != null)
{
SPFieldUserValueCollection userValues = new SPFieldUserValueCollection(web, sliAction[fieldName].ToString());
string usr = "";
foreach (SPFieldUserValue userV in userValues)
{
usr = usr + userV.LookupValue;
}
dr[fieldName] = usr;
}
if (sliAction["RespExt"] != null)
dr[fieldName] = sliAction["RespExt"].ToString();
}
else if(fieldType.Name.Equals("SPFieldUserValueCollection"))
{
if (sliAction[fieldName] != null)
{
SPFieldUserValueCollection userValues = new SPFieldUserValueCollection(web, sliAction[fieldName].ToString());
foreach(SPFieldUserValue spu in userValues)
dr[fieldName] = dr[fieldName] + "," + spu.User.Name;
dr[fieldName] = dr[fieldName].ToString().Substring(1, dr[fieldName].ToString().Length - 1);
}
if (sliAction["RespExt"] != null)
dr[fieldName] = sliAction["RespExt"].ToString();
}
else if (fieldType == typeof(DateTime))
{
if (sliAction[fieldName] != null)
{
string dateString = sliAction.Fields[fieldName].GetFieldValueForEdit(sliAction[fieldName]);
dr[fieldName] = dateString;
}
else
{
dr[fieldName] = "-";
}
}

else
dr[fieldName] = sliAction[fieldName];
}

Send email from SharePoint web part



protected void Button1_Click(object sender, EventArgs e)
{
try
{
MailAddress[] ma = { new MailAddress("mail@mail.com") };
SendEmail(ma, "hello world from C# ", "this is sp");
SendEmailFromSP("mail@mail.com", "hello subject from SP", "hello body");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}

}


private void SendEmailFromSP(string address, string sub, string bd)
{
SPSite site = SPContext.Current.Site;
SPWeb thisWeb = site.OpenWeb();
string toField = address;
string subject = sub;
string body = bd;
bool success = SPUtility.SendEmail(thisWeb, true, true, toField, subject, body);
Console.WriteLine(success);
}

private void SendEmail(MailAddress[] masTo, string subject, string body)
{
using (MailMessage mail = new MailMessage())
{
mail.From = new MailAddress(SPContext.Current.Site.WebApplication.OutboundMailSenderAddress);
foreach (MailAddress ma in masTo)
mail.To.Add(ma);
mail.Subject = subject;
mail.IsBodyHtml = true;
mail.Body = body;
SmtpClient smtp = new SmtpClient(SPContext.Current.Site.WebApplication.OutboundMailServiceInstance.Server.Address);
smtp.UseDefaultCredentials = true;
smtp.Send(mail);
Label1.Text = "OK";
}
}

Wednesday, 14 March 2012

SharePoint 2010 REST with ASP.NET

From http://extendtheenterprise.com/2010/11/03/using-sharepoint-2010-rest-apis-in-asp-net/
with some changes to make it work for me.



Default.aspx


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="SPRest._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<style type="text/css">
table.gridtbl {
background-color: orange;
font-family: tahoma;
}
table.gridtbl TR {
background-color: white;
font-family: tahoma;
}
table.gridtbl TH {
background-color:Gray;
PADDING:4px;
color: White;
font-family: tahoma;
}
table.gridtbl TD {
PADDING:4px;
font-family: tahoma;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" CSSClass="gridtbl" CellSpacing="1" GridLines="None"/>
</div>
</form>
</body>
</html>





Default.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using SPRest.SUB1DataContext;
using System.Net;
namespace SPRest
{
public partial class _Default : System.Web.UI.Page
{
SPRest.SUB1DataContext.SUB1DataContext context = new SPRest.SUB1DataContext.SUB1DataContext(new Uri("http://blah/_vti_bin/listdata.svc"));

protected void Page_Load(object sender, EventArgs e)
{
context.Credentials = CredentialCache.DefaultNetworkCredentials;
BindData();
}

protected void BindData()
{
var custItems = from c in context.Customer.ToList()
join d in context.Purchases.ToList()
on c.CustomerID equals d.PurchaserID into TMP
from subTMP in TMP.DefaultIfEmpty()
select new
{
c.CustomerID,
c.Name,
OrderNum =(subTMP==null)? "NA" : subTMP.OrderNumber,
Product = (subTMP==null)? "NA" : subTMP.Product,
Qty = (subTMP==null)? null : subTMP.Quantity,
Price = (subTMP==null)? null : subTMP.Price
};

GridView1.DataSource = custItems;
GridView1.DataBind();
}
}
}



Result

JQuery: SharePoint field for editform.aspx

Setting fields via JQuery route.



<script src="http://code.jquery.com/jquery-latest.js"></script>


<script type="text/javascript">


$(document).ready(function () {

$("#ctl00_m_g_1596db13_5dea_457d_9096_ec6073656ee4_ctl00_ctl05_ctl01_ctl00_ctl00_ctl04_ctl00_ctl00_TextField").val("hello");
$('input[title="Name"]').val('just testing');

});</script>



How it looks, note the HTML for the input fields.

Javascript: SharePoint field for editform.aspx

This gets the parameter value of NextSubjectID and set INPUT element with Title=SubjectID on the form to desired value.

getQueryString function found here

http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript





Tuesday, 13 March 2012

JQuery with Template

Tutorial from
http://weblogs.asp.net/jan/archive/2010/10/05/getting-started-with-jquery-templates-and-sharepoint-2010.aspx

 


<script src="http://code.jquery.com/jquery.min.js" type="text/javascript"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js" type="text/javascript"></script>


<script id="tasktemplate" type="text/x-jquery-tmpl">
<li>
<b class="ms-rteFontSize-4">${Title}</b> - ${StatusValue}
<div>{{html Description}}</div>
</li>
</script>

<ul id="tasksUL"></ul>

<script type="text/javascript">
$(document).ready(function () {
$.getJSON(
"../_vti_bin/listdata.svc/Tasks?$filter=StatusValue ne 'Completed'", null,
function (data) {
alert("hello " + data.d.results);
$("#tasktemplate").tmpl(data.d.results).appendTo("#tasksUL");

});
});</script>

Monday, 12 March 2012

CAML LEFT JOIN

Trying to do a left join with CAML and found out that the only way to do it is if the lists are join with the ID field.

My Lists are set up this way,




Data for ActionList



Data for SubjectList


Here is the code that returns the data table for two columns from those two list.


private DataTable getActionSubjectListData()
{
string[] fields = { "Title", "SubjectName" };
foreach (string s in fields)
{
BoundField bf = new BoundField();
bf.DataField = s;
bf.HeaderText = s;
spgActionSubjectList.Columns.Add(bf);
}

DataTable dt = new DataTable();

dt.Columns.Add(new DataColumn("Title", Type.GetType("System.String")));
dt.Columns.Add(new DataColumn("SubjectName", Type.GetType("System.String")));

SPSite oSite = SPContext.Current.Site;
SPWeb oWeb = SPContext.Current.Web;

SPList actionList = oWeb.Lists["ActionList"];
SPList subjectList = oWeb.Lists["SubjectList"];
SPField actionSubjectID = actionList.Fields["SubjectID"];
SPField subjectTitle = subjectList.Fields["Title"];
SPField subjectIDD = subjectList.Fields["SubjectID"];
SPQuery query = new SPQuery();

query.Joins = "<Join Type='LEFT' ListAlias='SubjectList'>" +
"<Eq>" +
"<FieldRef Name='" + actionSubjectID.InternalName + "' RefType='Id'/>" +
"<FieldRef List='SubjectList' Name='ID'/>" +
"</Eq>" +
"</Join>";

query.ProjectedFields = "<Field Name='SubjectName' Type='Lookup' List='SubjectList' ShowField='" + subjectTitle.InternalName + "'/> ";


query.ViewFields = "<FieldRef Name='SubjectName' />" +
"<FieldRef Name='Title' />" ;

query.Query = "";

SPListItemCollection items = actionList.GetItems(query);

foreach(SPListItem sli in items)
{
SPFieldLookupValue lkpSubjectName = new SPFieldLookupValue(sli["SubjectName"].ToString());

dt.Rows.Add(sli.Title, lkpSubjectName.LookupValue);
}
return dt;
}



Web Part

Friday, 9 March 2012

JavaScript CEWP Query and Set Data

JavaScript help from http://www.mredkj.com/tutorials/tablebasics3.html

Create a simple list call Books, and then try pasting this into a CEWP.


<table id="mytbl">
<thead>
<tr>
<th colspan="2">header...</th>
</tr>
</thead>
<tbody></tbody>
</table>
<script type="text/javascript">




SP.SOD.executeOrDelayUntilScriptLoaded(example, 'SP.js');

function example() {
var ctx = new SP.ClientContext.get_current();
var oBooksList = ctx.get_web().get_lists().getByTitle('Books');
var caml = new SP.CamlQuery();
caml.set_viewXml("<View></View>");
this.allBooks = oBooksList.getItems(caml);
ctx.load(this.allBooks);

ctx.executeQueryAsync(
Function.createDelegate(this, this.onSucceededCallback),
null);
}

function onSucceededCallback(sender, args) {
var enumerator = this.allBooks.getEnumerator();
while (enumerator.moveNext()) {
var listItem = enumerator.get_current();
addRowInnerHTML("mytbl","ID: " + listItem.get_id() + ", Title: " +
listItem.get_item("Title"));
}
}

function addRowInnerHTML(tblId, txt)
{
var tblBody = document.getElementById(tblId).tBodies[0];
var newRow = tblBody.insertRow(-1);
var newCell0 = newRow.insertCell(0);
newCell0.innerHTML = '<input type="input" value="book" style="color: blue;" />';
var newCell1 = newRow.insertCell(1);
newCell1.innerHTML = txt;
}</script>

JavaScript CEWP with Client Context

This gets the last inserted item in table TestJS which has columns ID, Title, URL.


<a href="javascript:TEST()">Click ME!</a><script type="text/javascript">


function TEST()
{
// var myQueryString = '<View/>';

var myQueryString = "<View><Query><OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy></Query><RowLimit>1</RowLimit></View>";

var myContext = new SP.ClientContext.get_current();
var myWeb = myContext.get_web();
var myList = myWeb.get_lists().getByTitle('TestJS');
var myQuery = new SP.CamlQuery();
myQuery.set_viewXml(myQueryString);
myItems = myList.getItems(myQuery);

myContext.load(myItems,'Include(ID, Title, URL)');

myContext.executeQueryAsync(Function.createDelegate(this, TestSuccess), null);

}

function TestSuccess(sender,args)
{
var county = myItems.get_count();

var tEnumerator = myItems.getEnumerator();


var tDetails = '';

var currentEnum;
while(tEnumerator.moveNext())
{
currentEnum = tEnumerator.get_current();
tDetails = tDetails + ' ' + currentEnum.get_item('Title')
+ ' ' + currentEnum.get_item('URL');

}


alert("Query Result: " + tDetails);

alert("Last value: " + currentEnum.get_item('URL'));

}</script>


Thursday, 8 March 2012

Outer Join with Linq SharePoint 2010

With help from http://www.dotnetmafia.com/blogs/dotnettipoftheday/archive/2008/10/15/my-500th-post-left-outer-joins-with-linq.aspx, this is my outer join linq



var outerX = from cust in dataContext.Customers.ToList()
join ord in dataContext.Orders.ToList()
on cust.CustomerID.ToString().Trim()
equals ord.CustomerID.CustomerID.ToString().Trim()
into CustomerInformationGroup
from item in CustomerInformationGroup.DefaultIfEmpty(
new OrdersItem { Title="-",OrderID=0,OrderDate=DateTime.Now,Quantity=0,ProductID=new ProductsItem(),CustomerID=new CustomersItem()})
select new
{
CustomerID = cust.CustomerID,
Title = cust.Title,
City = cust.City,
CustomerCountry = cust.CustomerCountry,
JoiningDate = cust.JoiningDate,
OrderTitle = item.Title
};

dataGrdCustomer.DataSource = outerX.ToList();
dataGrdCustomer.Columns.Clear();

DataGridViewTextBoxColumn custName = new DataGridViewTextBoxColumn();
custName.DataPropertyName = "Title";
custName.Name = "Title";
custName.HeaderText = "Name";

dataGrdCustomer.Columns.Add(custName);

DataGridViewTextBoxColumn custID = new DataGridViewTextBoxColumn();
custID.DataPropertyName = "CustomerID";
custID.Name = "CustomerID";
custID.HeaderText = "CustomerID";
dataGrdCustomer.Columns.Add(custID);

DataGridViewTextBoxColumn custCity = new DataGridViewTextBoxColumn();
custCity.DataPropertyName = "City";
custCity.Name = "City";
custCity.HeaderText = "City";
dataGrdCustomer.Columns.Add(custCity);

DataGridViewTextBoxColumn custCountry = new DataGridViewTextBoxColumn();
custCountry.DataPropertyName = "CustomerCountry";
custCountry.Name = "CustomerCountry";
custCountry.HeaderText = "Country";
dataGrdCustomer.Columns.Add(custCountry);

DataGridViewTextBoxColumn prodTitle = new DataGridViewTextBoxColumn();
prodTitle.DataPropertyName = "OrderTitle";
prodTitle.Name = "OrderTitle";
prodTitle.HeaderText = "OrderTitle";
dataGrdCustomer.Columns.Add(prodTitle);


Here's the output table,

Inner join with LINQ in SharePoint 2010



var x = from cust in dataContext.Customers.ToList()
join ord in dataContext.Orders.ToList()
on cust.CustomerID.ToString().Trim() equals
ord.CustomerID.CustomerID.ToString().Trim()
select new
{
CustomerID = cust.CustomerID,
Title = cust.Title,
City = cust.City,
CustomerCountry = cust.CustomerCountry,
JoiningDate = cust.JoiningDate,
OrderTitle = ord.Title
};
dataGrdCustomer.DataSource = x.ToList();

Tuesday, 6 March 2012

Caml Query Client Object

I was wondering why the list query returns ALL of my list when the reason was that I have left out the <Query> tag! This is the working version...




SP.List oList = context.Web.Lists.GetByTitle("Projects");
CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml = "" + projectCode + "";
ListItemCollection collListItem = oList.GetItems(camlQuery);
context.Load(collListItem);
context.ExecuteQuery();

Monday, 5 March 2012

Customizing SPGridView style (with hover alt rows)

ascx


<style type="text/css">

.GridViewHeaderStyle {
background-color:#c3dde0;
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #a9c6c9;
}

.GridViewAltRowStyle
{
background-color: #F0F8FF;
font-weight: bold;
color: black;
}

.GridRowStyle
{
background-color: #E6E6FA;
font-weight: bold;
color: black;
}

.GridViewAltRowStyle:hover, .GridRowStyle:hover
{
background-color: yellow;
color: black;
font-weight: bold;
}

</style>


<SharePoint:SPGridView ID="myGridView"
runat="server" AutoGenerateColumns="false" >
</SharePoint:SPGridView>




ascx.cs


public partial class SPGridViewTestUserControl : UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
string[] fields = { "ID","Name","Country","Total"};
foreach (string s in fields)
{
BoundField bf = new BoundField();
bf.DataField = s;
bf.HeaderText = s;
myGridView.Columns.Add(bf);
}


myGridView.GroupField = "Name";
myGridView.AllowGrouping = true;
myGridView.AllowGroupCollapse = true;
myGridView.AlternatingRowStyle.CssClass = "GridViewAltRowStyle";
myGridView.RowStyle.CssClass = "GridRowStyle";

myGridView.DataSource = SelectData();
myGridView.DataBind();

// if this is set before databind, it won't include the column where the grouping is (top left)
foreach (DataControlField dcf in myGridView.Columns)
{
dcf.HeaderStyle.CssClass = "GridViewHeaderStyle";
}
}


public DataTable SelectData()
{
DataTable dataSource = new DataTable();

dataSource.Columns.Add(new DataColumn("ID", Type.GetType("System.Int32")));
dataSource.Columns.Add(new DataColumn("Name", Type.GetType("System.String")));
dataSource.Columns.Add(new DataColumn("Country", Type.GetType("System.String")));
dataSource.Columns.Add(new DataColumn("Total", Type.GetType("System.Int32")));

dataSource.Rows.Add(1, "Jack", "USA", 10000);
dataSource.Rows.Add(2, "Jack", "Thailand", 15000);
dataSource.Rows.Add(3, "Jack", "Australia", 5000);
dataSource.Rows.Add(4, "Sam", "USA", 7000);
dataSource.Rows.Add(5, "Sam", "Thailand", 30000);
dataSource.Rows.Add(6, "Sam", "Australia", 8700);
dataSource.Rows.Add(7, "Andy", "USA", 3000);
dataSource.Rows.Add(8, "Andy", "Thailand", 50000);
dataSource.Rows.Add(9, "Andy", "Australia", 25000);

return dataSource;
}
}




How it looks,