I'm adding a new field to a list and view. To add the field to the view, I'm using this code:
view.ViewFields.Add("My New Field");
However this just tacks it on to the end of the view. How do I add the field to a particular column, or rearrange the field order? view.ViewFields is an SPViewFieldCollection object that inherits from SPBaseCollection and there are no Insert / Reverse / Sort / RemoveAt methods available.
I've found removing all items from the list and readding them in the order that I'd like works well (although a little drastic). Here is the code I'm using:
string[] fieldNames = new string[] { "Title", "My New Field", "Modified", "Created" };
SPViewFieldCollection viewFields = view.ViewFields;
viewFields.DeleteAll();
foreach (string fieldName in fieldNames)
{
viewFields.Add(fieldName);
}
view.Update();
You can use the default method:
int newFieldOrderIndex = 1;
SPViewFieldCollection viewFields = view.ViewFields;
viewFields.MoveFieldTo(fieldName, newFieldOrderIndex);
view.Update();
https://msdn.microsoft.com/EN-US/library/microsoft.sharepoint.spviewfieldcollection.movefieldto.aspx
You have to use the follow method to reorder the field
string reorderMethod = #"<?xml version=""1.0"" encoding=""UTF-8""?>
<Method ID=""0,REORDERFIELDS"">
<SetList Scope=""Request"">{0}</SetList>
<SetVar Name=""Cmd"">REORDERFIELDS</SetVar>
<SetVar Name=""ReorderedFields"">{1}</SetVar>
<SetVar Name=""owshiddenversion"">{2}</SetVar>
</Method>";
I had two different lists and similar view. I wanted to update destination list view field order if user change order in source view.
ViewFieldCollection srcViewFields = srcView.ViewFields;
ViewFieldCollection destViewFields = destView.ViewFields;
var srcArray = srcViewFields.ToArray<string>();
var destArray = destViewFields.ToArray<string>();
foreach (var item in destArray)
{
destViewFields.MoveFieldTo(item, Array.IndexOf(srcArray, item));
destView.Update();
}
Related
I have a list A with columns Title, Emp ID & Start Date and End Date, Designation, in List A I have some data, and another List B column name same as List A, all are single line text and I want to retrieve all the data which is in List A using Visual Studio.
//Code
using System.Net;
using Microsoft.SharePoint.Client;
using (ClientContext context = new ClientContext("http://yourserver.sharepoint.com/")) {
context.Credentials = new NetworkCredential("user", "password", "domain");
List announcementsList = context.Web.Lists.GetByTitle("List A");
// This creates a CamlQuery that has a RowLimit of 100, and also specifies Scope="RecursiveAll"
// so that it grabs all list items, regardless of the folder they are in.
CamlQuery query = CamlQuery.CreateAllItemsQuery(100);
ListItemCollection items = announcementsList.GetItems(query);
// Retrieve all items in the ListItemCollection from List.GetItems(Query).
context.Load(items);
context.ExecuteQuery();
foreach (ListItem listItem in items)
{
// We have all the list item data. For example, Title.
label1.Text = label1.Text + ", " + listItem["Title"];
//label2.Text = label2.Text + ", " + listItem["Emp_x0020_ID"];
//EMP_x0020_ID could be internal name of SharePoint list column "EMP ID"
//Likewise check the column internal name for all the columns
//To find internal name, go to list settings and click each column
//you will see towards the end of the url something like &Field=Emp_x0020_ID
//"Emp_x0020_ID" is the internal name of the field
}
}
I hope this helps
Your question is tagged with sharepoint-online so this code will work for you. Instead of NetworkCredential (as stated in answer by #Dhurba) you have to use SharePointOnlineCredentials.
string userName = "";
string password = "";
string siteUrl = "https://tenant.sharepoint.com";
using (ClientContext cc = new ClientContext(siteUrl))
using (SecureString securedPassword = new SecureString())
{
password.ToList().ForEach(c => securedPassword.AppendChar(c));
cc.Credentials = new SharePointOnlineCredentials(userName, securedPassword);
// Load only server relative url
cc.Load(cc.Web, p => p.ServerRelativeUrl);
cc.ExecuteQuery();
// Get list by url - better than by title, because title can be different in other languages
List list = cc.Web.GetList($"{cc.Web.ServerRelativeUrl.TrimEnd('/')}/Lists/SomeListUrl");
// Load all items even if the list contains more than 5000 items,
// which is hard limit in SharePoint Online, using paggination
CamlQuery query = CamlQuery.CreateAllItemsQuery(200);
do
{
ListItemCollection items = list.GetItems(query);
cc.Load(items);
cc.ExecuteQuery();
foreach (ListItem item in items)
{
Console.WriteLine($"ID: {item.Id} | {item["InternalNameOfColumn"]}");
}
// Set position info to query
query.ListItemCollectionPosition = items.ListItemCollectionPosition;
// When there are no other items the position info will be null
} while (query.ListItemCollectionPosition != null);
}
Note:
If you are using older Visual Studio than 2017, the interpolation $"{someVariable}" will not work and you will have to replace it with eg. string.Format("{0}", someVariable).
I have a CamlQuery which I set as follows:
function getPartID(partName) {
var clientContext = new SP.ClientContext('/sites/HepatoChemKitCustomizationForms/');
var oList = clientContext.get_web().get_lists().getByTitle('PartsTable');
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name="Part_x0020_Name" /><Value Type="Text">' + partName + '</Value></Eq></Where></Query></View>');
this.collListItem = oList.getItems(camlQuery);
clientContext.load(collListItem);
clientContext.executeQueryAsync(Function.createDelegate(this, this.onPartQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}
function onPartQuerySucceeded(sender, args) {
var listItemEnumerator = collListItem.getEnumerator();
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
partID = (oListItem.get_item('Part_x0020_ID'));
}
}
'Part Name' is an existing field in the table on which I'm running the query, it is a text field, and the variable partName contains a string which is included in this field in the table.
However, the query returns the last item in the table instead of this one (one of the first items, not that it matters).
I've tried deleting the last item to see if there was something specific about that one but it happened again with the new last item.
I'm new to caml so I don't know what it going wrong with this.
Any help would be appreciated.
UPDATE:
I think I found the problem. When I ran alert (partName + " " + oListItem.get_item('Part_x0020_Name')); it shows this:
I don't know why the string is being built with a carriage return though. I use the following code to build the string:
(catalystArray[i] + "/" + baseArray[j]);
If the object from catalystArray does have a carriage return tacked onto it, how would I remove it?
UPDATE:
Solved it. Dumb mistake, but it took me all day to find.
catalystArray[i].replace(/[\n\r]+/g, '');
baseArray[i].replace(/[\n\r]+/g, '');
(catalystArray[i] + "/" + baseArray[j]);
When setting the View XML of a CAML Query object, you should include the outer <View> and <Query> elements in your XML.
If the XML is not in a format recognized by SharePoint, it'll perform a default query that will (usually) return all items. That is likely what is happening in your case, with the code enumerating through all the items in the results. As a consequence, only the last item's values are stored to the variables you expected.
I am updating a SharePoint list item using the ValidateUpdateListItem method of the client-side object model to prevent creation of a new item version. This basically works fine for all fields except the ones with person or group field type. Does anyone know what is the correct string representation of a user or group value to be used as FieldValue of an ListItemFormUpdateValue object? I have already tried everything that seems reasonable to me (user ID from User Info, login name, lookup-value like combinations of these data etc.) without any success.
I just ran into a problem where updating more than 12 person or group fields with item update caused it to throw an exception. Apparently this is caused due to the list view look up threshold in SP online (12 as of this date).
http://blog.vanmeeuwen-online.nl/2012/07/value-does-not-fall-within-expected.html
To work around that I used the ValidateUpdateListItem method to update the person or group ids. The trick is to assign it a json in the format of
[{"Key":"i:0#.f|membership|user#yoursite.onmicrosoft.com"}]
formValues.Add(new ListItemFormUpdateValue() { FieldName = "AssignedTo", FieldValue = "[{'Key':'i:0#.f|membership|user#yoursite.onmicrosoft.com'}]" });
For multiple values, it can be comma separated. Have not tried it with group but i think it should work.
Hopefully this can be useful for someone.
Unfortunately ListItem.ValidateUpdateListItem method does not support the update of user field value. For example, in the following example AssignedTo field will not be updated:
using (var ctx = GetContext(webUri, userName, password))
{
var list = ctx.Web.Lists.GetByTitle(listTitle);
var item = list.GetItemById(itemId);
var formValues = new List<ListItemFormUpdateValue>();
formValues.Add(new ListItemFormUpdateValue() { FieldName = "Title", FieldValue = taskName});
formValues.Add(new ListItemFormUpdateValue() { FieldName = "AssignedTo", FieldValue = userId.ToString() }); //not supported
item.ValidateUpdateListItem(formValues, true, string.Empty);
ctx.ExecuteQuery();
}
Instead consider ListItem.Update Method to update user field value as demonstrated below:
using (var ctx = GetContext(webUri, userName, password))
{
var list = ctx.Web.Lists.GetByTitle(listTitle);
var item = list.GetItemById(itemId);
item["Title"] = taskName;
var assignedToValue = new FieldUserValue() { LookupId = userId };
var assignedToValues = new[] { assignedToValue };
item["AssignedTo"] = assignedToValues; //multi-valued user field
item.Update();
ctx.ExecuteQuery();
}
I have a plugin that is registered Update, Order, Post Operation. In the plugin I perform a retrievemultiple on the salesorderdetail. The problem I'm having is that there are 3 products that make up the order but I am returning 5 rows from the retrieve operation. I have added and deleted the same product multiple times during my testing and I'm not sure if that's what's causing the problem. I was thinking that after deleting a product from the order it may set a flag and get deleted after, but I don't see a status code or state code as an attribute. Why would it return too many rows?
Here is my code...
// Set the properties of the QueryExpression object.
orderDetailQuery.EntityName = "salesorderdetail";
orderDetailQuery.ColumnSet = orderDetailColumnSet;
EntityCollection salesOrderDetail = service.RetrieveMultiple(orderDetailQuery);
orderProductQuery.EntityName = "product";
orderProductQuery.ColumnSet = orderProductColumnSet;
foreach (var orderDetail in salesOrderDetail.Entities)
{
if(orderDetail.Attributes.Contains("productid"))
{
productGuid = ((EntityReference)orderDetail["productid"]).Id;
Entity product = service.Retrieve("product", productGuid, orderProductColumnSet);
}
}
Thank you for the help!!
The code you posted does not show you filtering for the specific Order.
I would expect that to retrieve all entities of that type in the system.
To filter, assuming you are using a QueryByAttribute, is to add an filter along the lines of:
var query = new QueryByAttribute();
query.EntityName = "salesorderdetail";
query.AddAttributeValue("orderid", orderId);//orderId is the Id of the parent Order
orderDetailQuery.EntityName = "salesorderdetail";
orderDetailQuery.ColumnSet = orderDetailColumnSet;
var results = service.RetrieveMultiple(query);
That way you are restricting your query to just products for the given order.
I'm not sure that your filtering is implemented. Here's a shot from the hip on how you could query for instances of SalesOrderDetail entity, fetching the values of fieldName1 and fieldName2 fields provided that the it's linked to the order with guid orderId.
QueryExpression query = new QueryExpression
{
EntityName = "salesorderdetail",
ColumnSet = new ColumnSet("fieldName1", "fieldName2"),
Criteria = new FilterExpression
{
Conditions =
{
new ConditionExpression
{
AttributeName = "orderid",
Operator = ConditionOperator.Equal,
Values = { orderId }
}
}
}
};
What is the optimal way to get a list items and their properties from a SP list using Client object model?
Here is the code I'm using.
string server = "http://localhost";
ClientContext context = new ClientContext(server);
Web web = context.Web;
var spList = web.Lists.GetByTitle("Contact");
CamlQuery query = new CamlQuery();
var items = spList.GetItems(query);
context.Load(items,
itema => itema.Include(
item => item,
item => item["CustomerId"]));
context.ExecuteQuery();
Console.WriteLine("Items");
foreach (var item in items.ToList())
{
context.Load(item);
}
context.ExecuteQuery();
foreach (var item in items)
{
foreach (var a in item.FieldValues)
{
Console.WriteLine(a.Key + ":" + a.Value.ToString());
}
}
I want to remove the single liner foreach used to load list item in the context and if possible load the item field values in the first Execute Query itself.
I tried using the following
context.Load(items,
itema => itema.Include(
item => item,
item=> item.FieldValues,
item => item["CustomerId"]));
which doesn't work.
Any one can provide a cleaner solution?
The most efficient way to query SharePoint is to use a CAML Query. By calling (SP)List.GetItems(camlQuery). You will receive always an instance of (SP)ListItemCollection.
So the the most efficient query will look like this
string server = "http://localhost";
var ctx = new ClientContext(server);
var web = ctx.Web;
var list = web.Lists.GetByTitle("Contacts");
var listItemCollection = list.GetItems(CamlQuery.CreateAllItemsQuery());
// always use QueryTrimming to minimize size of
// data that has to be transfered
ctx.Load(listItemCollection,
eachItem => eachItem.Include(
item => item,
item => item["CustomerId"]));
// ExecuteQuery will pull all data from SharePoint
// which has been staged to Load()
ctx.ExecuteQuery();
foreach(ListItem listItem in listItemCollection)
{
Console.WriteLine(listItem["CustomerId"]);
}
Thorsten
I am not 100% sure what properties you would like to get from the fields but you could play around with the following:
SPSite oSite = new SPSite("http://localhost");
SPWeb oWeb = oSite.OpenWeb();
SPList oList = oWeb.Lists["LIST NAME"];
SPFieldCollection oFields = oList.Fields;
foreach (SPField oField in oFields)
{
Console.WriteLine("Property: " + oField.GetProperty("PROPERTY"));
}
OR
The property you are looking for may actually be under the SPField object. Take a look here for the properties and methods available: http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spfield_members(v=office.12).aspx
Hope this helps. If not some more info on what actual properties you want to get out of the lists' fields might help provide a more accurate solution?
Change your code to this.
IQueryable<ListItem> items = spList.GetItems(query);
Then call LoadQuery() instead of Load()
context.LoadQuery(items);
You may add additional expressions to read the property of the ListItem you wanted like this:
context.LoadQuery(items.Include(item => item["CustomerId"]));
I am actually having problem trying to do item => item.FieldValues, but item => item.FieldValuesAsText works. I am not sure why :( But just doing context.LoadQuery(items) should do what you want.
CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml = "<View Scope=\"RecursiveAll\"><Query><Where><Eq><FieldRef Name=\"FSObjType\" /><Value Type=\"Integer\">0</Value></Eq></Where></Query><RowLimit>100</RowLimit></View>";
ListItemCollection listItemCollection = srcList.GetItems(camlQuery);
srcContext.Load(listItemCollection);
await srcContext.ExecuteQueryAsync();
Querying for FSObjType=0 returns the items with all fields populated! See:
https://blog.velingeorgiev.com/sharepoint-online-csom-all-list-items-content-caml-query
The query gets all list items in batches of 100. May you just could add an AND clause to the query to get specific items.