Scott Hanselman just released a new and improved list of tools for developers and power users:

Scott Hanselman's 2006 Ultimate Developer and Power Users Tool List for Windows

If you've seen his previous lists, this one won't disappoint.  I'm always guaranteed to fine a gem or two here.  I have to admit that its satisfying to see another CodeRush fan.  If you're a geek, power user or developer, go check it out.  There are tools in his updated list you didn't know you needed until you saw them.  Definitely worth the read!

drohm, Tue 08/29/06 02:18 AM

About a month ago I used one of the new features built into .NET 2.0 and didn't realize its power until just yesterday after reading an MSDN article by Ken Getz and then a blog post by Chad Finsterwald. When I first used Predicates I knew it was something that helped my code look 'cleaner' but not to the degree I found yesterday. In case you're not familiar with Predicates, they are new to .NET 2.0 and are used by collections such as Array and List to perform methods such as RemoveAll, Find, FindAll, Exists, etc.  As the MSDN documentation points out, a predicate is a delegate.  As long as the method signatures are the same then any method that conforms to the signature of the Predicate can be called in its place.  The biggest benefits of using Predicates is that they allow your code to be more expressive and promote code reuse.

I'll explain how I was using predicates initially and then show how I improved the design.  In my web application, I'm using a LookupManager class that looks up items in a database.  One of the uses for this class is to get items for say, a state dropdown control.  Each item in the state list has an Id that is reflected in the database.  In my case, I'm using Guid's as the primary key.  I don't want to insert Guid's as the value for each ListItem in the aspx page, so I'm masking those Id's.  In order for me to search the list from a postback so that I can map the MaskedId back to the original Id, I need to make use of the List's Find method.  This is where predicates help make my code cleaner.

Here is my initial implementation:

        public LookupItem GetItem(LookupType type, IdentityField id)

        {

            _searchLookupItemId = id;

            List<LookupItem> items = Lookup(type);

            LookupItem foundItem = new LookupItem();

            foundItem = items.Find(LookupItemMatchById);

 

            return foundItem;

        }

 

        public LookupItem GetItem(LookupType type, int maskedId)

        {

            _searchLookupItemMaskedId = maskedId;

            List<LookupItem> items = Lookup(type);

            LookupItem foundItem = new LookupItem();

            foundItem = items.Find(LookupItemMatchByMaskedId);

 

            return foundItem;

        }

These two methods allow me to search the List by either the Id or MaskedId.  Each one calls the List's Find method, passing in the predicate method.  Here are those methods:

        #region LookupItemMatchById(LookupItem searchItem)

        /// <summary>

        /// Predicate that finds the <see cref="DougRohm.Solid.Domain.LookupItem"/> by matching Id's.

        /// </summary>

        /// <param name="searchItem">Item to search.</param>

        /// <returns>Boolean indicating if a match was found.</returns>

        private bool LookupItemMatchById(LookupItem searchItem)

        {

            if (searchItem.Id.Value.Equals(_Id))

            {

                return true;

            }

 

            return false;

        }

        #endregion

 

        #region LookupItemMatchByMaskedId(LookupItem searchItem)

        /// <summary>

        /// Predicate that finds the <see cref="DougRohm.Solid.Domain.LookupItem"/> by matching MaskedId's.

        /// </summary>

        /// <param name="searchItem">Item to search.</param>

        /// <returns>Boolean value indicating if a match was found.</returns>

        private bool LookupItemMatchByMaskedId(LookupItem searchItem)

        {

            if (searchItem.MaskedId.Equals(_MaskedId))

            {

                return true;

            }

 

            return false;

        }

        #endregion

One thing to note here.  In each GetItem method above, I'm setting member variables that tell each predicate what to search for.  This is one of the limitations to predicates - you can't pass parameters to them.  Using member variable is a way to get around this.  The main problem with that is that it clutters up the LookupManager class.  Not only is the class cluttered with the predicates themselves, but now I'm adding more member variables. Afterall, what does the LookupManager class have to do with Finding items based on Id's or MaskedId's?  Too much noise.

The ultimate solution to this is to wrap those member variables and the predicates themselves into its own class.  This allows for even greater code reuse and simplifies the LookupManager class at the same time.  Here is my final solution:

    /// <summary>

    /// Custom predicate class used to search a <see cref="DougRohm.Solid.Domain.LookupItem"/> collection

    /// by either it's Id or MaskedId.

    /// </summary>

    public class LookupItemIdMatch

    {

        #region Fields

 

        private IdentityField _Id;

        private int _MaskedId;

 

        #endregion

 

        #region Properties

 

        public IdentityField Id

        {

            get { return _Id; }

            set { _Id = value; }

        }

 

        public int MaskedId

        {

            get { return _MaskedId; }

            set { _MaskedId = value; }

        }

 

        public Predicate<LookupItem> MatchId

        {

            get { return LookupItemMatchById; }

        }

 

        public Predicate<LookupItem> MatchMaskedId

        {

            get { return LookupItemMatchByMaskedId; }

        }

 

        #endregion

 

        #region Constructors

 

        public LookupItemIdMatch(IdentityField id)

        {

            _Id = id;

        }

 

        public LookupItemIdMatch(int maskedId)

        {

            _MaskedId = maskedId;

        }

 

        #endregion

 

        #region Predicates

 

        #region LookupItemMatchById(LookupItem searchItem)

        /// <summary>

        /// Predicate that finds the <see cref="DougRohm.Solid.Domain.LookupItem"/> by matching Id's.

        /// </summary>

        /// <param name="searchItem">Item to search.</param>

        /// <returns>Boolean indicating if a match was found.</returns>

        private bool LookupItemMatchById(LookupItem searchItem)

        {

            if (searchItem.Id.Value.Equals(_Id))

            {

                return true;

            }

 

            return false;

        }

        #endregion

 

        #region LookupItemMatchByMaskedId(LookupItem searchItem)

        /// <summary>

        /// Predicate that finds the <see cref="DougRohm.Solid.Domain.LookupItem"/> by matching MaskedId's.

        /// </summary>

        /// <param name="searchItem">Item to search.</param>

        /// <returns>Boolean value indicating if a match was found.</returns>

        private bool LookupItemMatchByMaskedId(LookupItem searchItem)

        {

            if (searchItem.MaskedId.Equals(_MaskedId))

            {

                return true;

            }

 

            return false;

        }

        #endregion

 

        #endregion

    }

There are two constructors to the class, one that takes an IdentityField and one that takes an int.  I can instantiate this class with the appropriate Id that I plan to use.  Also, there are two properties that return predicates, MatchId and MatchMaskedId.  Each property returns the appropriate internal predicate for use in external code. To use this new class back in my LookupManager class in the GetItem methods I simply 'new' up an instance of this class:

        #region GetItem(LookupType type, IdentityField id)

        /// <summary>

        /// Gets a <see cref="DougRohm.Solid.Domain.LookupItem"/> based on the Id.

        /// </summary>

        /// <param name="type">A <see cref="DougRohm.Solid.BLL.LookupType" /> for the search.</param>

        /// <param name="id">The <see cref="DougRohm.Solid.Domain.LookupItem.Id"/> for the search.</param>

        /// <returns>Returns a <see cref="DougRohm.Solid.Domain.LookupItem"/>.</returns>

        public LookupItem GetItem(LookupType type, IdentityField id)

        {

            List<LookupItem> items = Lookup(type);

            LookupItem foundItem = new LookupItem();

            foundItem = items.Find(new LookupItemIdMatch(id).MatchId);

 

            return foundItem;

        }

        #endregion

 

        #region GetItem(LookupType type, int maskedId)

        /// <summary>

        /// Gets a <see cref="DougRohm.Solid.Domain.LookupItem"/> based on the Masked Id.

        /// </summary>

        /// <param name="type">A <see cref="DougRohm.Solid.BLL.LookupType" /> for the search.</param>

        /// <param name="maskedId">The <see cref="DougRohm.Solid.Domain.LookupItem.MaskedId"/> for the search.</param>

        /// <returns>Returns a <see cref="DougRohm.Solid.Domain.LookupItem"/>.</returns>

        public LookupItem GetItem(LookupType type, int maskedId)

        {

            List<LookupItem> items = Lookup(type);

            LookupItem foundItem = new LookupItem();

            foundItem = items.Find(new LookupItemIdMatch(maskedId).MatchMaskedId);

 

            return foundItem;

        }

        #endregion

As you can see in each method, I call the Find method on the List items and instantiate the LookupItemIdMatch class passing in the search item.  I then call the property to return the correct predicate. I like this solution, its clean, elegant, and promotes code reuse. Oh, there is one other benefit to using predicates, they run faster than if you were to use foreach loops.  The performance increase isn't earth shattering, but faster nonetheless.

I hope in showing how I made use of predicates can help you.

Using the ObjectDataSource and either a GridView or DetailsView you can very easily create data-driven web sites.  What's even better about using these controls is that they give the developer a way to create data-driven pages without writing a single line of code.  All of this is great and extremely useful, up until you need to do more customized solutions.  For instance, what do you do if you need to dynamically set parameter values in the code-beside file for a GridView or DetailsView control?

You can do this by handling the appropriate event for the DataSourceControl.  The events listed below all fire before their business class methods are called making them the perfect place to do your changes or updates.

  • Selecting
  • Inserting
  • Updating
  • Deleting

There are other events you can catch and handle, but for the purposes of what we want to do, these are the events of interest.  Each of these events contain an InputParameters collection, passed in by the ObjectDataSourceMethodEventArgs parameter. Once inside the event, you can set the value of the parameter you need to modify and thats it.  Here is an example of catching the Inserting event and setting the value of the "audit" parameter.  In this case, the DetailsView is bound to a business class object.  The InsertMethod for the DetailsView has an 'audit' parameter that we need to set dynamically when the event is fired:

        protected void objCurrOption_Inserting(object sender, ObjectDataSourceMethodEventArgs e)

        {

            e.InputParameters["pollId"] = new IdentityField(e.InputParameters["pollId"].ToString());

            e.InputParameters["audit"] = new Audit(CurrentUserName, CurrentUserIP, CurrentUser);

        }

Again, this event is fired before the method on the business object is called. You can use the same method to dynamically set values for Updates, Deletes, and Selects.

drohm, Tue 08/01/06 05:32 AM

The July CTP of Atlas was released yesterday mostly as a bug-fix release. The details of the release are:

UpdatePanel and ScriptManager:
  • ScriptManager.RegisterControl() takes optional parameter to specify client type to create.
  • Fix for UpdatePanels in Firefox.
Drag and Drop:
  • Added public dragStart/dragEnd events to DragDropManager.
  • dragStart fires with dragMode, dataType, and data as eventArgs.
  • dragStop fires with empty eventArgs.
  • style.position of dragVisuals will no longer default to "absolute".
  • DragDropManager do longers disposes dropTargets when unregistering them.
  • FloatingBehavior now unregisters itself on dispose.

Head over to the Atlas web site to download the new version.