如何使用SharePoint library
获取特定CSOM
的所有子文件夹列表?当用户点击“选择文件夹”时,我想提供与SharePoint相同的功能。
我发现这篇文章CAML and the Client Object Model我认为非常好,但是当我尝试以下内容时,我会收到错误:
using (ClientContext clientContext = new ClientContext(this.SpSite))
{
var web = clientContext.Web;
var list = web.Lists.GetByTitle('Contracts');
var query = new CamlQuery();
query.FolderServerRelativeUrl = "/Contracts";
query.ViewXml = "<View Scope='RecursiveAll'>"
+ "<Query>"
+ " <Where>"
+ " <Eq><FieldRef Name='FSObjType' /><Value Type='Integer'>1</Value></Eq>"
+ " </Where>"
+ "</Query>"
+ "</View>";
var folderItems = list.GetItems(query);
clientContext.Load(folderItems);
clientContext.ExecuteQuery();
foreach (ListItem item in folderItems)
{
// item[ "..." ];
}
}
我也尝试过不同的CALM查询,但无济于事:
query.ViewXml = "<View Scope=\"RecursiveAll\"> " +
"<Query>" +
"<Where>" +
"<Eq>" +
"<FieldRef Name=\"FileDirRef\" />" +
"<Value Type=\"Text\">" + title + "</Value>" +
"</Eq>" +
"</Where>" +
"</Query>" +
"</View>";
任何帮助都将不胜感激。
感谢。
UPDATE-1:
我在StackExchange
上发现了一个问题How to traverse SharePoint Library in Client Object Model?,它与我的需求非常接近,但仍然存在一些问题:
它使用递归,这意味着如果你有很多级别,它最终会产生大量请求,并且可能显示非常慢。
未订购退回的数据。基于我提供的快照,而不是返回01,02,03等...它以随机顺序返回值。
我希望我能够拨打一个电话并获取所有文件夹和子文件夹的列表,但我想这也可能最终耗费时间。
我想我有几个选择:
坚持递归方法,弄清楚如何整理数据,但我仍需要弄清楚后者。
仅在顶层请求文件夹,并且仅在展开文件夹时按需请求子文件夹。理想情况下,如果使用这种方法,最好知道一个文件夹是否有任何子文件夹,这意味着还必须解决这个问题。
到达那里,但还没到那里。
所以如果有人可以提供额外的反馈,片段,任何事情,请做。
感谢。
答案 0 :(得分:1)
对于一次加载所有文件夹的情况,我建议进行以下调整:
由于CSOM API已经包含the built in method,因此加载所有文件夹项可以这样执行:
var folderItems = list.GetItems(CamlQuery.CreateAllFoldersQuery());
其次,我建议从关联的列表项中检索文件夹对象:
var allFolders = folderItems.Select(i => i.Folder).ToList();
示例:
public static List<Folder> GetAllFolders(List list)
{
var ctx = list.Context;
var folderItems = list.GetItems(CamlQuery.CreateAllFoldersQuery());
ctx.Load(folderItems, icol => icol.Include(i => i.Folder));
ctx.ExecuteQuery();
var allFolders = folderItems.Select(i => i.Folder).ToList();
return allFolders;
}
由于从性能角度加载整个文件夹结构可能是一个瓶颈,为避免您考虑按需加载方法:
加载表单后,检索 1st 级别文件夹列表并填充树视图:
var list = ctx.Web.Lists.GetByTitle(libraryTitle);
var folders = FolderManager.GetFolders(list.RootFolder);
var rootNode = new TreeNode(libraryTitle);
folderSelector.Nodes.Add(rootNode);
foreach (var folder in folders)
{
var folderNode = new TreeNode(folder.Name) {Tag = folder};
rootNode.Nodes.Add(folderNode);
}
然后根据需要加载子文件夹,并在触发expand
事件后填充节点:
private void folderTreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
if (e.Node.Level > 0 ) //skip root level
{
var folders = FolderManager.GetFolders((Folder)e.Node.Tag);
foreach (var folder in folders)
{
var folderNode = new TreeNode(folder.Name) { Tag = folder };
e.Node.Nodes.Add(folderNode);
}
}
}
,其中
public static List<Folder> GetFolders(Folder parentFolder)
{
var ctx = parentFolder.Context;
var result = ctx.LoadQuery(parentFolder.Folders.Where(f => !f.ListItemAllFields.ServerObjectIsNull.Value));
ctx.ExecuteQuery();
return result.ToList();
}
答案 1 :(得分:0)
我最终使用Caml Designer 2013搞清楚了。这个概念非常好,但对于我的品味仍然非常不稳定,这使得它无法使用,但经过多次试验和错误后,我最终查看了“查询选项”部分。
事实证明,在本节中,有一个处理文件夹和选项的选项。子文件夹,它最终为我生成了正确的Calm查询。
这是最后的结果:
using (ClientContext clientContext = new ClientContext(this.SpSite))
{
List spList = clientContext.Web.Lists.GetByTitle(title);
clientContext.Load(spList);
clientContext.ExecuteQuery();
if (spList != null && spList.ItemCount > 0)
{
CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml =
"<View Scope='RecursiveAll'>"
+ " <Query>"
+ " <Where>"
+ " <Eq><FieldRef Name='FSObjType' /><Value Type='Integer'>1</Value></Eq>"
+ " </Where>"
+ " </Query>"
+ " <ViewFields><FieldRef Name='Title' /></ViewFields>"
+ "</View>";
ListItemCollection listItems = spList.GetItems(camlQuery);
clientContext.Load(listItems);
clientContext.ExecuteQuery();
foreach (var item in listItems)
{
Debug.WriteLine($"Title: {item.FieldValues["Title"]}
- FileRef: {item.FieldValues["FileRef"]}
- FileLeafRef: {item.FieldValues["FileLeafRef"]}");
}
}
}
以上代码生成了以下结果:
Title: 2016 - FileRef: /Contracts/2016 - FileLeafRef: 2016
Title: 2017 - FileRef: /Contracts/2017 - FileLeafRef: 2017
Title: 01 - FileRef: /Contracts/2016/01 - FileLeafRef: 01
Title: 02 - FileRef: /Contracts/2016/02 - FileLeafRef: 02
Title: 03 - FileRef: /Contracts/2016/03 - FileLeafRef: 03
Title: 04 - FileRef: /Contracts/2016/04 - FileLeafRef: 04
Title: 05 - FileRef: /Contracts/2016/05 - FileLeafRef: 05
Title: 06 - FileRef: /Contracts/2016/06 - FileLeafRef: 06
Title: 07 - FileRef: /Contracts/2016/07 - FileLeafRef: 07
Title: 08 - FileRef: /Contracts/2016/08 - FileLeafRef: 08
Title: 09 - FileRef: /Contracts/2016/09 - FileLeafRef: 09
Title: 10 - FileRef: /Contracts/2016/10 - FileLeafRef: 10
Title: 11 - FileRef: /Contracts/2016/11 - FileLeafRef: 11
Title: 12 - FileRef: /Contracts/2016/12 - FileLeafRef: 12
Title: 01 - FileRef: /Contracts/2017/01 - FileLeafRef: 01
Title: 02 - FileRef: /Contracts/2017/02 - FileLeafRef: 02
Title: 03 - FileRef: /Contracts/2017/03 - FileLeafRef: 03
Title: 04 - FileRef: /Contracts/2017/04 - FileLeafRef: 04
Title: 05 - FileRef: /Contracts/2017/05 - FileLeafRef: 05
Title: 06 - FileRef: /Contracts/2017/06 - FileLeafRef: 06
Title: 07 - FileRef: /Contracts/2017/07 - FileLeafRef: 07
Title: 08 - FileRef: /Contracts/2017/08 - FileLeafRef: 08
Title: 09 - FileRef: /Contracts/2017/09 - FileLeafRef: 09
Title: 10 - FileRef: /Contracts/2017/10 - FileLeafRef: 10
Title: 11 - FileRef: /Contracts/2017/11 - FileLeafRef: 11
Title: 12 - FileRef: /Contracts/2017/12 - FileLeafRef: 12
所以,我还要做的就是查看FieldValues字典中返回的其他属性,看看是否有一个可以帮助我识别父节点或子节点,但即使已经存在,也可以轻松解析诀窍。
希望这有助于节省您的时间!
PS:我不知道你们中的任何一位SharePoint专家是否注意到了,但我原来的问题代码看起来与解决方案非常相似,但它没有产生相同的结果。如果这是一个快速突出的内容,请分享,因为我很想知道,但不能再花时间在这个问题上。