In creating a custom XAML UserControl, a need arose to make use of generics with the UserControl class. The control is based upon the XAML AutoSuggestionBox control and implements a quick lookup of a user from an app supplied list of users. The control uses Linq queries to efficiently search through a list of type User using Name and Id properties. The search can be on partial name completion or on user’s initials. So as to allow the use of a broad range of list types for the supplied user list, as provided in the UserControl’s hosting app, the app’s user type needs to implement a specific set of properties that are used in queries and so it must implement a specific interface (called IUser). It would have been nice to have parameterised the UserControl class using generics to specify the list of users’ data type as the apps user type and constrain it to implement the interface using generics. But the custom UserControl class does not permit generics.
Consider the following:
public class AClass<T> where T : IUser { }
This permits the passing of a generic class T to the class when it is instantiated, but T must implement the IUser interface. Now try to do the same with a custom UserControl class:
public sealed partial class CustomControl<T> : UserControl where T: IUser { public CustomControl() { this.InitializeComponent(); } }
You get a message that says there is no InitializeComponent method that take a T parameter.
The solution covered here uses Reflection (System.Reflection). It facilitates the generic passing of a list of any class type passed as an object and at first casts to an IList class. If successful with that, the data type of the elements in the IList (actually an array) are investigated. The interfaces of the elements’ data type are determined and a check for the required interface, IUser is made. If this all aligns, then Reflection is used to cast the elements to the base class of the interface (User) and a list of the User data type is generated within the custom control for its searches.
Nb1: The User class is the base class from which the interface IUser is generated. Application user list data types are then effectively a auperclass of the User class in that they will in general, have all of the interface properties and more. The control implementation could have required that the app user type inherit directly upon the User type (as an explicit extension of the User class). You can assign or cast down from the extended class instance to the base class, just losing the extended information. But this was envisaged as too much push back from the control; although it is a valid and perhaps simpler solution. But hey, lets dive into some Reflection!
Nb2: With Reflection we can programmatically at runtime, get an object’s class type, its interfaces, properties, methods and events. Knowing its properties we can actually get the values of the properties. So it would indeed be possible to generically cast any class that has the User properties down to the User class, without the app class declaring it allegiance to the IUsr interface, . Going further, we could even programmatically map suitable properties and values in a non-conforming class instance. These mapping could be part of the custom UserControl setting.