SharePoint 2010. PostBack для Fluent Ribbon API

Пост о том как добавить серверную обработку нажатия на кнопку на рибоне, созданном с помощью SharePoint 2010 Fluent Ribbon API.

Новое в коде

FluentRibbon.Definitions.Controls.ButtonBaseDefinition

Первое, что нам понадобится - регистрация методов-обработчиков событий.

Для начала добавим два поля: первое для регистрации метода-обработчика, второе для хранения аргумента:

  1. /// <summary>
  2. /// PostBack argument
  3. /// </summary>
  4. public string ButtonActionArgument = string.Empty;
  5.  
  6. /// <summary>
  7. /// PostBackaction
  8. /// </summary>
  9. public Action<string> ButtonAction;

PostBack на стороне клиента будет вызываться стандартным javascript-методом __doPostBack. В качестве аргументов этому методу мы будем передавать уникальный идентификатор кнопки (свойство FullId) и сам аргумент из поля ButtonActionArgument. Следуя вышесказанному заменим поле CommandJavaScript в классе на одноименное свойство с несложной логикой:

  1. /// <summary>
  2. /// Javascript will be run when button is pressed.
  3. /// Required for all types of buttons.
  4. /// By default, button does nothing.
  5. /// </summary>
  6. public string CommandJavaScript
  7. {
  8.     get
  9.     {
  10.         if (ButtonAction == null)
  11.             return _commandJavaScript;
  12.         return string.Format("{0}; __doPostBack('{1}',{2});"
  13.             _commandJavaScript, 
  14.             FullId, 
  15.             ButtonActionArgument);
  16.     }
  17.     set
  18.     {
  19.         _commandJavaScript = value;
  20.     }
  21. }
  22.  
  23. private string _commandJavaScript;

В этом свойстве я оставил вызов стандартной javascript-команды перед отправкой формы на сервер. В таком случае надо быть внимательней и избегать возврата управления (return) в javascript'е.

Обработка PostBack'а на сервере

Теперь осталось реализовать вызов делегата, указанного в новом поле ButtonAction. Я сделал это на примере класса FluentRibbon.RibbonControl:

  1. protected override void OnLoad(EventArgs e)
  2. {
  3.     base.OnLoad(e);
  4.     // Если PostBack'а не было, то выходим
  5.     if (!Page.IsPostBack) return;
  6.     var target = Request.Form["__EVENTTARGET"];
  7.     var argument = Request.Form["__EVENTARGUMENT"];
  8.     // Получаем таб
  9.     var tabs = GetTabDefinition();
  10.     var controls = new List<ButtonBaseDefinition>();
  11.     // Перебираем группы на рибоне
  12.     if (tabs.Groups.Length > 0)
  13.     {
  14.         // Кнопки верхнего уровня, расположенные на рибоне
  15.         var firstLevelControls = tabs.Groups
  16.             .SelectMany(g => g.Controls)
  17.             .OfType<ButtonBaseDefinition>();
  18.         // Кнопки второго уровня, расположенные
  19.         // внутри контейнеров
  20.         var secondLevelControls = firstLevelControls
  21.             .OfType<IContainer>()
  22.             .SelectMany(c => c.Controls)
  23.             .OfType<ButtonBaseDefinition>();
  24.  
  25.         controls.AddRange(firstLevelControls);
  26.         controls.AddRange(secondLevelControls);
  27.  
  28.         // Ищем наш контрол
  29.         var targetControl = controls
  30.             .Where(c => c.FullId == target)
  31.             .FirstOrDefault();
  32.         // Если контрол найден и действие указано, то вызываем его, передав аргумент
  33.         if (targetControl != null)
  34.         {
  35.             if (targetControl.ButtonAction != null)
  36.             {
  37.                 targetControl.ButtonAction.Invoke(argument);
  38.             }
  39.         }
  40.     }
  41. }

Вот и все изменения нам необходимые. Я привел пример только для класса FluentRibbon.RibbonControl. Для реализации этой функциональности в классе FluentRibbon.RibbonLayoutsPage, придется либо копировать её из RibbonControl'а, либо выносить в третий класс.

Результат

Теперь классы в проекте выглядят несколько иначе:

Применение

Очень просто и понятно, я думаю, без дополнительных комментариев:

  1. public override TabDefinition GetTabDefinition()
  2. {
  3.     // Создаем кнопку, вызывающую PostBack
  4.     var postBackButton = new ButtonDefinition
  5.                                 {
  6.                                     Id = "PostBackButton",
  7.                                     Title = "PostBack Button",
  8.                                     Image = ImageLibrary.GetStandardImage(10, 10),
  9.                                     ButtonAction = CustomRibbonButtonDefinition
  10.                                 };
  11.     // Возвращаем таб с PostBack-кнопкой
  12.     return new TabDefinition()
  13.                 {
  14.                     Id = "PostBackTab",
  15.                     Title = "PostBackTab",
  16.                     Groups = new[]
  17.                     {
  18.                     new GroupDefinition()
  19.                         {
  20.                             Id = "PostBackGroup",
  21.                             Title = "PostBackGroup",
  22.                             Template = GroupTemplateLibrary.SimpleTemplate,
  23.                             Controls = new ControlDefinition[] {postBackButton}
  24.                         }
  25.                     }
  26.                 };
  27. }
  28.  
  29. // Обработчик нажатия на PostBack-кнопку
  30. public void CustomRibbonButtonDefinition(string arg)
  31. {
  32.     var id = 0;
  33.     if(int.TryParse(arg, out id))
  34.     {
  35.         //var repository = new DocumentRepository();
  36.         // ...
  37.     }
  38. }

JavaScript в качестве аргумента

Также можно в качестве аргумента передавать какую-нибудь javascript-функцию. Примерно вот так:

  1. // Создаем кнопку, вызывающую PostBack
  2. var postBackButton = new ButtonDefinition
  3.                   {
  4.                       Id = "PostBackButton",
  5.                       Title = "PostBack Button",
  6.                       Image = ImageLibrary.GetStandardImage(10, 10),
  7.                       ButtonAction = CustomRibbonButtonDefinition,
  8.                       ButtonActionArgument = "SP.ClientContext.get_current().get_url()"
  9.                   };

Update

Также рекомендую почитать пост Андрея Маркеева и комментарии к нему здесь.

Виталий Жуков

Виталий Жуков

Техлид, Архитектор, Разработчик, Microsoft MVP. Более 20 лет опыта в области системной интеграции и разработки программного обеспечения. Специализируюсь на проектировании и внедрении масштабируемых высокопроизводительных программных решений в различных отраслях.

Смотрите также