Synopsis:
We would like to build an object which has in-built support to change notification support and different types of validation features including Required, Regular Expression and Custom validations without having to add INotifyPropertyChanged interface implementation in the component. Interesting? Read the following article.
Article:
Problem Statement:
As we know, WPF supports very good data binding features bound to CLR Objects / XML data source providers. In order to avail binding in an object, of course, we have to make sure that the object at-least supports the implementation of INotifyPropertyChanged interface if we can’t have Dependency Properties. So, when it comes to simple properties, we need to ensure that all properties setter implementation triggers an event to notify to update the values in the User Interface. If your component has more number of properties, it suddenly becomes cluttered in the code. And over a period of time, it is very difficult to maintain the solution as well.
Solution:
Having said this, by taking advantages of .NET 4.0 Dynamic Programming capabilities, it becomes sort of a relief in creating such components very easily. Idea goes like this …
We would like to have our object as simple as possible, like the example given below.
public class Employee
{
[Required(ErrorMessage = "Id Required")]
public string EmployeeId { get; set; }
{
[Required(ErrorMessage = "Id Required")]
public string EmployeeId { get; set; }
[Required(ErrorMessage = "Name Required")]
public string EmployeeName { get; set; }
public string EmployeeName { get; set; }
[Range(2000, 50000, ErrorMessage = "Package Offered Not In Range")]
public int PackageOffered { get; set; }
public int PackageOffered { get; set; }
[RegularExpression(@"\d{3,5}-\d{6,8}", ErrorMessage = @"Phone Not Valid")]
public string Phone { get; set; }
public string Phone { get; set; }
public override string ToString()
{
return string.Format(@”{0}, {1}, {2}, {3}”,
this.EmployeeId, this.EmployeeName, this.PackageOffered, this.Phone);
}
}
{
return string.Format(@”{0}, {1}, {2}, {3}”,
this.EmployeeId, this.EmployeeName, this.PackageOffered, this.Phone);
}
}
Note: No implementation of INotifyPropertyChanged interface has been provided in the Employee component.
Let’s now build a general purpose component which accepts a Generic Type, and inherits DynamicObject of .NET 4.0 to encapsulate such that all calls made toEmployee class get diverted to this component. And this class going to provide the implementation of INotifyPropertyChanged interface, and apply validation logic as well.
We would call this component as DynamicBaseEntity, and will have mainly two important method implementations such as TryGetMember and TrySetMember to perform dynamic setting and getting values and validations. And, in many cases we might need to convert the our Dynamic Object into original object ie., Employee. So, we could be able to pass entity objects into subsequent layers.
public class DynamicBaseEntity<T> : DynamicObject, INotifyPropertyChanged where T : new()
{
private Type tType = typeof(T);
private object instance = default(object);
{
private Type tType = typeof(T);
private object instance = default(object);
public DynamicBaseEntity()
{
instance = new T();
}
{
instance = new T();
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var isSuccess = default(bool);
var property = tType.GetProperty(binder.Name, BindingFlags.Public | BindingFlags.Instance);
result = default(object);
{
var isSuccess = default(bool);
var property = tType.GetProperty(binder.Name, BindingFlags.Public | BindingFlags.Instance);
result = default(object);
if (property == null)
return isSuccess;
return isSuccess;
result = property.GetValue(instance, null);
isSuccess = true;
return result != null && isSuccess;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var isSuccess = default(bool);
var property = tType.GetProperty(binder.Name, BindingFlags.Public | BindingFlags.Instance);
{
var isSuccess = default(bool);
var property = tType.GetProperty(binder.Name, BindingFlags.Public | BindingFlags.Instance);
if (property == null)
return isSuccess;
return isSuccess;
value = Convert.ChangeType(value, property.PropertyType);
property.SetValue(instance, value, null);
var attributes = property.GetCustomAttributes(typeof(ValidationAttribute), true);
foreach (ValidationAttribute attribute in attributes)
Validator.ValidateProperty(value, new ValidationContext(instance, null, null)
{
MemberName = property.Name
});
Validator.ValidateProperty(value, new ValidationContext(instance, null, null)
{
MemberName = property.Name
});
Notify(binder.Name);
isSuccess = true;
return isSuccess;
}
}
private void Notify(string propertyName)
{
if (propertyName != null && PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
{
if (propertyName != null && PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
result = (T)instance;
{
result = (T)instance;
return instance != null && result != null;
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
Let me explain the above implementation.
a. In the constructor we create an instance of the type we intend to.
b. TryGetMember method implemented such that we retrieve value from the original object using Reflection.
c. TrySetMember method has been implemented such that we set the value to the original object using Reflection with appropriate validation execution logic. Along-with, we have also the implementation of change notification.
d. TryConvert method implemented for the sake of retrieving original object from Dynamic Object.
Now have a look at the usage of this DynamicBaseEntity component in a typical application:
public static class MainClass
{
public static void Main(string[] args)
{
dynamic dynamicObject = new DynamicBaseEntity<Employee>();
{
public static void Main(string[] args)
{
dynamic dynamicObject = new DynamicBaseEntity<Employee>();
dynamicObject.PropertyChanged += new PropertyChangedEventHandler((objSender, objArgs) =>
{
Console.WriteLine(“Argument Value Changed : ” + objArgs.PropertyName);
});
{
Console.WriteLine(“Argument Value Changed : ” + objArgs.PropertyName);
});
try
{
dynamicObject.EmployeeId = “E10001″;
dynamicObject.EmployeeName = “Ramkumar JD”;
dynamicObject.Phone = “080-3984343″;
dynamicObject.PackageOffered = 12000;
}
catch (Exception exceptionObject)
{
Console.WriteLine(“Error : ” + exceptionObject.Message);
}
{
dynamicObject.EmployeeId = “E10001″;
dynamicObject.EmployeeName = “Ramkumar JD”;
dynamicObject.Phone = “080-3984343″;
dynamicObject.PackageOffered = 12000;
}
catch (Exception exceptionObject)
{
Console.WriteLine(“Error : ” + exceptionObject.Message);
}
Employee eObject = (Employee)dynamicObject;
Console.WriteLine(eObject.ToString());
Console.ReadLine();
Console.ReadLine();
}
}
I’ve provided an implementation of WPF application which uses this feature.
NOTE: If you see the limitations of this solution, VS 2010 or XAML designer may not offer intellisense support to the type, as we resolve all properties of the object at runtime.
I’ve provided the implementation in the Dynamic Object such a way that it throws an exception when you try to set / get a property which is not found in the type we intend to dynamically work on.
Hope it benefits you and reduces our effort in building Entity objects that support Data Binding for WPF applications.
Looking for complete source code with a sample application?
Click here to continue downloading from SkyDrive.