Поэтому, представляю уважаемым читателям еще один мой OpenSource-проект, SharePoint 2010 Fluent Ribbon API!
Этот проект нацелен на упрощение работы с Ribbon'ом в SharePoint'е. Как известно, программное создание Ribbon'а требует выполнения большого числа действий, которые мне удалось спрятать в сборке FluentRibbon.
FluentRibbon 1.0 включают следующие основные классы:
- ContextualWebPart - базовый класс для веб-частей с контекстными вкладками риббона
- RibbonLayoutsPage - базовый класс для Application Page с риббоном
При этом, возможно динамическое создание риббона (например, в зависимости от привилегий текущего пользователя.
Chess WebPart
Вместе с FluentRibbon поставляется проект-пример ChessWebPart - веб-часть с javascript-шахматами, управление игрой и настройки в которой вынесены на риббон:
Решил вам сюда написать, так как почему gotdotnet.ru не работает
ОтветитьУдалитьВы писали использовать следующий код для добавления кнопки на ribbon:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb web = (properties.Feature.Parent as SPSite).RootWeb;
var group = new GroupDefinition()
{
Id = "Order",
Title = "Заявка на доступ к ИТ ресурсу",
Template = GroupTemplateLibrary.SimpleTemplate,
Controls = new ControlDefinition[]
{
new ButtonDefinition()
{
Id="Approve",
Title = "Утвердить",
Image = new ImageDefinition()
{
Url32 = "/_layouts/images/PpsMaAdminValid.png",
Url16 = "/_layouts/images/NoteBoard_32x32.png"
},
ToolTip = new ToolTipDefinition()
{
Title = "Утвердить",
Description = "Утвердить заявку"
},
CommandJavaScript = "alert('approve')"
}
}
};
var ribbonCustomAction = new RibbonCustomAction();
ribbonCustomAction.AddControlGroup(group, SPRibbonIds.ListForm_Display.Id, 50);
ribbonCustomAction.Provision(properties.Feature.DefinitionId, web, ListTypes.GenericList, ListForms.DisplayForm);
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPWeb web = (properties.Feature.Parent as SPSite).RootWeb;
RibbonCustomAction.RemoveAllCustomizations(web, properties.Feature.DefinitionId);
}
Добавил код такой же как у вас.
В packagе добавил: Source Path: ссылка на FluentRiboon.Dll, Deployment Target: GlobalAssemblyCashe, Safe Controls - Namespace: FluentRibbon, Assembly Name: FluentRibbon, Safe: true
Пробовал очищать кэш браузера.
При активации фичи смотрю дебагом FeatureActivated выполняется без ошибок, но кнопка на ribbon так и не добавляется.
Vladimir, ну Safe controls необязательно, в остальном вроде все нормально. У меня этот код работает, поэтому давайте сделаем проще - я выложил готовый проект, а вы уж там посмотрите, в чем была проблема :)
ОтветитьУдалитьПока что не могу подумать ни на что другое, кроме как на кэш. Если в браузере точно кэш очищен, возможно, стоит очистить каталог C:\Users\(user)\AppData\Local\assembly\dl3\, ну и т.д.
Еще можете залезть в PowerShell и проверить, что SPWeb-объект содержит в коллекции UserCustomActions эту модификацию. Делается это очень легко (естественно, нужна PowerShell-консоль SharePoint):
$w = Get-SPWeb http://localhost
$w.UserCustomActions
Не получилось почему-то в sandbox развернуть готовый проект: Error occurred in deployment step 'Add Solution': Sandboxed code execution request failed.
ОтветитьУдалитьв логах ошибка:
Updating SPPersistedObject SPFeatureDefinition Name=FeatureDefinition/45d39b27-aa81-4a82-8240-50b5a95b000a. Version: -1 Ensure: False, HashCode: 16117708, Id: 45d39b27-aa81-4a82-8240-50b5a95b000a, Stack: at Microsoft.SharePoint.Administration.SPPersistedObject.BaseUpdate() at Microsoft.SharePoint.Administration.SPPersistedChildCollection`1.Add(T newObj, Boolean ensure) at Microsoft.SharePoint.Administration.SPPersistedChildCollection`1.Add(T newObj) at Microsoft.SharePoint.Administration.SPFeatureDefinitionCollection.AddCore(SPFeatureDefinition featdef, SPSite site, String solutionHash, Boolean fForce, Boolean fDoValidation) at Microsoft.SharePoint.Administration.SPFeatureDefinitionCollection.AddInternal(String relativePathToFeatureManifest, Guid solutionId, String solutionHash, SPSite site, Boolean force, Boolean fDoValidation, SPFeatureDefinitionContext featureDefinitionContext) at Microsoft.SharePoint.Administration.SPSolutionPackage.AddFeatureDefinitions(SPFeatureDefinitionCollection featColl, SPFeatureDefinitionContext context, Boolean force, Boolean activateFeatures, SPSite site, SPWeb web) at Microsoft.SharePoint.Administration.SPUserCodeSolutionPackage.EnableSiteCollectionSolution(SPSite site, Int32 solutionGalleryItemId, Boolean force) at Microsoft.SharePoint.SPUserSolutionCollection.<>c__DisplayClass1.b__0() at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode) at Microsoft.SharePoint.SPUserSolutionCollection.AddOrUpgrade(SPListItem item, SPUserSolution existingSolution) at Microsoft.SharePoint.SPUserSolutionCollection.Add(Int32 solutionGalleryItemId) at Microsoft.VisualStudio.SharePoint.Commands.UserSolutionDeploymentManager.DeploySolution(String name, Int32 solutionFileId) at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) at System.Delegate.DynamicInvokeImpl(Object[] args) at Microsoft.VisualStudio.SharePoint.Commands.SharePointCommand.Execute(SharePointCommandContext commandContext) at Microsoft.VisualStudio.SharePoint.Commands.SharePointCommand.Execute(SharePointContext sharePointContext, CommandFlags flags, Byte[] serializedParameter, ISharePointCommandLogger logger) at Microsoft.VisualStudio.SharePoint.Commands.CommandManager.ExecuteCommand(SharePointContext sharePointContext, String commandId, CommandFlags flags, Byte[] messageBody) at Microsoft.VisualStudio.SharePoint.Commands.RemoteCommandService.ExecuteCommand(String commandId, CommandFlags flags, Byte[] messageBody)
Развернул все то же самое в ферму, в референсах и в solution использовал FluentRibbon.dll
Очистил кэш браузера, почистил папку C:\Users\(user)\AppData\Local\assembly\dl3\,
папки C:\Windows\assembly\temp\
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\Temporary ASP.NET Files\
C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\
Выполнил командлет
$w = Get-SPWeb http://localhost
$w.UserCustomActions
В коллекции UserCustomActions содержит в себе что-то.
Но в кастомном списке так и не появляется кнопка на рибоне.
Разобрался:) Беру SharePoint 2010 Fluent Ribbon API на вооружение
ОтветитьУдалитьЗдравствуйте. не могли бы показать пример для свойства CommandEnableJavaScript.
ОтветитьУдалитьМне надо реализовать следующее: добавляю кнопку на форму просмотра списка, например если в поле 'Название' написано 'Тест', то кнопку делать неактивной. Заранее благодарен.
Здравствуйте.
ОтветитьУдалитьА как сделать так, чтоб кнопка отображалась или не отображалась в зависимости от кого какие права у пользователя?
Владимир, добрый день!
ОтветитьУдалитьЕсли вы используете RibbonCustomAction для развертывания изменений ленты, то у метода
RibbonCustomAction.Provision есть оверлоады с параметром rights - соответственно, в этот параметр вы можете прописать нужные для доступа к кнопке права (с помощью флагового перечисления SPBasePermissions).
Если же вы используете RibbonController, RibbonLayoutsPage или ContextualWebpart, то можно просто формировать определение кнопки в зависимости от прав пользователя SPContext.Current.Web.CurrentUser, т.е. делать это на стороне сервера при создании определения кнопки.
Добрый день!
ОтветитьУдалитьИ все таки не могли бы показать пример для CommandEnableJavaScript. Очень надо.
new ButtonDefinition()
{
Id="ApproveOrderButton",
Title = "Утвердить",
Image = ImageLibrary.GetStandardImage(8, 4),
ToolTip = new ToolTipDefinition()
{
Title = "Утвердить заявку",
Description = "Утвердить заявку"
},
CommandJavaScript = GetApproveJavascript(),
CommandEnableJavaScript = EnableApproveButton()
}
CommandEnableJavaScript может принимать либо "true" либо "false"
пробую сделать кнопку неактивной
string EnableApproveButton()
{
string javascript = "javascript:return 'false'";
}
Но она остается активной.
Пример для CommandEnableJavaScript:
ОтветитьУдалить// Делать кнопку доступной только если в текущем представлении выбран 1 элемент списка
CommandEnableJavaScript = "SP.ListOperation.Selection.getSelectedItems().length == 1;",
с этим примером понятно, но я использую кнопку когда ribbon располагается на форме просмотра списка. Возможно ли с помощью CommandEnableJavaScript реализовать такой алгоритм: если в поле 'Название' написано 'Тест', то кнопку при открытии формы списка делать неактивной?
ОтветитьУдалитьПо ходу в этом случае это свойство не работает. Это баг?
ОтветитьУдалитьVladimir, такого рода условия если делать правильно, то придется использовать EcmaScript Client Object Model для запроса заголовка списка, потому что заголовок может быть не включен в представление. Если вы уверены, что заголовок всегда присутствует в представлении списка, можно попробовать выдрать его каким-нибудь jQuery-запросом.
ОтветитьУдалитьДа, для получения ID текущего выделенного элемента нужно использовать как раз функцию SP.ListOperation.getSelectedItems(), это массив объектов, у каждого объекта есть поле id. По SP.ListOperation много информации в MSDN и в гугле.
Андрей, а как насчет PostBack'а?
ОтветитьУдалитьhttp://blog.vitalyzhukov.ru/ru/sharepoint-2010-fluent-ribbon-events-server-handling.aspx
Что-нибудь вроде этого не пробовал добавить?
Виталий, постбэки это буу :)
УдалитьА вообще да, работа с постбэками описана в документации. Еще на эту тему публиковал статью на NothingButSharePoint про то, как работать с ToggleButton'ами и UpdatePanel'ью :).
P.S. Маленькая подсказка: в комментариях можно использовать HTML-тэги, в частности тэг <a>.
Андрей, насчет "буу": это твое мнение, а SPRibbon - вещь классная и популярная, потому, я считаю, там это должно быть. Как, например, быть, если тебе после нажатия на кнопку риббона надо изменить содержимое риббона?
УдалитьИ еще, добавь в проект классы аналогичные RibbonControl : UserControl, унаследованные от Microsoft.SharePoint.WebPartPages.WebPartPage,
Microsoft.SharePoint.WebControls.LayoutsPageBase,
Microsoft.SharePoint.WebPartPages.WikiEditPage. Или расскажи, почему этого не будет.
Согласен, красивую обертку написать можно. Но как минимум пример работы с постбэками есть в документации, т.е. на текущий момент это наверное всё-таки не суперкритично.
УдалитьВ общем, я создал задачу, сроков никаких не могу дать, но как минимум я подумаю как её лучше сделать и со временем сделаю. К слову, CodePlex очень хорошо поддерживает возможность предложения патчей и вообще командной разработки, так что если вдруг есть интерес помочь проекту и написать тот или иной функционал, это можно обсудить.
Насчет контролов и страниц, скорее всего делать не буду, потому что есть и другие проблемы, которые возникают из-за жесткой привязки к наследованию. Например, были вот такие жалобы:
1. Нельзя создать две вкладки на одной странице
2. У некоторых людей были определены свои наследники для LayoutsPageBase например, поэтому они иногда вообще не могли использовать RibbonLayoutsPage без редизайна собственного кода
Все это было известно и обсуждалось на CodePlex'е. Было создано даже несколько задач по этому поводу.
Именно поэтому я в конечном итоге вывел класс RibbonController в "public", и теперь предлагаю использовать его вместо наследования от RibbonControl или RibbonLayoutsPage. Пользоваться им довольно удобно, почти никакого лишнего кода не будет. В рабочем проекте, мы уже полностью перешли на его использование.
С огромным удовольствием при участие в проекте. Мне на проекте пришлось взять исходники и дописать функционал необходимый для проекта. Отсюда и мой пост появился. Я думаю, моя ситуация стандартна.
УдалитьОбсуждения на CodePlex'е не читал, каюсь.
По поводу RibbonController'а: я сделал метод расширитель для класса Page, чтобы регистрировать таб на странице, сделал кэширование и прочее. Хотелось бы поделиться.
Чуть не забыл: Спасибо за SPRibbon
Коллеги, у меня одного при разворачивании проекта не активируются фичи?
ОтветитьУдалитьСоздал проект веб-парта. Добавил туда код, использующий эту гениальную API. Код добавляет пару кнопок в рибон.
Потом пытаюсь разворачиваться и мне говорят. "Ошибка в шаге развертывания "Активация компонентов": В экземпляре объекта не задана ссылка на объект.".
Если я потом открываю список фич и активирую её вручную то всё работает, но вот из VS мне нормально проект не развернуть. Точнее он разворачивается, но фичи не активируются. Лог мне ничего интересного не выдал.
Андрей, на Codeplex есть примеры (вкладка Source Code) с использованием этого API, и всё работает как часы. Рекомендую исследовать и делать по аналогии.
УдалитьНа самом деле, баги бывают, к сожалению. Например, возможно, какой-нибудь параметр в определении кнопок не заполнен или заполнен не так как я это задумывал. Я был бы очень признателен, если бы вы запостили код определения ваших кастомизаций риббона на Codeplex в Discussions (там есть форматирование кода), я бы попробовал воспроизвести ошибку.
День добрый! как можно привязать кнопку на рибоне к определенному списку?
ОтветитьУдалитьЗдравствуйте, Екатерина.
УдалитьИспользуйте метод RibbonCustomAction.Provision. Туда передавайте объект SPList, соответствующий вашему списку.
Большое спасибо)) работает! А если взять не список, а библиотеку документов? не смотря на то, что библиотеку можно взять как splist, ничего не отображается на ленте где расположена библиотека документов. Есть какая то разница между списком и библиотекой?
УдалитьЕлена, там используются разные вкладки, у которых соответственно разные ID'ы.
УдалитьТ.е. например, чтобы добавить группу на вкладку где расположены кнопки для элементов списка, нужно при Provision указывать ID целевой вкладки "Ribbon.ListItem", а для библиотеки документов - "Ribbon.Document". Напомню, эти ID-шники в Fluent Ribbon проще всего получать из класса SPRibbonIds.
Этот комментарий был удален автором.
УдалитьСпасибо, все работает :) только я Катя)) еще вопросик... можно ли к такой кнопке прикрутить функционал, который написан на C#, а не на javascript(commandjavascript)?
ОтветитьУдалить_dopostnack, see examples on CodePlex
УдалитьHi. Cuold you tell me how to run javascript on Tab something like "Tab.Loaded(javascript)". I need to change RibbonLabel.Text (with value from UserControl "some" Label on same page). I can't use javascript from UserControl becouse Ribbon panel loads later then UC. Or you have some solution....
ОтветитьУдалитьЗдравствуйте, помогите начинающему, пожалуйста - второй день мучаюсь.
ОтветитьУдалитьКак к кнопке Save (button.Command = SPRibbonIds.ListForm_Edit.Groups.Commit.ControlIds.Publish;) прикрутить JavaScript, который бы работал ПОСЛЕ сохранения элемента.
Я уже кучу вариантов передумал: думал, что ткну на эту кнопку JavaScript'ом, затем сделаю, что нужно. Но у ней id не постоянный. Еще был вариант найти вызываемый этой командой js код, тут тоже крах. Дошел до команды Ribbon.ListForm.Edit.Commit.Publish, и все, сам код где-то запрятан - неизвестно где.
День добрый!
УдалитьЗадача не такая уж простая даже для многих "профессионалов"...
В общем случае необходимо выполнить два шага:
1. Заменить кнопку Save на свою собственную с помощью кастомизаций риббона
2. В качестве обработчика использовать свой кастомный обработчик, в котором сначала вызвать стандартную команду, потом выполнить свой код
Чтобы заменить стандартную кнопку на свою, надо пойти в 14\TEMPLATE\GLOBAL\XML\CMDUI.XML и подсмотреть там определение для кнопки. Задеплоить это определение, но вместо стандартного обработчика указать свой.
В SharePoint Ribbon API для замены стандартных кнопок есть специальный класс ControlLibrary.StandardButtons, который очень легко использовать. Конкретно и с примером как это сделать - описано здесь.
Чтобы вызвать стандартную команду для кнопки из обработчика, нужно использовать SP.Ribbon.PageManager. Команда выглядит примерно так:
var commandName = "StandardCommandName";
SP.Ribbon.PageManager.get_instance().executeRootCommand(commandName, window.g_CUIcommandProperties, {CommandId: commandName}, null);
Т.е. в твоем случае commandName должно быть "Ribbon.ListForm.Edit.Commit.Publish".
Я не тестировал конкретно для Publish, но для других команд такой способ работает отлично.
В частности, вот мой ответ на SP SE, где спрашивали почти идентичный вопрос про подмену команды "DownloadCopy": Attach a Javascript function to an OOTB ribbon button.
Этот комментарий был удален автором.
УдалитьБольшое спасибо за ответ,
Удалитьи я сейчас глупый вопрос задать хочу: а как к кнопке свой обработчик прикрутить?
Вот то есть я создаю кнопку:
var someBtn = ControlLibrary.StandardButtons.ListForm_Edit.Commit_Publish("", SPContext.Current.Web.Locale.LCID);
button.Command = SPRibbonIds.ListForm_Edit.Groups.Commit.ControlIds.Publish;
А что дальше?
Здравствуйте, Андрей!
ОтветитьУдалитьПодскажите, пожалуйста, возможно ли в PWA (SharePoint 2010) с помощью Javascript переключать представления с одного на другое, например, в "Центре проектов" или "Отчете по задачам"?
Виталий, здравствуйте! К сожалению с PWA практически не работал, поэтому ничего не могу сказать про переключение представлений :(
УдалитьСпасибо за отклик!
УдалитьА вообще возможно с помощью javascript управлять выпадающими списками в SharePoint 2010, а конкретно программно выбирать пункты выпадающего списка?