Friday, July 13, 2012

Just Visiting or (not so) Simple Extension Methods (part 4)

One of my favorite design patterns since the age of c++ is the Visitor Pattern. I will not explain here what the visitor pattern is. But, if you know how to use the design pattern this is a post worth reading.
One may ask what the visitor pattern has to do with LightSwitch. Well, it doesn’t! I mean not exclusively. But the code below provides a full visitor pattern implementation background that can also be used in LS. Also, a part of the implementation is ideal for LS, since one of the challenges I had to face, when trying to widely use the visitor pattern, was make it work for “sealed” classes, classes that were not written by me and could not easily fit to my –reflection based- visitor pattern implementation. To solve this the best thing I could think of was “wrapping”. And working with LS, most of the classes (apart from the ones that belong to the domain/datasource) are actually “sealed” in the way described above.(I have to note here that this reflection-based implementation is a revision of an implementation I found (if I recall correct) in CodeProject).
First the two basic interfaces that have to be defined:
The IVisitor interface that has to be implemented by the “worker” (or helper to follow the VB-oriented naming of the LS Team Sarcastic smile) class.
public interface IVisitor
{
  void VisitDefault(IVisitorTarget source);
}



Then the IVisitorTarget interface (implied above) that has to be implemented by the class to be “consumed/visited” by the Visitor.
public interface IVisitorTarget
{
  void Accept(IVisitor visitor);
}



Ok, I know, nothing much up to now. But as I say “The longest journey starts with the first step”…(yes I am an old Chinese philosopher)

To have your visitor pattern in place you need an extension method to do the trick:
public static bool ConcreteVisit(this IVisitorTarget target, IVisitor visitor) {
  Type[] types = new Type[] { target.GetType() };
  MethodInfo mi = visitor.GetType().GetMethod("Visit", types);

  if (mi == null)
    return false;

  mi.Invoke(visitor, new object[] { target });
  return true;
}

Now that these pieces are in place let’s say we have a class called DisplayNameBuilder that implements the IVisitor interface. Also, let’s say we have a Customer entity in our datasource and we want it to implement the IVisitorTarget interface. All we have to do is open Customer entity in the designer, click Write Code and change the class declaration to:
public partial class Model : IVisitorTarget



make sure you are using the namespace of the class where the above extension method is implemented and implement the IVisitorTarget interface like this:
#region IVisitorTarget Members
public void Accept(IVisitor visitor) {
  if (!this.ConcreteVisit(visitor))
    visitor.VisitDefault(this);
}
#endregion



Also this is a sample implementation of the DisplayNameBuilder class:
public class DisplayNameBuilder : IVisitor
{
  public string Name{
    get;
    private set;
  }

  public void VisitDefault(IVisitorTarget visitorTarget){
    Name = visitorTarget.ToString();
  }

  public void Visit(Customer visitorTarget){
    Name = string.Format("{0}{1}{2}", visitorTarget.FirstName, string.IsNullOrWhiteSpace(visitorTarget.FirstName) ? "", " ", visitorTarget.LastName);
  }
}



In the above code please note these:


  1. The code was written in Live Writer as it’s demo code, so maybe it does not compile as is.Embarrassed smile

  2. The customer is implied to have a nullable FirstName property and a not nullable LastName (which I believe it’s a fair assumption and I agree with me).

  3. The implementation, as obvious, is domain aware as it knows what Customer is. This implies that the ideal place for this class to live is in the Common project.

Now lets say you create a calculated string field in Customer entity called hmmmmm… DisplayName (surprised? It’s a gift I have regarding giving original namesSmile with tongue out). This would be the code that would implement the calculation of DisplayName property:
partial void DisplayName_Compute(ref string result) {
  DisplayNameBuilder builder = new DisplayNameBuilder();
  this.Accept(builder);
  result = builder.Name;
}

I HAVE to stress one more time that the code is for demonstration purposes only. It’s not just you, it IS too much fuss for nothing.

Ok, now it should be easier to understand the problem of using the visitor pattern with pre-defined classes. You cannot add the IVisitorTarget behavior to most of the classes, automatically generated by LS.

So this is the solution to the problem.
public class IVisitorWrapper<TObjectType> : IVisitorTarget
{
  public TObjectType Content {
    get;
    set;
  }

  #region IVisitorTarget Members
  public void Accept(IVisitor visitor) {
    if (!this.ConcreteVisit(this, visitor))
      if (!this.VisitWrapper(this, visitor))
        visitor.VisitDefault(this);
  }
  #endregion
}




This is a wrapper class (one could say it is an IVisitorTarget decorator). If you are still with me and you keep on reading the code you have already noticed that VisitWrapper extension method is not yet defined, so this is it:
public static bool VisitWrapper<TObjectType>(this IVisitorWrapper<TObjectType> wrapper, IVisitor visitor) {
  Type[] types = new Type[] { typeof(TObjectType) };
  MethodInfo mi = visitor.GetType().GetMethod("Visit", types);

  if (mi == null)
    return false;

  mi.Invoke(visitor, new object[] { wrapper.Content });
  return true;
}



Now you can wrap any type of object and use the DisplayNameBuilder to build it’s display name. Also (as –I hope- you guessed) you have to implement the respective Visit method in DisplayNameBuilder in order not go get the type name back as Name.

Well, as Porky says: That’s all Folks Smile. I hope that except for exhausting it was also interesting.

Wednesday, July 11, 2012

Application Logo (tailored on customer demand)

This is the most recent comment in the Application Logo Sample post:
“Hi Kostas,
I wanted to find out if there is a way of opening an active screen as soon as I click on the logo. I have tried but my attempt was in vain. If it is possible, could you please help me out?
Thanks,
Darryn”

My first reaction was to ask for details (typical way of buying time Smile). But then I though I could do the changes required and post a new article. So simply put, this is the answer I propose to Darryn:
public static void AddLogo(this Microsoft.LightSwitch.Client.IClientApplication application, System.Windows.HorizontalAlignment alignment, string screenName) {
  Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() => { LogoPlacement.AddLogo(application, System.Windows.Application.Current.RootVisual, alignment, screenName); });
}


private static class LogoPlacement
{
  internal static void AddLogo(Microsoft.LightSwitch.Client.IClientApplication application, UIElement element, System.Windows.HorizontalAlignment alignment, string screenName) {
    if (rcb != null) return;

    for (int i = 0; i < System.Windows.Media.VisualTreeHelper.GetChildrenCount(element); i++) {
      if (rcb != null)
        return;
      UIElement child = (UIElement)System.Windows.Media.VisualTreeHelper.GetChild(element, i);
      AddLogo(application, child, alignment, screenName);
    }
    if (element is Microsoft.LightSwitch.Runtime.Shell.Implementation.Standard.RibbonCommandBar) {
      rcb = element as Microsoft.LightSwitch.Runtime.Shell.Implementation.Standard.RibbonCommandBar;
      Image myImage = new Image() {
        Stretch = System.Windows.Media.Stretch.Uniform,
        Margin = new Thickness(2, 8, 14, 8),
        HorizontalAlignment = alignment,
        Cursor = System.Windows.Input.Cursors.Hand
      };
      myImage.SetValue(ComponentViewModelService.ViewModelNameProperty, "Default.LogoViewModel");
      myImage.SetBinding(Image.SourceProperty, new System.Windows.Data.Binding { Path = new PropertyPath("Logo") });
      if (!string.IsNullOrWhiteSpace(screenName))
        myImage.MouseLeftButtonUp += (s, e) => { application.Details.Dispatcher.BeginInvoke(() => application.Details.Methods[string.Format("Show{0}", screenName)].CreateInvocation().Execute()); };
      myImage.SizeChanged += (s, e) => {
        double left = (s as Image).HorizontalAlignment == HorizontalAlignment.Left ? e.NewSize.Width + 10.0 : 0.0;
        double right = (s as Image).HorizontalAlignment == HorizontalAlignment.Right ? e.NewSize.Width + 10.0 : 0.0;
        rcb.Padding = new Thickness(left, 0, right, 0);
      };
      ((Grid)rcb.Parent).Children.Add(myImage);
    }
  }




With bold I have marked the additions/changes I had to make to accommodate Darryn’s request.
I hope Darryn is happy Smile with tongue out.

Simple Extension Methods (part 3)

One very common task when one is implementing the business logic in Common project is writing custom PropertyName_Changed partial methods.
This “approach” has an undesired “side-effect” when the property is an entity property (as compared to screen properties). The property changes many times during the lifetime of the object. While loading, while deleting etc., whereas what we want to implement is handle the “actual” property changes caused either by the user or by some other piece of business logic.
I found myself debugging code that shouldn’t be executing (according to my logic, obviously LS had another opinion) before ending up writing a small extension method to use in all PropertyName_Changed partial methods. I don’t claim this method will help you avoid ALL unwanted business logic code execution, but covers most of the cases. I would be glad to read any comments improving it in a generic way.
Here is the code of the extension method:
public static bool IgnorePropertyChange(this IEntityObject entity) {
  return entity.Details.EntityState == EntityState.Unchanged ||
         entity.Details.EntityState == EntityState.Discarded ||
         entity.Details.EntityState == EntityState.Deleted;
}




And here how all my property changed partial implementations for entity properties look like
partial void ScheduledEndDate_Changed() {
  if (this.IgnorePropertyChange())
    return;
  .
  .
  .
}



This looks (and is) simple but the concept, alone, of “unwanted” code execution is important and should be taken good care of. If not using this extension method any other way one may like Winking smile.