Archives

Archives / 2012 / December
  • ASP.NET Web Forms Extensibility: Expression Builders

    I have talked extensively about expression builders in the past, and that is because I find them extremely useful, for building no code solutions.

    In a nutshell, it is a design-time mechanism for executing a method which receives some parameters and returns something that will be bound to a control’s property. Anyone who has used resources – <%$ Expression:xxx %> -, bound a connection string or an application setting to a data source control – <%$ ConnectionStrings:xxx %> and <%$ AppSettings:xxx %> – on an ASP.NET page has used expression builders. These expression builders are included with ASP.NET, and do useful things, such as returning a connection string or an application setting from the configuration file, or returning a translated resource according to the current browser culture, without the need to code.

    One example would be, for example, picking up some value from the current HttpContext and assigning it to some control’s property. Here’s a simple way to achieve it, using DataBinder.Eval to process possibly complex expressions:

       1: public class ContextExpressionBuilder : ExpressionBuilder
       2: {
       3:     #region Public static methods
       4:     public static Object GetValue(String expression, Type propertyType)
       5:     {
       6:         HttpContext context = HttpContext.Current;
       7:         Object expressionValue = DataBinder.Eval(context, expression.Trim().Replace('\'', '"'));
       8:  
       9:         expressionValue = Convert(expressionValue, propertyType);
      10:  
      11:         return (expressionValue);
      12:     }
      13:  
      14:     #endregion
      15:  
      16:     #region Public override methods
      17:     public override Object EvaluateExpression(Object target, BoundPropertyEntry entry, Object parsedData, ExpressionBuilderContext context)
      18:     {
      19:         return (GetValue(entry.Expression, entry.PropertyInfo.PropertyType));
      20:     }
      21:     #endregion
      22:  
      23:     #region Protected static methods
      24:     protected static Object Convert(Object value, Type propertyType)
      25:     {
      26:         if (value != null)
      27:         {
      28:             if (propertyType.IsAssignableFrom(value.GetType()) == false)
      29:             {
      30:                 if (propertyType.IsEnum == true)
      31:                 {
      32:                     value = Enum.Parse(propertyType, value.ToString(), true);
      33:                 }
      34:                 else if (propertyType == typeof(String))
      35:                 {
      36:                     value = value.ToString();
      37:                 }
      38:                 else if ((typeof(IConvertible).IsAssignableFrom(propertyType) == true) && (typeof(IConvertible).IsAssignableFrom(value.GetType()) == true))
      39:                 {
      40:                     value = System.Convert.ChangeType(value, propertyType);
      41:                 }
      42:             }
      43:         }
      44:  
      45:         return (value);
      46:     }
      47:     #endregion
      48:  
      49:     #region Public override methods
      50:     public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, Object parsedData, ExpressionBuilderContext context)
      51:     {            
      52:         if (String.IsNullOrEmpty(entry.Expression) == true)
      53:         {
      54:             return (new CodePrimitiveExpression(String.Empty));
      55:         }
      56:         else
      57:         {
      58:             return (new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(this.GetType()), "GetValue"), new CodePrimitiveExpression(entry.Expression.Trim()), new CodeTypeOfExpression(entry.PropertyInfo.PropertyType)));
      59:         }
      60:     }
      61:     #endregion
      62:  
      63:     #region Public override properties
      64:     public override Boolean SupportsEvaluate
      65:     {
      66:         get
      67:         {
      68:             return (true);
      69:         }
      70:     }
      71:     #endregion
      72: }

    As you can see, there are two methods that may be called in order to retrieve a value:

    In this example, I have implemented both methods, so that it can be used in various scenarios. On the GetCodeExpression method I simply return a Code DOM expression that calls the static method GetValue on my expression builder. I have a method that tries to convert the returned value into the target property on the declaring control, in case they are of different types.

    Expression builders need to be registered on the Web.config file, on the expressionBuilders section:

       1: <configuration>
       2:     <system.web>
       3:         <compilation>
       4:             <expressionBuilders>
       5:                 <add expressionPrefix="Context" type="MyNamespace.ContextExpressionBuilder, MyAssembly"/>
       6:             </expressionBuilders>
       7:         </compilation>

    Finally, here’s how to use this sample expression builder to feed a Label text on a markup file:

       1: <span>Value of cookie MyId: <asp:Label runat="server" Text="<%$ Context:Request.Cookies['MyId'].Value %>" /></span>

    This is identical to having the following code:

       1: myLiteral.Text = HttpContext.Current.Request.Cookies["MyId"].Value;

    The syntax is <%$ MyRegisteredPrefix: SomeString %>, where MyRegisteredPrefix is what you want it to be, and what is registered on Web.config, and SomeString is also a randomly-formed string. Note that the expression builders forbid us to using in this string, so, what I did was allow to be used instead, and replace them at runtime.

    What remains to be said is regarding editors for allowing integrated expression builder design inside Visual Studio, but since that is strictly not required, I leave it to some other time.

    As usual, hope you find this of use. Look for the other expression builders that I wrote, all code is available on the blog.

    Read more...

  • Windows Presentation Foundation 4.5 Cookbook Review

    Windows Presentation Foundation 4.5 Cookbook

    As promised, here’s my review of Windows Presentation Foundation 4.5 Cookbook, that Packt Publishing kindly made available to me.

    It is an introductory book, targeted at WPF newcomers or users with few experience, following the typical recipes or cookbook style. Like all Packt Publishing books on development, each recipe comes with sample code that is self-sufficient for understanding the concepts it tries to illustrate.

    It starts on chapter 1 by introducing the most important concepts, the XAML language itself, what can be declared in XAML and how to do it, what are dependency and attached properties as well as markup extensions and events, which should give readers a most required introduction to how WPF works and how to do basic stuff.

    It moves on to resources on chapter 2, which also makes since, since it’s such an important concept in WPF.

    Next, chapter 3, come the panels used for laying controls on the screen, all of the out of the box panels are described with typical use cases.

    Controls come next in chapter 4; the difference between elements and controls is introduced, as well as content controls, headered controls and items controls, and all standard controls are introduced. The book shows how to change the way they look by using templates.

    The next chapter, 5, talks about top level windows and the WPF application object: how to access startup arguments, how to set the main window, using standard dialogs and there’s even a sample on how to have a irregularly-shaped window.

    This is one of the most important concepts in WPF: data binding, which is the theme for the following chapter, 6. All common scenarios are introduced, the binding modes, directions, triggers, etc. It talks about the INotifyPropertyChanged interface and how to use it for notifying data binding subscribers of changes in data sources. Data templates and selectors are also covered, as are value converters and data triggers. Examples include master-detail and sorting, grouping and filtering collections and binding trees and grids. Last it covers validation rules and error templates.

    Chapter 7 talks about the current trend in WPF development, the Model View View-Model (MVVM) framework. This is a well known pattern for connecting things interface to actions, and it is explained competently. A typical implementation is presented which also presents the command pattern used throughout WPF. A complete application using MVVM is presented from start to finish, including typical features such as undo.

    Style and layout is covered on chapter 8. Why/how to use styles, applying them automatically,  using the many types of triggers to change styles automatically, using Expression Blend behaviors and templates are all covered.

    Next chapter, 9, is about graphics and animations programming. It explains how to create shapes, transform common UI elements, apply special effects and perform simple animations.

    The following chapter, 10, is about creating custom controls, either by deriving from UserControl or from an existing control or framework element class, applying custom templates for changing the way the control looks. One useful example is a custom layout panel that arranges its children along a circumference.

    The final chapter, 11, is about multi-threading programming and how one can integrate it with WPF. Includes how to invoke methods and properties on WPF classes from threads other than the main UI, using background tasks and timers and even using the new C# 5.0 asynchronous operations.

    It’s an interesting book, like I said, mostly for newcomers. It provides a competent introduction to WPF, with examples that cover the most common scenarios and also give directions to more complex ones. I recommend it to everyone wishing to learn WPF.

    Read more...

  • Loading Entities Dynamically with Entity Framework

    Sometimes we may be faced with the need to load entities dynamically, that is, knowing their Type and the value(s) for the property(ies) representing the primary key.

    One way to achieve this is by using the following extension methods for ObjectContext (which can be obtained from a DbContext, of course):

       1: public static class ObjectContextExtensions
       2: {
       3:     public static Object Load(this ObjectContext ctx, Type type, params Object [] ids)
       4:     {
       5:         Object p = null;
       6:  
       7:         EntityType ospaceType = ctx.MetadataWorkspace.GetItems<EntityType>(DataSpace.OSpace).SingleOrDefault(x => x.FullName == type.FullName);
       8:  
       9:         List<String> idProperties = ospaceType.KeyMembers.Select(k => k.Name).ToList();
      10:  
      11:         List<EntityKeyMember> members = new List<EntityKeyMember>();
      12:  
      13:         EntitySetBase collection = ctx.MetadataWorkspace.GetEntityContainer(ctx.DefaultContainerName, DataSpace.CSpace).BaseEntitySets.Where(x => x.ElementType.FullName == type.FullName).Single();
      14:  
      15:         for (Int32 i = 0; i < ids.Length; ++i)
      16:         {
      17:             members.Add(new EntityKeyMember(idProperties[i], ids[i]));
      18:         }
      19:  
      20:         EntityKey key = new EntityKey(String.Concat(ctx.DefaultContainerName, ".", collection.Name), members);
      21:  
      22:         if (ctx.TryGetObjectByKey(key, out p) == true)
      23:         {
      24:             return (p);
      25:         }
      26:  
      27:         return (p);
      28:     }
      29:  
      30:     public static T Load<T>(this ObjectContext ctx, params Object[] ids)
      31:     {
      32:         return ((T)Load(ctx, typeof(T), ids));
      33:     }
      34: }

    This will work with both single-property primary keys or with multiple, but you will have to supply each of the corresponding values in the appropriate order.

    Hope you find this useful! Winking smile

    Read more...