Tuesday 30 April 2013

Simple UI scaling animation

       I often forget about different properties used with animation, hence another post about it, to follow up the previous one. It's just a small code snippet that fits just right into the previous code. Scaling animation isn't as useful as the sliding out one in my opinion, but it might come in handy one day, and I don't wanna have to roam the internet for hours to find it again.
       The only part that changes from the code in the last post are the storyboards. You can replace them with the ones below and it should work from the get go.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<Storyboard x:Key="firstStoryboard">     
    <DoubleAnimation Storyboard.TargetName="animatedGrid2"
    Duration="00:00:00.3"
    Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
    To="1" />
</Storyboard>
<Storyboard x:Key="secondStoryboard">
    <DoubleAnimation Storyboard.TargetName="animatedGrid2"
    Duration="00:00:00.3"
    Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
    To="0" />
</Storyboard>
     
         Because the site I usually use for code to html conversion http://puzzleware.net/codehtmler/ seems to be down, and I don't have Visual Studio with the code conversion plugin nearby I've used another web code converter, that's why a different theme. The one I used today is: http://hilite.me/

Saturday 27 April 2013

Simple UI sliding animation

          Adding simple animation to your app can make it feel much more natural. And there's nothing as annatural in UI for us humans, as things suddenly popping out all over the place (which they usually do if we only use visibility when we need to show something to the user).
Quite frequent UI operation is checking a checkbox or switching radiobuttons and uncovering some previusly hidden part of UI. What makes it more appealing to the user is, when the hidden part of UI gently slides out instead of appearing suddenly. I'll show 2 different animation types appropriate in this situation. First one in this post.
  1 <Grid.Resources>
  2    <Storyboard x:Key="firstStoryboard"> 
  3        <DoubleAnimation Storyboard.TargetName="animatedGrid" 
  4        Duration="00:00:00.3" 
  5        Storyboard.TargetProperty="Height" 
  6        To="100" /> 
  7    </Storyboard> 
  8    <Storyboard x:Key="secondStoryboard">  
  9        <DoubleAnimation Storyboard.TargetName="animatedGrid" 
 10        Duration="00:00:00.3" 
 11        Storyboard.TargetProperty="Height" 
 12        To="0" /> 
 13    </Storyboard> 
 14 </TabItem.Resources> 
 15 <Grid HorizontalAlignment="Stretch"> 
 16     <Grid.ColumnDefinitions> 
 17         <ColumnDefinition Width="Auto"/> 
 18         <ColumnDefinition Width="Auto"/>                             
 19     </Grid.ColumnDefinitions> 
 20     <Grid.RowDefinitions> 
 21         <RowDefinition Height="Auto"/> 
 22         <RowDefinition Height="Auto"/>         
 23         <RowDefinition/>
 24     </Grid.RowDefinitions> 
 25     <RadioButton Content="First"/>   
 26     <RadioButton Content="Second" Grid.Column="1"> 
 27         <ToggleButton.Triggers> 
 28         <EventTrigger RoutedEvent="ToggleButton.Checked"> 
 29             <BeginStoryboard Storyboard="{StaticResource firstStoryboard}"/> 
 30         </EventTrigger> 
 31         <EventTrigger RoutedEvent="ToggleButton.Unchecked">
 32             <BeginStoryboard Storyboard="{StaticResource secondStoryboard}"/>
 33         </EventTrigger> 
 34         </ToggleButton.Triggers> 
 35     </RadioButton>
 36     <Grid Grid.Row="1" Grid.ColumnSpan="2" x:Name="animatedGrid" Height="0">
 37         <TextBlock Text="RandomText"/> 
 38     </Grid> 
 39 </Grid>
         This is a pretty simple piece of XAML code. What we need are 2 storyboards, one for the sliding out animation, one for the sliding back one. In this case we want to animate the height property and we need to state the max height explicitly. For each place in UI where you use this animation, you'd have to set the height to the value which would allow the whole hidden control to be visible after the animation took place.
        The animation is triggered by a routed event caused by the RadioButton being Checked or Unchecked. One important thing is to remember, that we need to set the starting Height to 0.

Monday 22 April 2013

Google maps api v3 and custom markers

         I found myself in need of using custom google maps markers. Taking into consideration that the Google Chart tools API is now deprecated and will cease to work on April 20, 2015 and using 3rd party api was off the table I had to glue together several samples and fumble through many tutorials. I mostly based this on following great code sample http://blog.mridey.com/2009/09/label-overlay-example-for-google-maps.html by Marc Ridey. Default google maps Marker consist of a red pin with a dot in the middle. To achieve a similar effect with a custom content marker I created a Label object. First problem to overcome was creating a proper marker with editable text inside.
  1 function Label(opt_options) { 
  2     // Initialization 
  3     this.setValues(opt_options); 
  4   
  5     // Image initialization 
  6     var labImg = document.createElement('img');                             
  7     labImg.setAttribute('src','Images/marker.png'); 
  8     labImg.style.cssText = 'position: relative;left: -50%; top: -100%';
  9     labImg.setAttribute('alt',''); 
 10     labImg.style.width = '21px' 
 11     labImg.style.height = '34px' 
 12   
 13     // Marker text initialization 
 14     var span = this.span_ = document.createElement('span');     
 15     span.style.cssText = 'position: absolute; top: -100%; 
 16        left: -12px; width: 21px; align: left; text-align: center'; 
 17   
 18     // Creating a div with image background and text inside
 19     var div = this.div_ = document.createElement('div');
 20     div.appendChild(labImg); 
 21     div.appendChild(span); 
 22     div.style.cssText = 'position: absolute; display: none;';
 23 };
         In the code above I'm creating a simple marker that consists of a div with image as background and a span which will include the markers's text. For this marker to become a map overlay object it has to inherit google.maps.OverlayView. The former we'll force us to implement onAdd(), onRemove() and draw() methods, which are described properly in the link I provided earlier. I created two collections to help me in my implementation. First one: positions collection holds latitudes and longitudes, the second one data such as zIndex nad label's text. I populated them in addMarker method. As I mentioned earlier we need to setup the inheritance somewhere in code:
      Label.prototype = new google.maps.OverlayView; 
And finally function for adding new markers:
  1 // Adding new marker 
  2 function addMarker(long, lat, desc) {
  3     var latlng = new google.maps.LatLng(lat,long);   
  4     var label = new Label({
  5                    map: map 
  6               }); 
  7                              
  8     label.set('zIndex',10000000 - (long * 10000));
  9     label.set('text', desc); 
 10      
 11     labels[id] = label; 
 12     positions[id] = latlng; 
 13 }
       These two functions and the code from the link I pasted earlier is enough to create a map with your own markers with your own labels inside. The method that changes most from Marc Ridey's tutorial is the draw event method. It actually differs slightly but I'll add it, to make the post more complete.
  1 // Label drawing event 
  2 Label.prototype.draw = function() { 
  3    var projection = this.getProjection();
  4    var oldid = this.get('text') 
  5    var position = projection.fromLatLngToDivPixel(positions[oldid]);
  6    var div = this.div_;
  7                             
  8    div.style.left = position.x + 'px'; 
  9    div.style.top = position.y + 'px'; 
 10    div.style.display = 'block'; 
 11    div.style.zIndex = this.get('zIndex'); 
 12    this.span_.innerHTML = this.get('text').toString(); 
 13 };
I also added several functions that controlled the map later from my WPF application:
  1 // Remove marker by id 
  2 function deleteMarker(id) {    
  3     var label = labels[id]; 
  4     label.onRemove();                          
  5 } 
  6  
  7 // Center on location 
  8 function setCenter(lat, long) {
  9     var latlng = new google.maps.LatLng(lat, long);
 10     map.panTo(latlng); 
 11 } 
 12    
 13 // Zoom to fit markers 
 14 function zoomToMarkers() {                             
 15     var bounds = new google.maps.LatLngBounds();
 16     for(var x in markers) { 
 17       bounds.extend(markers[x]); 
 18     } 
 19  
 20     map.fitBounds(bounds);                              
 21 }  
 22     
 23 // Remove all markers 
 24 function clearMarkers() { 
 25     for(var x in markers) {   
 26          var label = labels[x]; 
 27          label.onRemove();              
 28     } 
 29 }

Thursday 18 April 2013

Different ways of adding converters in XAML

In this post I'd like to commit to memory several ways of adding converters into the xaml code. There's of course the built in:
Code Snippet
  1. <BooleanToVisibilityConverter x:Key="BoolToVisConverter"/>

As any other converter after that we can simply add it to binding configuration:
Code Snippet
  1. Converter={StaticResource BoolToVisConverter}}

There are other ways of adding and instantiating converters in code though. For instance, what, if we don't want to go through the hassle of adding a converter in resources every time we want to use one? Below you have an ordinary converter with additional property - which changes the converter into a singleton.

Code Snippet
  1. public class ThingToThingConverter : IValueConverter
  2. {
  3.     private static ThingToThingConverter _instance;
  4.     public static ThingToThingConverter Instance
  5.     {
  6.         get
  7.         {
  8.             return _instance ?? (_instance = new ThingToThingConverter());
  9.         }
  10.     }

Thanks to this, we can now use above converter without adding it first to window's/control's resources. Like this:
Code Snippet
  1. Converter={x:Static Converters:ThingToThingConverter.Instance}}">

Another way of doing this is by using MarkupExtension, it's similar to the above, but I find is slightly more comfortable:

Code Snippet
  1. public class SmthToSmthConverter : MarkupExtension, IValueConverter
  2. {
  3.     public static SmthToSmthConverter _converter = null;
  4.  
  5.     public SmthToSmthConverter()
  6.     {        
  7.     }
  8.  
  9.     public override object ProvideValue(IServiceProvider serviceProvider)
  10.     {
  11.         if (_converter == null)
  12.             _converter = new SmthToSmthConverter();
  13.         return _converter;
  14.     }

ProvideValue method is called whenever XAML processor examines a MarkupExtension node and returns our converter into the object graph. All this allows us to use the following markup:
Code Snippet
  1. Converter={Converters:ThingToThingEnumConverter}