public static void SetPropertyValue(object ctrl, string propertyName, object value, params object[] args) { // The first thing we have to do is figure out if we can tell whether or // not we're on the right thread. If we can't tell that, then this // whole thing is useless. bool needsInvoke = false; object parent = ctrl; // Get the object's Type. Type objType = ctrl.GetType(); PropertyInfo piInvoke = null; // Try and see if the passed object has a property called // "InvokeRequired". Probably not, so... if ((piInvoke = objType.GetProperty("InvokeRequired")) != null) { object retVal = piInvoke.GetValue(ctrl, null); needsInvoke = (retVal == null || retVal.GetType().Name != "Boolean") ? false : (bool)retVal; } else if ((piInvoke = objType.GetProperty("Owner")) != null || (piInvoke = objType.GetProperty("Parent")) != null) { // If it doesn't have the "InvokeRequired" property, we check to // see if it has a property named "Owner" object owner = piInvoke.GetValue(ctrl, null); if (owner != null) { // If it does, grab the owner and get it's Type. Type ownType = owner.GetType(); // Now we'll check to see if the owner has an "InvokeRequired" // property. This is the way ToolStripMenus and ToolBarMenus // work. PropertyInfo pOwn = ownType.GetProperty("InvokeRequired"); if (pOwn != null) { object retVal = pOwn.GetValue(owner, null); needsInvoke = (retVal == null || retVal.GetType().Name != "Boolean") ? false : (bool)retVal; // We have to remember which object defines our current // thread context. parent = owner; } } } else { // If none of that worked, then we can't figure it out, so just throw // an error. Otherwise we'll end up triggering one by accident or // in an infinate loop. throw new ArgumentException("Cannot determine thread context from the given object."); } // If made it this far, we found some way to determine thread context, so // now this starts to look a little more familiar. if (needsInvoke) { // The 'parent' variable will be a reference to either the passed // object or it's owner, if an "Owner" property was found. This, // also, is for ToolStripMenus and ToolBarMenus. Individual // ToolBarButtons and ToolStripMenuItems do not have "Invoke" or // "BeginInvoke" methods. We have to call their owner's methods. Type parType = parent.GetType(); Type[] paramTypes = new Type[] { typeof(Delegate), typeof(object[]) }; MethodInfo miInvoke = null; // Create the delegate like normal; SetObjectPropertyValueDelegate del = new SetObjectPropertyValueDelegate(CrossThreadUI.SetPropertyValue); // Then try and find the "Invoke" or "BeginInvoke" method. If we // don't find either, we have to throw an exception. if (CrossThreadUI.ExecSync && ((miInvoke = parType.GetMethod("Invoke", paramTypes)) != null)) { miInvoke.Invoke(parent, new object[] { del, new object[] { ctrl, propertyName, value, args } }); } else if ((miInvoke = parType.GetMethod("BeginInvoke", paramTypes)) != null) { miInvoke.Invoke(parent, new object[] { del, new object[] { ctrl, propertyName, value, args } }); } else { throw new ArgumentException("Specified object does not expose any default methods for invoking methods on its executing thread."); } } else { // Now that we've determined thread context and decided we're on the // correct thread, lets set the property value. PropertyInfo pi = objType.GetProperty(propertyName, CrossThreadUI.Binding); // Make sure the passed object's Type matches the property's Type. if (pi.PropertyType != typeof(System.String) && !value.GetType().IsAssignableFrom(pi.PropertyType)) { throw new ArgumentException("Value Type does not match property Type.", "value"); } if (pi != null) { try { pi.SetValue(ctrl, ((pi.PropertyType.FullName == "System.String") ? value.ToString() : value), args); } catch { throw; } } } }
/// <summary> /// Sets the specified property value on an object that does not inherit from System.Windows.Forms.Control. An exception will be thrown if the control /// does not expose a property with the specified name or it has neither an 'InvokeRequired' property nor an 'Owner' or 'Parent' property with /// an 'InvokeRequired' property. /// </summary> /// <param name="ctrl">The object instance whose property will be set.</param> /// <param name="propertyName">The name of the Property member that will receive the new value.</param> /// <param name="value">The value to assign to the property. This object must be properly typed to match the property's signature.</param> /// <param name="args">Any optional arguments that must be provided to access this property. Array objects must be properly typed to match property's signature.</param> public static void SetPropertyValue(object ctrl, string propertyName, object value, params object[] args) { // The first thing we have to do is figure out if we can tell whether or // not we're on the right thread. If we can't tell that, then this // whole thing is useless. bool needsInvoke = false; object parent = ctrl; // Get the object's Type. Type objType = ctrl.GetType(); PropertyInfo piInvoke = null; // Try and see if the passed object has a property called // "InvokeRequired". Probably not, so... if ((piInvoke = objType.GetProperty("InvokeRequired")) != null) { object retVal = piInvoke.GetValue(ctrl, null); needsInvoke = (retVal == null || retVal.GetType().Name != "Boolean") ? false : (bool)retVal; } else if ((piInvoke = objType.GetProperty("Owner")) != null || (piInvoke = objType.GetProperty("Parent")) != null) { // If it doesn't have the "InvokeRequired" property, we check to // see if it has a property named "Owner" object owner = piInvoke.GetValue(ctrl, null); if (owner != null) { // If it does, grab the owner and get it's Type. Type ownType = owner.GetType(); // Now we'll check to see if the owner has an "InvokeRequired" // property. This is the way ToolStripMenus and ToolBarMenus // work. PropertyInfo pOwn = ownType.GetProperty("InvokeRequired"); if (pOwn != null) { object retVal = pOwn.GetValue(owner, null); needsInvoke = (retVal == null || retVal.GetType().Name != "Boolean") ? false : (bool)retVal; // We have to remember which object defines our current // thread context. parent = owner; } } } else // If none of that worked, then we can't figure it out, so just throw // an error. Otherwise we'll end up triggering one by accident or // in an infinate loop. throw new ArgumentException("Cannot determine thread context from the given object."); // If made it this far, we found some way to determine thread context, so // now this starts to look a little more familiar. if (needsInvoke) { // The 'parent' variable will be a reference to either the passed // object or it's owner, if an "Owner" property was found. This, // also, is for ToolStripMenus and ToolBarMenus. Individual // ToolBarButtons and ToolStripMenuItems do not have "Invoke" or // "BeginInvoke" methods. We have to call their owner's methods. Type parType = parent.GetType(); Type[] paramTypes = new Type[] { typeof(Delegate), typeof(object[]) }; MethodInfo miInvoke = null; // Create the delegate like normal; SetObjectPropertyValueDelegate del = new SetObjectPropertyValueDelegate(CrossThreadUI.SetPropertyValue); // Then try and find the "Invoke" or "BeginInvoke" method. If we // don't find either, we have to throw an exception. if (CrossThreadUI.ExecSync && ((miInvoke = parType.GetMethod("Invoke", paramTypes)) != null)) miInvoke.Invoke(parent, new object[] { del, new object[] { ctrl, propertyName, value, args } }); else if ((miInvoke = parType.GetMethod("BeginInvoke", paramTypes)) != null) miInvoke.Invoke(parent, new object[] { del, new object[] { ctrl, propertyName, value, args } }); else throw new ArgumentException("Specified object does not expose any default methods for invoking methods on its executing thread."); } else { // Now that we've determined thread context and decided we're on the // correct thread, lets set the property value. PropertyInfo pi = objType.GetProperty(propertyName, CrossThreadUI.Binding); // Make sure the passed object's Type matches the property's Type. if (pi.PropertyType != typeof(System.String) && !value.GetType().IsAssignableFrom(pi.PropertyType)) throw new ArgumentException("Value Type does not match property Type.", "value"); if (pi != null) try { pi.SetValue(ctrl, ((pi.PropertyType.FullName == "System.String") ? value.ToString() : value), args); } catch { throw; } } }