0

Using conventions with Passive View

Posted by Mark Nijhof on Dec 19, 2009 in - Dotnet  | View Original Article
 

I was reading Ayende’s blog post about building UI based on conventions and thought; hey I have something similar in my CQRS example. And since this is the least interesting part of the whole example I guess it will be missed by many, and I can’t let that happen.

Passive View

The example has a Win Forms application in there that is build accordingly to the Passive View pattern, so my actual forms are being dumbed down to simple views without any logic in them, well almost no logic. Then I have presenters that have the actual logic in them, or delegate the logic to other responsible entities (services or whatever).

The reason for doing this is because you want to be able to test the behavioral parts of your code as simple as possible, and nothing is more simple then being able to unit test your behavior, hey even better drive your design / behavior through Test-Driven Development Design (TDD). Imagine how hard that would be to do when not abstracting these different responsibilities from each other (hehe I am sure some of you don’t even need to imagine this ;) ).

I realize the Win Forms is so not _in_ anymore and that nobody uses them, but perhaps what I show you here makes you think about other areas that this could be applied to.

The View

The view is responsible for displaying information to a user, capturing user requests, and … uhm no that’s it. Let’s take a look at a simple view.

    1 namespace Fohjin.DDD.BankApplication.Views
    2 {
    3     public partial class ClientSearchForm : Form, IClientSearchFormView
    4     {
    5         public ClientSearchForm()
    6         {
    7             InitializeComponent();
    8             RegisterClientEvents();
    9         }
   10 
   11         public event EventAction OnCreateNewClient;
   12         public event EventAction OnOpenSelectedClient;
   13 
   14         private void RegisterClientEvents()
   15         {
   16             addANewClientToolStripMenuItem.Click += (s, e) => OnCreateNewClient();
   17             _clients.Click += (s, e) => OnOpenSelectedClient();
   18         }
   19 
   20         public IEnumerable<ClientReport> Clients
   21         {
   22             get { return (IEnumerable<ClientReport>)_clients.DataSource; }
   23             set { _clients.DataSource = value; }
   24         }
   25 
   26         public ClientReport GetSelectedClient()
   27         {
   28             return (ClientReport)_clients.SelectedItem;
   29         }
   30     }
   31 }

So what is happening here? As you can see there are two public events declared and there are two properties that provide access to some form controls. The interesting thing here is that the two public events are wired to two events from two form controls. But hey nothing is happening; no behavior, no calls to services or anything. Below here is the declaration of the interface that the form implements.

    1 namespace Fohjin.DDD.BankApplication.Views
    2 {
    3     public interface IClientSearchFormView : IView
    4     {
    5         IEnumerable<ClientReport> Clients { get; set; }
    6         ClientReport GetSelectedClient();
    7         event EventAction OnCreateNewClient;
    8         event EventAction OnOpenSelectedClient;
    9     }
   10 }

Here are both the two public events and the two properties that provide access to two form controls, of course the implementation could be anything. This interface is used by the presenter to control the view.

The Presenter

So the presenter is responsible for controlling the view; which includes setting and retrieving data and executing behavior that is triggered by the user of the view. Below is the presenter that is responsible for managing the previous mentioned view.

    1 namespace Fohjin.DDD.BankApplication.Presenters
    2 {
    3     public class ClientSearchFormPresenter : Presenter<IClientSearchFormView>, IClientSearchFormPresenter
    4     {
    5         private readonly IClientSearchFormView _clientSearchFormView;
    6 
    7         public ClientSearchFormPresenter(IClientSearchFormView clientSearchFormView) : base(clientSearchFormView)
    8         {
    9             _clientSearchFormView = clientSearchFormView;
   10         }
   11 
   12         public void CreateNewClient()
   13         {
   14             // Do something
   15         }
   16 
   17         public void OpenSelectedClient()
   18         {
   19             // Do something
   20         }
   21 
   22         public void Display()
   23         {
   24             LoadData();
   25             try
   26             {
   27                 _clientSearchFormView.ShowDialog();
   28             }
   29             finally
   30             {
   31                 _clientSearchFormView.Dispose();
   32             }
   33         }
   34 
   35         private void LoadData()
   36         {
   37             // Do something
   38         }
   39     }
   40 }

For simplicity I removed any other external dependencies and replaced the behavior with a comment “Do something”. Talking about external dependencies; the interface that is implemented by the view is injected into the presenter, this is interesting.

Look at the Display method, there you see that the view that is injected first gets its data loaded and then actually gets activated. This means that the view will not get its own data, but that the presenter will provide it to the view, for this the presenter will use the two properties that where declared in the interface. And it means that the presenter is responsible for activating the view. This is different from how Win Forms works out of the box.

For this to work I had to change the Program class, here take a look:

    1 namespace Fohjin.DDD.BankApplication
    2 {
    3     static class Program
    4     {
    5         /// <summary>
    6         /// The main entry point for the application.
    7         /// </summary>
    8         [STAThread]
    9         static void Main()
   10         {
   11             ApplicationBootStrapper.BootStrap();
   12 
   13             var clientSearchFormPresenter = ObjectFactory.GetInstance<IClientSearchFormPresenter>();
   14 
   15             Application.EnableVisualStyles();
   16 
   17             clientSearchFormPresenter.Display();
   18         }
   19     }
   20 }

Look at line 17 in there, the method Display is called on the presenter, which then prepares and activates the view.

But I can hear you think; what about these two events that where declared on that interface as well, you know “OnCreateNewClient” and “OnOpenSelectedClient”? I can see some obvious candidates “CreateNewClient” and “OpenSelectedClient” but they are not wired-up together. What gives?

The Magic

You must have noticed that the names are very similar and that they follow a certain pattern, this is the convention that I have chosen to use. Basically I call my event handlers the same as the events without the “On” prefix. Then I have a base presenter class without the word “Base” because that would be EVIL. And this class will wire-up the events with the event handlers for me.

    1 namespace Fohjin.DDD.BankApplication.Presenters
    2 {
    3     public abstract class Presenter<TView> where TView : class, IView
    4     {
    5         protected Presenter(TView view)
    6         {
    7             HookUpViewEvents(view);
    8         }
    9 
   10         private void HookUpViewEvents(TView view)
   11         {
   12             var viewDefinedEvents = GetViewDefinedEvents();
   13             var viewEvents = GetViewEvents(view, viewDefinedEvents);
   14             var presenterEventHandlers = GetPresenterEventHandlers(viewDefinedEvents, this);
   15 
   16             foreach (var viewDefinedEvent in viewDefinedEvents)
   17             {
   18                 var eventInfo = viewEvents[viewDefinedEvent];
   19                 var methodInfo = GetTheEventHandler(viewDefinedEvent, presenterEventHandlers, eventInfo);
   20 
   21                 WireUpTheEventAndEventHandler(view, eventInfo, methodInfo);
   22             }
   23         }
   24 
   25         private MethodInfo GetTheEventHandler(string viewDefinedEvent, IDictionary<string, MethodInfo> presenterEventHandlers, EventInfo eventInfo)
   26         {
   27             var substring = viewDefinedEvent.Substring(2);
   28             if (!presenterEventHandlers.ContainsKey(substring))
   29                 throw new Exception(string.Format("\n\nThere is no event handler for event '{0}' on presenter '{1}' expected '{2}'\n\n", eventInfo.Name, GetType().FullName, substring));
   30 
   31             return presenterEventHandlers[substring];
   32         }
   33 
   34         private void WireUpTheEventAndEventHandler(TView view, EventInfo eventInfo, MethodInfo methodInfo)
   35         {
   36             var newDelegate = Delegate.CreateDelegate(typeof(EventAction), this, methodInfo);
   37             eventInfo.AddEventHandler(view, newDelegate);
   38         }
   39 
   40         private static IDictionary<string, MethodInfo> GetPresenterEventHandlers<TPresenter>(ICollection<string> actionProperties, TPresenter presenter)
   41         {
   42             return presenter
   43                 .GetType()
   44                 .GetMethods(BindingFlags.Instance | BindingFlags.Public)
   45                 .Where(x => Contains(actionProperties, x))
   46                 .ToList()
   47                 .Select(x => new KeyValuePair<string, MethodInfo>(x.Name, x))
   48                 .ToDictionary(x => x.Key, x => x.Value);
   49         }
   50 
   51         private static List<string> GetViewDefinedEvents()
   52         {
   53             return typeof(TView).GetEvents().Select(x => x.Name).ToList();
   54         }
   55 
   56         private static IDictionary<string, EventInfo> GetViewEvents(TView view, ICollection<string> actionProperties)
   57         {
   58             return view
   59                 .GetType()
   60                 .GetEvents()
   61                 .Where(x => Contains(actionProperties, x))
   62                 .ToList()
   63                 .Select(x => new KeyValuePair<string, EventInfo>(x.Name, x))
   64                 .ToDictionary(x => x.Key, x => x.Value);
   65         }
   66 
   67         private static bool Contains(ICollection<string> actionProperties, EventInfo x)
   68         {
   69             return actionProperties.Contains(x.Name);
   70         }
   71 
   72         private static bool Contains(ICollection<string> actionProperties, MethodInfo x)
   73         {
   74             return actionProperties.Contains(string.Format("On{0}", x.Name));
   75         }
   76     }
   77 }

The abstract base class Presenter needs the view interface as the generic parameter of the view that the presenter controls. A reference to the actual view will be injected into the presenter class. Then the first thing that happens is that I get all the events declared from the provided interface. Then I get the actual events from the provided view, but only those that have been defined on the provided interface. This makes it possible to define multiple interfaces on the same view that get controlled by different presenters. After this I get all the public methods from the presenter.

Once I have the events form the view and the methods from the presenter then I can start matching them together. As I mentioned before in my case I use a very simple convention where the event is prefixed with “On” so in order to get the event handler I only need to search my event handler collection for a name of the event minus “On”. Then finally the event gets the event handler added to its collection of event handlers.

When there is no event handler for a provided event then I throw an exception, because I consider this to be a bug. There might be event handlers that does not have an event associated with it, but I consider that less harmful since this logic would not be called anyway. This exception will be visible in the unit tests for the presenter.

Reflection

Yes this relies very heavily on reflection, but for this scenario I don’t mind. Indeed it is slower, but the question is; will you notice this when displaying a form, and I don’t think you will. You could improve this code by for example making the WireUpEventAndEventHandler an action and cache those for the combination of the presenter and view interface, but I don’t think that is worth the effort.

The Specifications

I am going to leave you with the specifications that I have for the presenter that I used for this post. The whole presenter is being tested by setting data on the view and triggering events. I am not calling the methods directly on the presenter itself. And if you want to see more, then get the code from GitHub.

    1 namespace Test.Fohjin.DDD.Scenarios.Opening_the_bank_application
    2 {
    3     public class When_in_the_GUI_openeing_the_bank_application : PresenterTestFixture<ClientSearchFormPresenter>
    4     {
    5         private List<ClientReport> _clientReports;
    6 
    7         protected override void SetupDependencies()
    8         {
    9             _clientReports = new List<ClientReport> { new ClientReport(Guid.NewGuid(), "Client Name") };
   10             OnDependency<IReportingRepository>()
   11                 .Setup(x => x.GetByExample<ClientReport>(null))
   12                 .Returns(_clientReports);
   13         }
   14 
   15         protected override void When()
   16         {
   17             Presenter.Display();
   18         }
   19 
   20         [Then]
   21         public void Then_show_dialog_will_be_called_on_the_view()
   22         {
   23             On<IClientSearchFormView>().VerifyThat.Method(x => x.ShowDialog()).WasCalled();
   24         }
   25 
   26         [Then]
   27         public void Then_client_report_data_from_the_reporting_repository_is_being_loaded_into_the_view()
   28         {
   29             On<IClientSearchFormView>().VerifyThat.ValueIsSetFor(x => x.Clients = _clientReports);
   30         }
   31     }
   32 }

    1 namespace Test.Fohjin.DDD.Scenarios.Adding_a_new_client
    2 {
    3     public class When_in_the_GUI_adding_a_new_client : PresenterTestFixture<ClientSearchFormPresenter>
    4     {
    5         protected override void When()
    6         {
    7             On<IClientSearchFormView>().FireEvent(x => x.OnCreateNewClient += delegate { });
    8         }
    9 
   10         [Then]
   11         public void Then_client_report_data_from_the_reporting_repository_is_being_loaded_into_the_view()
   12         {
   13             On<IClientDetailsPresenter>().VerifyThat.Method(x => x.SetClient(null)).WasCalled();
   14         }
   15 
   16         [Then]
   17         public void Then_display_will_be_called_on_the_view()
   18         {
   19             On<IClientDetailsPresenter>().VerifyThat.Method(x => x.Display()).WasCalled();
   20         }
   21     }
   22 }

    1 namespace Test.Fohjin.DDD.Scenarios.Displaying_client_details
    2 {
    3     public class When_in_the_GUI_opening_an_existing_client : PresenterTestFixture<ClientSearchFormPresenter>
    4     {
    5         private ClientReport _clientReport;
    6 
    7         protected override void SetupDependencies()
    8         {
    9             OnDependency<IPopupPresenter>()
   10                 .Setup(x => x.CatchPossibleException(It.IsAny<Action>()))
   11                 .Callback<Action>(x => x());
   12 
   13             _clientReport = new ClientReport(Guid.NewGuid(), "Client Name");
   14 
   15             OnDependency<IClientSearchFormView>()
   16                 .Setup(x => x.GetSelectedClient())
   17                 .Returns(_clientReport);
   18         }
   19 
   20         protected override void When()
   21         {
   22             On<IClientSearchFormView>().FireEvent(x => x.OnOpenSelectedClient += delegate { });
   23         }
   24 
   25         [Then]
   26         public void Then_get_selected_client_will_be_called_on_the_view()
   27         {
   28             On<IClientSearchFormView>().VerifyThat.Method(x => x.GetSelectedClient()).WasCalled();
   29         }
   30 
   31         [Then]
   32         public void Then_client_report_data_from_the_reporting_repository_is_being_loaded_into_the_view()
   33         {
   34             On<IClientDetailsPresenter>().VerifyThat.Method(x => x.SetClient(_clientReport)).WasCalled();
   35         }
   36 
   37         [Then]
   38         public void Then_display_will_be_called_on_the_view()
   39         {
   40             On<IClientDetailsPresenter>().VerifyThat.Method(x => x.Display()).WasCalled();
   41         }
   42     }
   43 }

Tags: , , ,

 
0

esXpress VMware Backup Free Download

Posted by Latest News from Cloud Computing Journal on Dec 19, 2009 in - General, - Technology News, CLoud Computing  | View Original Article
 PHD Virtual Technologies, award-winning provider of esXpress, the fastest multi-VM backup and restore solution on the market, today announced that Seattle Bank has standardized backup of their virtual infrastructure on esXpress, thereby enabling same-day disaster recovery compared to their previous full day loss of business continuity. Following the deployment of esXpress on two geographically distributed VMware ESX clusters, Seattle Bank has reduced its recovery time from one day to less than two hours with esXpress.

read more

Tags: ,

 
0

Free Virtual Appliance for Cloud Computing

Posted by Latest News from Cloud Computing Journal on Dec 19, 2009 in - General, - Technology News, CLoud Computing  | View Original Article
 up.time represents a quantum leap forward for companies that need to drive both IT performance and cost-savings, while ensuring a consistent quality of service. The technology provides IT managers with an unobstructed view of the datacenter to efficiently manage distributed applications and global services levels, while maximizing enterprise-wide IT resources. The solution's ability to provide dashboards that deeply monitor, measure, and manage IT infrastructure and applications in virtual, physical and Cloud environments, as well as across multiple/remote locations, platforms, databases, and more has helped hundreds of customers achieve new levels of performance and immediate cost savings.

read more

Tags: ,

 
0

Surviving a Re-Org

Posted by Tom Barker on Dec 19, 2009 in - Miscelleneous  | View Original Article
  End of year is a time when companies and departments reflect on the previous year and begin planning for new projects and challenges in the coming year. It's also a time when departments usually restructure to bring more focus and...

Tags: , , , , ,

 
0

Taking a Visit To The SUSE Studio

Posted by Jan Van Ryswyck on Dec 19, 2009 in - Dotnet  | View Original Article
 

After listening to the keynote of Monospace 2009, I got somewhat intrigued by the possibilities of SUSE Studio. Miguel de Icaza talked about this in his presentation and because its not that easy to follow a demo through an mp3 recording, I wanted to try it on my own. SUSE Studio lets you create your own customized appliances. An appliance is a pre-configured  combination of an operating system (SUSE Linux in this case),  applications and their configuration.

After logging on, the first step is creating a new appliance. Here you can choose which type of operating system you want to install (desktop, server or minimal), what type of desktop (GNOME or KDE) and the particular processor architecture you want to target (32-bit or 64-bit).

image

You can also give you’re appliance a name.

image

After you created your new appliance, its possible to select the packages that you want installed.  

image 

Off course, you don’t have to choose everything yourself. Some packages are selected by default. Having MonoDevelop pre-installed is quite easy. Just search and add it to the selected software. You can even upload your own package and have it pre-installed for your appliance.

image

After you made up your mind on which particular applications should be included with your appliance, you can choose to do some configuration. For example, one of the most important choices you have to make is the background of your appliance ;-) .

image 

Other settings like the language, keyboard layout, time zone, users + password, etc. … can all be pre-configured. When you’re done configuring, you can choose to create the appliance. There are a couple of delivery options you can choose from:

image 

When SUSE Studio is done building the appliance you composed, you can either download it or take a test drive. Now, this is the probably the coolest feature of SUSE Studio. With test drive you can boot and test your appliance in a browser without downloading it!

image

 

image

I don’t know about you, but I would love to have something similar for configuring Windows appliances. I mean, wouldn’t it be cool to have the Windows OS pre-installed with Visual Studio, Resharper, TestDriven.NET, etc. …?

The only thing that I feel is missing in SUSE Studio are a couple of packages that are not yet available, like CouchDB for example. I also kind of expected that the latest version of MonoDevelop and Mono would be available already, but at the time of this writing only the previous versions can be pre-installed.

Now try it for yourself, its free :-) . The only thing you have to do is apply for an invitation and you’re ready to take if for a test drive.

Tags: , ,

 
0

The New Version of EC2Studio Is Released

Posted by Latest News from Cloud Computing Journal on Dec 19, 2009 in - General, - Technology News, CLoud Computing  | View Original Article
 The users can use several Amazon EC2 accounts when they work with the add-in. Account changing in the add-in is available in the same easy manner like changing of the AWS region at the all EC2 add-in pages. Once an account is added and the connection is tested – it’s ready to use.

read more

Tags: ,

 
0

QOW: What are you most excited about for 2010?

Posted by Rich Tretola on Dec 19, 2009 in - Miscelleneous  | View Original Article
  The world of technology is constantly in flux and 2010 seems like it will be a very existing year. With the many scheduled releases of exciting new Android phones the re-emergence of the handset wars in the world of mobile...

Tags: , , , ,

 
0

What You Need To Know About Behavioral CSS

Posted by Tim Wright on Dec 19, 2009 in - CSS, - Design & Graphics  | View Original Article
 
Smashing-magazine-advertisement in What You Need To Know About Behavioral CSS
 in What You Need To Know About Behavioral CSS  in What You Need To Know About Behavioral CSS  in What You Need To Know About Behavioral CSS

Spacer in What You Need To Know About Behavioral CSS
As we move forward with the Web and browsers become capable of rendering more advanced code, we gradually get closer to the goal of universal standards across all platforms and computers. Not only will we have to spend less time making sure our box model looks right in IE6, but we create an atmosphere ripe for innovation and free of hacks and heavy front-end scripting.

The Web is an extremely adaptive environment and is surrounded by a collaborative community with a wealth of knowledge to share. If we collectively want to be able to have rounded corners, we make it happen. If we want to have multiple background images, we make it happen. If we want border images, we make that happen, too. So desire is not the issue. If it was, we would all still be using tables to lay out our pages and using heavy over-the-top code. We all know that anything can be done on the Web.

Made for the Web

CSS 3 properties like border-radius, box-shadow, and text-shadow are starting to gain momentum in WebKit (Safari, Chrome, etc.) and Gecko (Firefox) browsers. They are already creating more lightweight pages and richer experiences for users, not to mention that they degrade pretty gracefully; but they are only the tip of the iceberg of what we can do with CSS 3.

In this article, we will take those properties a step further and explore transformations, transitions, and animations. We’ll go over the code itself, available support and some examples to show exactly how these new properties improve not only your designs but the overall user experience.

CSS Transformations

CSS transformations are a W3C oddity. It is the first time I have sat down to read the full specifications on something and didn’t feel like I had a handle on the subject afterward. The specs are written with the level of technical jargon you would expect from the W3C, but it focuses on the graphic (as in graph drawing) element of transformations and matrices. Having not dealt with a matrix since freshman-year Calculus, I had to do a lot of good old-fashioned browser testing and guessing and checking for this section.

After going through every tutorial I could find and too many browser tests to count, I came out with some useful information on CSS transformations that I think we can all benefit from.

transform();

The transform property allows for the kind of functions also allowed by SVG. It can be applied to both inline and block-level elements. It allows us to twist, zoom in on and move elements, all with one line of CSS.

One of the biggest complaints about cutting-edge design is that the text is not selectable. This is no longer a problem when you use the transform property to manipulate text, because it is pure CSS and so any text within the element remains selectable. This is a huge advantage of CSS over using an image (or background image).

Some interesting and useful transform functions (that are supported):

  • rotate
    Rotate allow you to turn an object by passing a degree value through the function.
  • scale
    Scale is a zooming function and can make any element larger. It takes positive and negative values as well as decimals.
  • translate
    Translate essentially repositions an element based on X and Y coordinates.

Let’s look at each of these in more detail.

Rotate

The transform property has many uses, one of which is to rotate. Rotation turns an object based on a degree value and can be applied to both inline and block-level elements, It makes for a pretty cool effect.

Transform Rotate in What You Need To Know About Behavioral CSS

#nav {
    -webkit-transform: rotate(-90deg);
    -moz-transform: rotate(-90deg);
    filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
    }

Support
Support for transform: rotate is surprisingly widespread. In the CSS snippet above, we directly target -webkit- and -moz- and rotate the #nav element by -90 degrees.

Pretty straightforward, right? The only problem is that the rotation is for a pretty important design element, and many designers will be reluctant to use it if Internet Explorer does not recognize it.

Luckily, IE has a filter for this: the image transform filter. It can take four rotation values: 0, 1, 2, and 3. You won’t get the same fine-grained control that comes with Webkit and Gecko, but your design will remain consistent across older browsers (even IE6).

Is it okay to use?
Yes, but make sure it is thoroughly tested.

Scale

Scaling does exactly what you think it would do: zoom in and out on an element. The scale function takes both width and height values, and those values can be positive, negative or decimals.

Positive values scale up the element, as you would expect, based on the width and height specified.

Negative values do not shrink the element, but rather reverse it (e.g. text is turned backwards) and then scaled accordingly. You can, however, use decimal values lower than 1 (e.g. .5) to shrink or zoom out of an element.

Transform Scale in What You Need To Know About Behavioral CSS

#nav {
/* The nav element width and height will double in size */
-webkit-transform: scale(2);
-moz-transform: scale(2);
}

#nav {
/* The nav element width will double in size, but the height will remain unchanged*/
-webkit-transform: scale(2, 1);
-moz-transform: scale(2, 1);
}

#nav {
/* The nav element width will double in size and flip horizontally,
but the height will remain unchanged */
-webkit-transform: scale(-2, 1);
-moz-transform: scale(-2, 1);
}

Support
The scale transformation is supported in Firefox, Safari and Chrome, but not any version of Internet Explorer (yet) as far as I could tell. Scaling an object is a fairly significant design choice, but it can be applied with progressive enhancement using :hover, which can add a little pop to your navigation especially.

#nav li a:hover{
/* This should make your navigation links zoom slightly on hover */
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
}

Is it okay to use?
From time to time, yes. But not with critical design elements.

Translate

The name “translate” is a little misleading. It is actually a method of positioning elements using X and Y values.

It looks much the same as the other kinds of transformation but adds an extra dimension to your website.

Transform Translate in What You Need To Know About Behavioral CSS

#nav{
/* This will move the #nav element left 10 pixels and down 20 pixels. */
-moz-transform: translate(10px, 20px);
-webkit-transform: translate(10px, 20px);
}

Support
Translate is currently supported in Firefox, Safari and Chrome when you use the vender extensions -moz- and -webkit-.

Is it okay to use?
Yes, but normal X/Y positioning is just as effective in many situations.

Chaining Transformations

Transformations are great individually, but if you want multiple transformations, the code can pile up pretty quickly, especially with the vendor extensions. Luckily, we have some built-in shortcuts:

#nav{
-moz-transform: translate(10, 25);
-webkit-transform: translate(10, 25);
-moz-transform: rotate(90deg);
-webkit-transform: rotate(90deg);
-moz-transform: scale(2, 1);
-webkit-transform: scale(2, 1);
}

These transformations can be chained together to make your CSS more efficient:

#nav{
-moz-transform: translate(10, 25) rotate(90deg) scale(2, 1);
-webkit-transform: translate(10, 25) rotate(90deg) scale(2, 1);
}

The real power of these properties is in combining and chaining them. You can move, turn, zoom in on and manipulate any inline or block-level element without JavaScript. Once support for these properties becomes widespread, we’ll be able to build and design even richer and more lightweight interfaces and applications.

Transition

A basic transition refers to a CSS property that define and moves an element from its inactive state (e.g. dark-blue background) to its hover or active state (e.g. light-blue background).

Transitions can be coupled with transformations (and trigger events such as :hover or :focus) to create a kind of animation. Fading the background color, sliding a block and spinning an object can all be done with CSS transitions.

#nav a{
background-color:red;
}

#nav a:hover,
#nav a:focus{
background-color:blue;

/* tell the transition to apply to background-color (looks like a CSS variable, doesn't it? #foreshadowing)*/
-webkit-transition-property:background-color;

/* make it 2 seconds long */
-webkit-transition-duration:2s;
}

Support
As cool as the transition property is, support is limited to WebKit browsers. Firefox does not support it right now, but it’s safe to assume that it is right behind WebKit on this. So you may as well add -moz-transition to your CSS for future enhancements. And even a version without a vendor extension, just in case.

Is it okay to use?
For subtle enhancements, yes, but not for dramatic effects.

Animation

Animations are where the real action in CSS 3 is. You can combine all of the elements we’ve talked about above with animation properties like animation-duration, animation-name and animation-timing-function to create Flash-like animations with pure CSS.

#rotate {
margin: 0 auto;
width: 600px;
height: 400px;

/* Ensures we're in 3-D space */
-webkit-transform-style: preserve-3d;

/*
Make the whole set of rows use the x-axis spin animation
for a duration of 7 seconds, running infinitely and linearly.
*/

-webkit-animation-name: x-spin;
-webkit-animation-duration: 7s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}

/* Defining the animation to be called. */
@-webkit-keyframes x-spin {
   0%    { -webkit-transform: rotateX(0deg); }
   50%   { -webkit-transform: rotateX(180deg); }
   100%  { -webkit-transform: rotateX(360deg); }
}

All this fantastic CSS animation code and a live example can be found at CSS3.info The demo is viewable in any browser, but the animation works only in the nightly build of WebKit. It looks just like the video above, but it’s worth installing WebKit to see it for yourself (it’s pretty awesome).

Support
There is, unfortunately, almost no support for CSS animations yet. To even experiment with them, you have to download the nightly build of WebKit. This is the first indication of CSS as a true programming language and a huge step towards not only Flash independence but super-usability and large-scale accessibility across the Web.

Conclusion

Right now, JavaScript bridges the gap until CSS 3 comes into full effect. Unfortunately, getting full browser support for these great properties will be a long journey. Until that day comes, we can take advantage of some serious progressive enhancement and rely on JavaScript to enhance our websites and applications. That’s not a bad thing; just how it is at the moment.

With the recent announcement of IE9, I wouldn’t be surprised if the IE team include some of these properties in the new version of the browser especially since talks for CSS3 integration have already begun (border-radius).

The future of the Web is bright, especially with these highly experimental properties such as animation. Although many of the properties are not usable for client or high-level production work, they sure are fun to play with! We can all look forward to the day when we have support across the board to build some really great lightweight applications.

References And Resources

(al)


© Tim Wright for Smashing Magazine, 2009. | Permalink | One comment | Add to del.icio.us | Digg this | Stumble on StumbleUpon! | Tweet it! | Submit to Reddit | Forum Smashing Magazine
Post tags: , ,

Tags: , , ,

 
0

Networking and Web Services in Silverlight 4

Posted by Silverlight Show on Dec 19, 2009 in - Miscelleneous  | View Original Article
 Yavor Georgiev has posted his presentation at last week’s PDC conference about what’s new in networking and web services in Silverlight 4 Beta.

For my presentation I put together an application that highlights some of the coolest web services features available in Silverlight 4 Beta. The app is intended to be used by travel agents and helps with their day-to-day work: it displays (fake) real-time price information for flight tickets, it can pull up real-time information about the status of a flight, it supports a chat feature so travel agents can talk to each other, and it supports sharing a set of tasks from Sharepoint.

Tags: ,

 
0

Architecting SL4 Applications with RIA Services, MEF and MVVM – Part 2

Posted by Silverlight Show on Dec 19, 2009 in - Miscelleneous  | View Original Article
 A while ago Shawn Wildermuth released the first part of the series on how to architect your Silverlight 4 projects. In this second part, he wants to show you how the Managed Extensibility Framework (MEF) can aid in that process.

If you read the first part of this series, go get the code again as I've refactored it to make it a little easier to create testability code. Chiefly I made two important changes:

  • Renamed the Data project to Common and put all the interfaces in that project.
  • Removed the interfaces on the ViewModels

Tags: ,

Copyright © 2010 Answer My Query All rights reserved. Maintained by Orange Brains .