Friday, April 23, 2010

List Item Ranking - Order your list items just like ordering columns in your list!

I wrote this code a while ago.  It took a lot of debugging and its not very elegant but I was pretty pressed for time.  If you have any suggestions on how to streamline, I'd like to hear them.

I also wrote code to attach to all custom lists via a feature.  This makes it easy to enable and disable.  Also, this has a transaction log functionality built to to archive changes in another list.  Ranks are 1-5 and are based on a field 'category'.  For example you can have 1-5 fruits, and 1-5 in category vegetables, so there are seperate 1-5 threads going on in the list.  This can be disabled by removing the category checks.

I can show the list attaching code as well if requested, I think its pretty useful.  This post is already long enough.


public override void ItemAdding(SPItemEventProperties properties)
    {
      try
      {
        this.DisableEventFiring();
        SPSite siteCollection = new SPSite(properties.WebUrl);
        SPWeb srcSite = siteCollection.OpenWeb();
        SPList srcList = srcSite.Lists[properties.ListId];
        //SPListItem srcItem = properties.ListItem;
        string myRank = properties.AfterProperties["Rank"].ToString();
        string myCategory = properties.AfterProperties["Category"].ToString();

        if (int.Parse(myRank) < 5)
        {
          IncrementRanks(srcList, myRank, myCategory, properties);
        }

        siteCollection.Dispose();
        srcSite.Dispose();
      }
      catch (Exception ex)
      {
        properties.ErrorMessage = ex.Message + " - " + ex.Data + " + " + ex.StackTrace;
        properties.Cancel = true;   
      }
      finally
      {
        this.EnableEventFiring();
      }
      //base.ItemAdding(properties);
    }

    public override void ItemUpdated(SPItemEventProperties properties)
    {
      base.ItemUpdated(properties);
    }

    public override void ItemUpdating(SPItemEventProperties properties)
    {
      try
      {
        this.DisableEventFiring();
        SPSite siteCollection = new SPSite(properties.WebUrl);
        SPWeb srcSite = siteCollection.OpenWeb();
        SPList srcList = srcSite.Lists[properties.ListId];
        //SPListItem srcItem = properties.ListItem;
        string myRank = properties.AfterProperties["Rank"].ToString();
        string myCategory = properties.AfterProperties["Category"].ToString();

        if (int.Parse(myRank) < 5 & !myRank.Equals(properties.ListItem["Rank"].ToString()))
        {
          IncrementRanks(srcList, myRank, myCategory, properties);
        }
 
        siteCollection.Dispose();
        srcSite.Dispose();
      }
      catch (Exception ex)
      {
        properties.ErrorMessage = ex.Message + " + " + ex.Data + " + " + ex.StackTrace;
        properties.Cancel = true;
      }

      try
      {
        //create transaction
        SPListItem newItem = properties.OpenWeb().Lists["Transaction Log"].Items.Add();

        foreach (SPField spf in properties.ListItem.Fields)
        {
          if (newItem.Fields.ContainsField(spf.Title) & !spf.Hidden & !spf.ReadOnlyField &
            !String.IsNullOrEmpty(properties.ListItem.GetFormattedValue(spf.Title)))
          {
            if (!spf.Title.Equals("Attachments"))
            {
              if (newItem.Fields.GetField(spf.Title).GetType() == spf.GetType())
              {
                newItem[spf.Title] = properties.ListItem[spf.Title];
              }
              else
              {
                newItem[spf.Title] = properties.ListItem.GetFormattedValue(spf.Title);
              }
            }
          }
        }
        newItem.Update();
      }
      catch (Exception ex)
      {
        properties.ErrorMessage = ex.Message + " - " + ex.Data + " - " + ex.StackTrace;
        properties.Cancel = true;
      }
      finally
      {
        this.EnableEventFiring();
      }
    }

    private static void IncrementRanks(SPList srcList, string myRank, string category, SPItemEventProperties properties)
    {
      bool rankExists = false;
      //check if there exists a duplicate rank
      SPListItem sameLiRank = null;
      foreach (SPListItem spli in srcList.Items)
      {
        string itemRank = spli["Rank"].ToString();
        if (itemRank == myRank & spli["Category"].ToString().Equals(category))
        {
          rankExists = true;
          sameLiRank = spli;
          break;
        }
      }

      int myRankint = int.Parse(myRank);
      
      int existingItemRank = 0;
      int myOldRank = 0;
      if(sameLiRank != null)
        existingItemRank = int.Parse(sameLiRank["Rank"].ToString());

      if (properties.ListItem != null)
        myOldRank = int.Parse(properties.ListItem["Rank"].ToString());

      if (rankExists & properties.ListItem != null & (myOldRank == existingItemRank - 1 | myOldRank == existingItemRank + 1))
      {
        sameLiRank["Rank"] = myOldRank.ToString();
        sameLiRank.SystemUpdate();
      }
      else if (rankExists)
      {
        List gList = new List();
        List rankedItems = new List();

        foreach (SPListItem spli in srcList.Items)
        {
          //set up our array of ranks
          int liRank = int.Parse(spli["Rank"].ToString());
          if (liRank < 5 & spli["Category"].ToString().Equals(category)) // filter category here 
            rankedItems.Add(spli);
        }

        //sort the items
        rankedItems.Sort(delegate(SPListItem li1, SPListItem li2) {
          return li1["Rank"].ToString().CompareTo(li2["Rank"].ToString());
        });

        foreach (SPListItem spli in rankedItems)
        {
          bool doIt = false;
          if(object.Equals(properties.ListItem, null))
          {
            doIt = true;
          }
          else if(properties.ListItem.UniqueId != spli.UniqueId)
          {
            doIt = true;
          }
          if (!string.IsNullOrEmpty(spli["Rank"].ToString()) &
            int.Parse(spli["Rank"].ToString()) >= myRankint & doIt) //fix issue so item shouldnt modify itself
          { //check for +1 and exit loop if there isnt
            
            spli["Rank"] = int.Parse(spli["Rank"].ToString()) + 1;
            spli.SystemUpdate();
          }
        }
      }
    }

No comments: