Friday, January 20, 2012

Application Logo

Reading this article in MSDN forums and taking the best (I hope) of what LR_ and Michael Washington offered as solutions I ended up with an extension class that allows you to put your application’s logo on the Ribbon Bar of any shell having one. You also have the choice to put it either on the left or the right. LR_’s original code was only modified in 2 points.
  1. You can decide if you want you Application Logo on the left or on the right of your commands.
  2. You don’t need to pass a URL to the image. The application’s logo (defined in project properties) is bound inspired by the XAML provided by Michael Washington.
I even left the LeftButtonDown part as it’s a good idea.

Although implied from the detailed reference to them I want to thank both guys for making it so easy for me to put my logo on screen.


    private static class LogoPlacement

    {

         public static void AddLogo(this Microsoft.LightSwitch.Client.IClientApplication application, System.Windows.HorizontalAlignment alignment) {

           Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() => { LogoPlacement.AddLogo(System.Windows.Application.Current.RootVisual, alignment); });

         }

      internal static void AddLogo(UIElement element, System.Windows.HorizontalAlignment alignment) {

        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(child, alignment);

        }

        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") });

          myImage.MouseLeftButtonUp += (s, e) => MessageBox.Show("Here may be some About...");

          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);

        }

      }

 

      private static RibbonCommandBar rcb = null;

    }



Monday, January 16, 2012

Save (is a pain in the) As

Currently being in the process of developing a business application, I came across an issue that looked harmless, but turned out to be what the title elegantly :-P implies.
Being very proud of what I can achieve in no time with LS, I had my product manager testing the application, when she ask me the simple: “How can I change something and save it as a new object with a new name?”. “It’s not implemented yet, but I am getting my hands on it right now and you will have it in no time”. What a typical developer answer!
“No time” turned out to be a full workday of experimenting trying to find out the best and most generic way to implement Save As functionality. Having an object being copied to another was something I had already implemented but I worked fine only on originals. Fetching an object to the client, modifying it somehow and then trying to copy to a new one, discard the changes of the original object and save the copy…well it was not a piece of cake, rather a pastry shop.
Creating a new object in a different instance of the dataworkspace and trying to copy ended up in a threading hell, as my object was not a simple one but having many one to many and many to many relations and threading had to be made “safe” to ensure consistency. Even if could manage to do it for the type of object requested by my product manager, the solution would be specific to this object and generalization would be a project on its own, with doubtful result.
Having the original and the copy on the same screen and context, made almost impossible to find a general way to discard changes made to the original (or any of the related objects) before saving the dataworkspace.
The final solution was rather naive, but totally generic and “LightSwitch” with only one drawback that I will mention at the end.
My datasource was an SQL Server based one. So I created a new one called myDataSourceNameCopy from the same database and also named all the entities EntityNameCopy (much better that EntityName1 suggested by default from LS. Now I had a myDataSourceName.Customer (for example) instance on my Customer Details screen and a myDataSourceNameCopy.CustomerCopy property waiting to be instantiated upon “Save As” command by the user.
A small parenthesis: one of the first contracts I designed and implemented for all the objects need was ICopyTo<TEntityType> where TEntityType : IEntityObject, which exposes a void CopyTo(TEntityType target). So Customer was already implementing ICopyTo<Customer> and what I had to do was implement ICopyTo<CustomerCopy> (and all referenced objects accordingly of course).
In order to by able to save from my screen both in myDataSourceName and myDataSourceNameCopy Ι took a look at this video tutorial. In the end when the used confirms the Save As, I save the changes in myDataSourceNameCopy, I discard the changes of myDataSourceName, close the screen, refresh the list of Customers (or whatever) and my “Saved As” Customer is there in the list of Customers ready to use. Well, I have to update two datasources every time my database changes but it’s a small price to pay, given that save as Is very important for my application.
The drawback is that I haven’t yet managed to figure out how this can be achieved with native LS datasources.
If anyone has implemented some other generic way to support Save As functionality and has to offer any ideas I would very much appreciate the comments.