Navigatie

Contact

Send mail to the author(s) E-mail

View Richard Soeteman's profile on LinkedIn

RSS 2.0 | Atom 1.0 | CDF

Archief

Categorieën

Blogroll

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Sign In

Zoeken

# Sunday, 22 February 2009
Sunday, 22 February 2009 10:38:11 (GMT Standard Time, UTC+00:00) ( ASP.NET | Umbraco )

This Blog is not active anymore, further posts will be available on my company website. Read new posts here

Yesterday I gave a demo about events in Umbraco V4. I did this by describing a few "Business problems" that could be solved using events. A few facts about events in Umbraco V4:

  • You find events on every Component in Umbraco.
  • To uses events, you need references to the businesslogic, cms and interfaces assemlies.
  • To use events, you have to create a class that uses umbraco.BusinessLogic.ApplicationBase as the base class.  In the constructor you can wire up the event handler. These classes will be automaticly picked up when you put the file in the App_Code folder of Umbraco or put the compiled DLL in the bin folder of Umbraco. I prefer the last one.
  • Most of the event args derive from CancelEventArgs, so we can cancel the operation.
  • Because an event executes in the background you should always document that you're using events and make sure you will write a logmessage when you're event handler gets executed.

For my demo's, I've used an Umbraco V4 installation with the Creative Website Wizard installed.

Demo 1 Auto Expire news

In the first demo.I've showed how the document.BeforePublish can be used to check if  a news item is allready expired, if so cancel the publish event, otherwise check if the expire date is set and if not, set the expire date to 14 days from now.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Text;
   4:  using umbraco.BusinessLogic;
   5:  using umbraco.cms.businesslogic.web;
   6:   
   7:  namespace AutoExpire
   8:  {
   9:      /// <summary>
  10:      /// 
  11:      /// </summary>
  12:      public class Expire :ApplicationBase
  13:      {
  14:          /// <summary>
  15:          /// Constructor used to wire up the event
  16:          /// </summary>
  17:          public Expire()
  18:          {
  19:              Document.BeforePublish += new Document.PublishEventHandler(Document_BeforePublish);
  20:          }
  21:   
  22:          /// <summary>
  23:          /// Check if the news item is expired, or check if we need to set the expire date
  24:          /// </summary>
  25:          void Document_BeforePublish(Document sender, umbraco.cms.businesslogic.PublishEventArgs e)
  26:          {
  27:              //Always LOG
  28:              Log.Add(LogTypes.Custom, sender.Id, "Event raised");
  29:              //Check if the doctype is news
  30:              if (sender.ContentType.Alias == "News")
  31:              {
  32:                  //Check if the expiredate is filled and the value is not allready expired
  33:                  if (sender.ExpireDate != DateTime.MinValue && sender.ExpireDate < DateTime.Now)
  34:                  {
  35:                      //Item is expired, cancel the publish
  36:                      e.Cancel = true;
  37:                  }
  38:                  else
  39:                  {
  40:                      //Date is not set set it now and save the doc. Probably better to to this in the before save event
  41:                      //since this is a demo it's allowed to do it here
  42:                      sender.ExpireDate = DateTime.Now.AddDays(14);
  43:                      sender.Save();
  44:   
  45:                  }
  46:              }
  47:          }
  48:      }
  49:  }

During this demo someone asked if it's possible to show a custom message in the speechbubble event when an event is canceled. This is not possible (tested it this morning), I've created an item on CodePlex.

Demo 2 Auto archive news

In this Demo I've created some functionality to automaticly move a news item to the archive folder when a content manager sets the archive boolean to true. First an archive boolean must be added to the news document and a new Archive folder must be created where we can store the archived News items in.

   1:  using umbraco.BusinessLogic;
   2:  using umbraco.cms.businesslogic.web;
   3:   
   4:  namespace AutoMoveToArchive
   5:  {
   6:      /// <summary>
   7:      /// Auto move demo
   8:      /// </summary>
   9:      public class AutoMoveToArchive : ApplicationBase
  10:      {
  11:          /// <summary>
  12:          /// Wire up the event handler
  13:          /// </summary>
  14:          public AutoMoveToArchive()
  15:          {
  16:              Document.BeforeSave += new Document.SaveEventHandler(Document_BeforeSave);
  17:          }
  18:   
  19:          /// <summary>
  20:          /// Before a documents get saved we wil check if the archived proerty is.
  21:          /// When it's set move it to the archive folder.
  22:          /// Again it;s demo code, normally you should also check if it's not allready IN the archived foder ;-)
  23:          /// </summary>
  24:          void Document_BeforeSave(Document sender, umbraco.cms.businesslogic.SaveEventArgs e)
  25:          {
  26:              // Set Arrchive folder id, no excuse to use hard coded values in Umbraco ;-)
  27:              int archiveId = 1123; 
  28:              //Log that we are doing something
  29:              Log.Add(LogTypes.Custom, sender.Id, "Document After save Raised");
  30:   
  31:              //Check if the item is news and must be archived
  32:              if (sender.ContentType.Alias == "News" && sender.getProperty("archived").Value.Equals(1))
  33:              {
  34:                  //Yes, move to archive
  35:                  sender.Move(archiveId);
  36:   
  37:                  //Unpublish from current Node
  38:                  umbraco.library.UnPublishSingleNode(sender.Id);
  39:                  sender.UnPublish();
  40:                  //Publish will get called if the user selected Save and publish
  41:              }
  42:          }
  43:      }
  44:  }

Demo 3 Add Unpublish menu Item to the Context menu

In this demo I've showed that we can use events to modify the context menu. I'm missing a unpublish item  in the context menu. This example is a little bit harder because we we need to create a menu item also. A menu item can be created to create a class that derives from the IAction interface. I will leave the explanation of this interface for a future blogpost.

   1:  using System;
   2:  using umbraco.BusinessLogic;
   3:  using umbraco.cms.presentation.Trees;
   4:  using umbraco.interfaces;
   5:   
   6:  namespace UnpublishAction
   7:  {
   8:      /// <summary>
   9:      /// Add unpublish to the menu item
  10:      /// </summary>
  11:      public class AddUnpublishActionEvent :ApplicationBase
  12:      {
  13:          public AddUnpublishActionEvent()
  14:          {
  15:              BaseContentTree.BeforeNodeRender += new BaseTree.BeforeNodeRenderEventHandler(BaseTree_BeforeNodeRender);
  16:          }
  17:   
  18:          /// <summary>
  19:          /// Before a menu item gets rendered  we will add the unpublish action if the document is published
  20:          /// </summary>
  21:          private void BaseTree_BeforeNodeRender(ref XmlTree sender, ref XmlTreeNode node, EventArgs e)
  22:          {
  23:              ///Only unpublish when published
  24:              if (node.Menu!= null && !node.NotPublished.GetValueOrDefault(true))
  25:              {
  26:                  //Find the publish action and add 1 for the index, so the position of the ubpublish  is direct after the publish menu item
  27:                  int index = node.Menu.FindIndex(delegate(IAction a) { return a.Alias == "publish"; })+1;
  28:   
  29:                  //Insert unpublish action
  30:                  node.Menu.Insert(index, UnpublishAction.Instance);
  31:              }
  32:          }
  33:      }
  34:  }

Download the complete solution for this demo here.

Demo 4 Invisible for Writer Usertype

In the last demo I've showed how to use the AfterNodeRender event to make protected nodes invisble for the Writer UserType

   1:  using System;
   2:  using umbraco.BusinessLogic;
   3:  using umbraco.cms.presentation.Trees;
   4:   
   5:  namespace OnlyForAdmins
   6:  {
   7:      /// <summary>
   8:      /// Makes a document invisible for writers
   9:      /// </summary>
  10:      public class MenuIsNotForWriters : ApplicationBase
  11:      {
  12:          /// <summary>
  13:          /// Wire up the event handler
  14:          /// </summary>
  15:          public MenuIsNotForWriters()
  16:          {
  17:              BaseContentTree.AfterNodeRender += new BaseTree.AfterNodeRenderEventHandler(BaseContentTree_AfterNodeRender);
  18:          }
  19:   
  20:          /// <summary>
  21:          /// Removes node from menu tree if page is protected and the user is a writer
  22:          /// </summary>
  23:          void BaseContentTree_AfterNodeRender(ref XmlTree sender, ref XmlTreeNode node, EventArgs e)
  24:          {
  25:              //check if page is protecetd and the usertype is writer
  26:              if (node.IsProtected.GetValueOrDefault(false) && umbraco.helper.GetCurrentUmbracoUser().UserType.Alias == "writer")
  27:              {
  28:                  //Writers cannot see protected pages
  29:                  sender.Remove(node);
  30:              }
  31:          }
  32:      }
  33:  }

Overview of all Events

Class Events
Access  
 

BeforeSave
AfterSave
BeforeAddProtection
AfterAddProtection
BeforeRemoveProtection
AfterRemoveProtection
BeforeAddMemberShipRoleToDocument AfterAddMemberShipRoleToDocument BeforeRemoveMemberShipRoleToDocument AfterRemoveMemberShipRoleToDocument BeforeRemoveMembershipUserFromDocument AfterRemoveMembershipUserFromDocument BeforeAddMembershipUserToDocument AfterAddMembershipUserToDocument

BaseTree  
 

BeforeNodeRender
AfterNodeRender

CMSNode  
 

BeforeSave
AfterSave
AfterNew
BeforeDelete
AfterDelete
BeforeMove
AfterMove

content  
 

BeforeUpdateDocumentCache
AfterUpdateDocumentCache
BeforeClearDocumentCache
AfterClearDocumentCache
BeforeRefreshContent
AfterRefreshContent

CreatedPackage  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete
BeforePublish
AfterPublish

DataType  
 

Saving
New
Deleting

Dictionary  
 

Saving
New
Deleting

Document  
 

BeforeSave 
AfterSave 
New 
BeforeDelete 
AfterDelete 
BeforePublish 
AfterPublish 
BeforeSendToPublish 
AfterSendToPublish 
BeforeUnPublish 
AfterUnPublish 
BeforeCopy 
AfterCopy 
BeforeRollBack 
AfterRollBack 
BeforeAddToIndex 
AfterAddToIndex

DocumentType  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

Domain  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

InstalledPackage  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

Language  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

Macro  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

Media  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

MediaType  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

Member  
 

BeforeSave
AfterSave
New
BeforeAddGroup
AfterAddGroup
BeforeRemoveGroup
AfterRemoveGroup
BeforeAddToCache
AfterAddToCache
BeforeDelete
AfterDelete

MemberGroup  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

MemberType  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

StyleSheet  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

StylesheetProperty  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

Template  
 

BeforeSave
AfterSave
New
BeforeDelete
AfterDelete

User  
 

Saving
New
Disabling
Deleting
FlushingFromCache
BeforeSave
AfterSave
New
BeforeDelete
AfterDelete
BeforePublish
AfterPublish

Sunday, 22 February 2009 11:16:10 (GMT Standard Time, UTC+00:00)
Very nice post Richard! I really like that the examples you provide show events used on other classes than Document as we're used to from the old Action Handler model.
Sunday, 22 February 2009 19:04:45 (GMT Standard Time, UTC+00:00)
um, holy crap! nice job... that sounds like it was a great session!
Monday, 23 February 2009 08:21:02 (GMT Standard Time, UTC+00:00)
Hey Richard, that is a wicked post.
It would be good to have some more examples/ideas/demos of how you could use these actionHandlers. I like the way you was able to add to the context menu.

I would highly recommend you do a track or at least an openspace session on this at CG09 as I would love to learn more about it.

Warren
Monday, 23 February 2009 08:29:18 (GMT Standard Time, UTC+00:00)
Thanks Richard for the demonstrations you gave, they were very interesting. Be sure to fix your laptop for the next meeting :-)

I just voted for the item of custom messages if an event is cancelled, and I also added an issue to codeplex to make the help button configurable (as discussed in the meeting):
http://www.codeplex.com/umbraco/WorkItem/View.aspx?WorkItemId=21317

Nico
Nico Lubbers
Monday, 23 February 2009 11:50:51 (GMT Standard Time, UTC+00:00)
Thank you for nice samples.
Petr Snobelt
Monday, 23 February 2009 16:13:50 (GMT Standard Time, UTC+00:00)
@All Thanks,

@Warren. I can do a practical hanking demo as Open space session at CG09. It will be my first CG and if I have to do a session on the first day I will be to nervous. Maybe next year, Open Space will be okay. Thanks for suggesting.

@Nico Next time we will buy a beamer from Dell ;-) it was frustrating. Good that you voted and created a workitem yourself. I hope that both workitems will be picked up by the core team.
Comments are closed.