Archive

Archive for December, 2012

C#: How to set or get value of a private or internal property through the Reflection

December 17th, 2012 3 comments

    Quite often in my practice I need to interact with hidden (internal and private) properties of an object. It easily can be done through the Reflection API. The only complication may arise here it’s when a private property is defined in one of the base classes. In this case we have to iterate through the object’s class hierarchy, looking for the property. So, trying to simplify getting and setting values of object’s private and internal properties, I’ve implemented a couple of the methods-extensions listed below. The GetPropertyValue method returns value of a private or internal property, and the SetPropertyValue, in turn, sets value to a private or internal property.

public static class ReflectionHelper
{
 private static PropertyInfo GetPropertyInfo(Type type, string propertyName)
 {
   PropertyInfo propInfo = null;
   do
   {
     propInfo = type.GetProperty(propertyName, 
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
     type = type.BaseType;
   }
   while (propInfo == null && type != null);
   return propInfo;
 }

 public static object GetPropertyValue(this object obj, string propertyName)
 {
   if (obj == null)
     throw new ArgumentNullException("obj");
   Type objType = obj.GetType();
   PropertyInfo propInfo = GetPropertyInfo(objType, propertyName);
   if (propInfo == null)
     throw new ArgumentOutOfRangeException("propertyName", 
       string.Format("Couldn't find property {0} in type {1}", propertyName, objType.FullName));
   return propInfo.GetValue(obj, null);
 }

 public static void SetPropertyValue(this object obj, string propertyName, object val)
 {
    if (obj == null)
      throw new ArgumentNullException("obj");
    Type objType = obj.GetType();
    PropertyInfo propInfo = GetPropertyInfo(objType, propertyName);
    if (propInfo == null)
      throw new ArgumentOutOfRangeException("propertyName", 
        string.Format("Couldn't find property {0} in type {1}", propertyName, objType.FullName));
    propInfo.SetValue(obj, val, null);
 }
}

Below is how to use the methods. Let’s assume we have the following hierarchy of classes:

class SomeBase
{
    private bool IsLimited { get; set; }

    public SomeBase()
    {
        IsLimited = false;
    }
}

class SomeClass : SomeBase
{
    private  string Str { get; set; }
    internal int    Int { get; set; }

    public SomeClass()
    {
        Str = "initial value";
        Int = 0;
    }
}

So, we need to get and set hidden properties’ values from within a project (library) different to the one where the SomeBase and SomeClass are located. A possible code may look like the following:

SomeClass someObj = new SomeClass();

// the Str and Int properties will be found on the first step of iteration, 
// so, the base class won't be analyzed
string currentStrValue = (string)someObj.GetPropertyValue("Str");
int    currentIntValue = (int)someObj.GetPropertyValue("Int");

// the IsLimited propertiy will be found on the second step of iteration, 
// so, the base class will be analyzed as well
bool currentBoolValue = (bool)someObj.GetPropertyValue("IsLimited");

// the Str and Int properties will be found on the first step of iteration, 
// so, the base class won't be analyzed
someObj.SetPropertyValue("Str", "brand new value");
someObj.SetPropertyValue("Int", -1);

// the IsLimited propertiy will be found on the second step of iteration, 
// so, the base class will be analyzed as well
someObj.SetPropertyValue("IsLimited", true);
Related posts:
Categories: C#, Reflection Tags: ,

jQuery: Plugins to handle long click and taphold events

December 3rd, 2012 1 comment

jQuery plugin to catch a long click event

Below is a simple jQuery plugin to catch a long click or long press:

(function ($) {
  $.fn.longClick = function (callback, timeout) {
   // bind to element's mousedown event to track the longclick's beginning
   $(this).mousedown(function (event) {
    // save the initial event object
    var initialEvent = event;
    // set the delay after which the callback will be called
    var timer = window.setTimeout(function () { callback(initialEvent); }, timeout);
    // bind to global mouseup event for clearance
    $(document).mouseup(function () {
      // clear timer
      window.clearTimeout(timer);
      // unbind from global mouseup event
      $(document).unbind("mouseup");
      return true;
      // use 'return false;' if you need to prevent default handler and 
      // stop event bubbling
    });
     return true;
     // use 'return false;' if you need to prevent default handler and 
     // stop event bubbling
   });
  };
})(jQuery);

...
// using
(function ($) {
  $("#someDiv").longClick(function (e) { 
              alert($(e.target).attr("id") + " was clicked"); }, 
              1500);	
})(jQuery);

The plugin accepts a callback function that will be called once a long click event occurred and a timeout in milliseconds saying how long user should keep button pressed to produce the long click.

jQuery plugin to catch a taphold event

The same long click for iPad is usually called taphold and can be implemented as follows:

(function ($) {
  $.fn.taphold = function (callback, timeout) {
   // bind to element's touchstart event to track the taphold's beginning
   $(this).bind("touchstart", function (event) {
    // save the initial event object
    var initialEvent = event;
    // set the delay after which the callback will be called
    var timer = window.setTimeout(function () { callback(initialEvent); }, timeout);
    // bind to global touchend and touchcancel events for clearance
    $(document).bind("touchend touchcancel", function () {
      // clear timer
      window.clearTimeout(timer);
      // unbind from touchend and touchcancel events
      $(document).unbind("touchend touchcancel");                
      return true;
      // use 'return false;' if you need to prevent default handler and 
      // stop event bubbling
    });            
    return true;            
    // use 'return false;' if you need to prevent default handler and 
    // stop event bubbling
   });
  };
})(jQuery);

...
// using
(function ($) {
  $("#someDiv").taphold(function () { 
               alert($(e.target).attr("id") + " was tapholded"); }, 
               1500);
})(jQuery);

The only difference from the previous plugin is that touchable device’s events are used.

Combined jQuery plugin to catch both long click and taphold events

Two shown above plugins can be quite easily combined in one. The new plugin checks if the current device is an iPad and, if so, deals with such iPad events as touchstart, touchend and touchcancel; otherwise, it uses traditional mousedown and mouseup.

(function ($) {
 $.fn.longclick = function (callback, timeout) {
   var isIPad = $.isIPad();

   var startEvents = isIPad ? "touchstart" :           "mousedown";
   var endEvents   = isIPad ? "touchend touchcancel" : "mouseup";

   $(this).bind(startEvents, function (event) {
    // save the initial event object
    var initialEvent = event;
    // set delay after which the callback will be called
    var timer = window.setTimeout(function () { callback(initialEvent); }, timeout);
    // bind to global event(s) for clearance
    $(document).bind(endEvents, function () {
        // clear timer
        window.clearTimeout(timer);
        // reset global event handlers
        $(document).unbind(endEvents);
        return true;
        // use 'return false;' if you need to prevent default handler and 
        // stop event bubbling
    });
    return true;
    // use 'return false;' if you need to prevent default handler and 
    // stop event bubbling
   });
 };
})(jQuery);

...
// using
(function ($) {
    $("#someDiv").longclick(function () { 
             alert($(e.target).attr("id") + " was clicked"); }, 
             1500);
})(jQuery);

Note that the isIPad plugin was described in the post – jQuery: Plugins to detect iPad and iPhone devices.

Related posts:
Categories: iPad, JavaScript, jQuery Tags: , ,