Pattern matching and guards in Less stylesheets
Tagged as Web WorkbenchOne really powerful feature of the Less Web stylesheet language is mixins. A Less mixin, like a Sass mixin, is a handy way of grouping multiple CSS values together so you can easily reuse them in several places — it allows you to avoid duplication in your CSS. The syntax is slightly different from Sass mixins, but the concept is the same.
One feature that Less mixins have but Sass mixins don’t is selecting between multiple mixin implementations. There are two ways of doing this: pattern matching and guards.
Pattern matching
In pattern matching, you create multiple implementations of the mixin, each identified by a pattern. For example:
.textBlock (dark, @colour) { color: darken(@colour, 10%); } .textBlock (light, @colour) { color: lighten(@colour, 10%); }
Now when you use the mixin, the implementation that gets chosen will depend on the value you pass for the pattern:
@flavour: light: .wonderful { .textBlock(@flavour, #888); } // Result: // .wonderful { // color: #a2a2a2; // }
Less has selected the ‘light’ implementation of .textBlock based on matching the value of @flavour to the available patterns.
If your implementations have a lot in common, fear not: the “@_” pattern matches anything. So you can put common elements under an “@_” pattern and that will get mixed in along with the properties from the more specific matches.
Guards
Pattern matching is limited to simple values. Guards extend that to expressions. So a guard can perform calculations or type checks in order to determine whether a mixin matches. Here’s an example:
.textBlock (@colour) when (lightness(@colour) >= 50%) { background-color: black; } .textBlock (@colour) when (lightness(@colour) < 50%) { background-color: white; } .textBlock (@colour) { color: @colour; }
If you use the .textBlock mixin with a light colour, the first and third implementations will match, and you’ll get the colour on a black background. If you use it with dark colour, the second and third will match, and you’ll get the colour on a white background. And you can have multiple guards on a single implementation, and-ed or or-ed together depending on when a particular implementation is appropriate.
For more info, see the docs on the Less Web site.
Try it in Web Workbench
The latest version of Mindscape Web Workbench, our free Visual Studio integration tool for Sass, Less and CoffeeScript, provides syntax highlighting for pattern matching and guards, so you can easily pick out patterns from parameters and get quick feedback if you mess up the syntax (I always forget the brackets around guard clauses).
You can download it from the Visual Studio Extension Manager — just click Online Gallery and search for Mindscape Web Workbench.
Nightly news, 27 January 2012
The big news in this week’s nightly builds is the new hotness in the WPF Elements DataGrid. Grouping, exporting, new APIs and, well, grouping again because it’s so neat — check it out! Of course, we’ve got a bunch of other updates for you as well. Here’s what’s new this week.
LightSpeed
- Exclude null associations from polymorphic association validation
- Fix for not being able to return array values from ICompiledParameterValues to populate an IN clause
- Fix for LINQ projection that included the result of a Count on a join-into result when there was no Where clause
- When updating a SQLite database with a GUID field, set COLLATE NOCASE on the column (because it is mapped as a string rather than a native GUID type)
- Added support for per-table identity block size (for when new tables use KeyTable but the database also contains legacy tables which are also updated by other apps using increment-by-1 sequences)
WPF Diagrams
- DiagramConnectionPointBase.OnPositionChanged is now exposed to user derived classes
- Fixed a bug in the ConnectionPointRelocation sample
WPF Elements
- DataGrid hotness!
- Fixed a bug in TimeExplorer
As usual, you can get the updated builds of free versions from the downloads page, and of full versions from the store.
Fresh WPF Elements 5 Features – DataGrid Grouping and Exporting!
Tagged as WPF ElementsOne of the great things about having a fast release cycle is being able to deliver cool new functionality as soon as it’s ready – no waiting for the next quarterly release for a crucial feature that could be released today. In the buildup to WPF Elements 5.1 we’ve been developing some great additions to the existing controls in the suite, as well as going through the codebase with a fine-toothed comb to ensure it remains highly stable and bug-free. We’re not cruel enough to make you wait for these improvements, so you can grab them from the nightly builds right now – both feature additions and bugfixes!
There are many small improvements to the API, such as being able to scroll a particular DataGrid cell into view, as well as two significant additions to the DataGrid we’re sure you’ll find very handy – Grouping and Exporting support. For the rest of the post I’ll be discussing how you can use these two features. First up – grouping!
Grouping
Users can now group data by any number of columns through an intuitive drag-and-drop interface – just drag a column header onto the grouping panel above the grid. Groups can be expanded and collapsed as expected, and the column grouping can be be removed by clicking on a button that appears on mouseover. Any number of columns can be added to the panel and the DataGrid will group the data in a nested fashion. Check out the demo below:
Just set the IsGroupingPanelVisible property to True to enable the grouping UI. Alternatively, if you want to provide your own UI for grouping — or no UI at all, for example if you have an application where the data should always appear grouped — you can group on columns programatically by adding them to the GroupedColumns collection:
MyDataGrid.GroupedColumns.Add(MyDataGrid.EffectiveColumns[0]);
Easy as that. Our DataGrid performance is speedy even with millions of rows, and it stays that way even if the DataGrid has a complex nesting hierarchy.
Exporting
Another handy new feature is the ability to export the data in a DataGrid into an appropriate file format. At the moment we support the near-universal CSV format with more to come, and you can export to file, string or TextWriter. Again, it’s dead easy to use.
DataGridExporter.Csv.WriteFile(MyDataGrid, file);
In combination with a SaveFileDialog, you can export your DataGrid:
and have the resulting file be opened by Excel, complete with columns automatically generated by the DataGrid from your collections.
That saves time! These two features along with bugfixes are available in the nightly builds right now, but they’ll officially be available in the WPF Elements 5.1 soon. You can check out the 60 day trial of WPF Elements 5 here featuring the DataGrid control plus more than 50 others.
Caliburn Micro Part 3: More About Events and Parameters
Tagged as WPFSo far in this Caliburn Micro tutorial series we have looked at how to get started with using Caliburn Micro in a WPF application, and how to link the view and the view-model together using data binding and events. In today’s tutorial, we will take a look at the more advanced ways of hooking up events and specifying event parameters. To experiment with these features, we will be further extending the application created in the previous two blog posts.
You may remember from the previous blog post that we hooked up events using the help of Caliburn Micro’s naming conventions. All we needed to do was set the name of a button in the view to be the same name as a method in the view-model. Then the Click event of the button will be automatically hooked up to call the appropriate method. Sometimes however you will need to explicitly hook up the events in order to provide event parameters or specify exactly which event you want to use. To do this, Caliburn Micro provides a long syntax and a short syntax. The advantage of the long syntax is its compatability with Microsoft Expression Blend. The short syntax is great if you’re not interested in using a designer and want to keep things short and sweet. Let’s start off with learning how to use the long syntax.
Long Syntax
The best way to begin is to modify the existing application to use the long syntax without changing the current behaviour. Open up AppView.xaml and include these 2 namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:cal="http://www.caliburnproject.org"
Then, simply replace the repeat button with this:
<RepeatButton Content="Up" Margin="15" VerticalAlignment="Top"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <cal:ActionMessage MethodName="IncrementCount" /> </i:EventTrigger> </i:Interaction.Triggers> </RepeatButton>
Run the application now and you will see it looks and behaves just as it did before. What we have done here is used System.Windows.Interactivity triggers to hook up an event to a method. In the EventTrigger we can specify which event we want to listen to, and using the Caliburn Micro ActionMessage we can specify which method should be called. Using this approach you can include any number of event triggers to listen to other events on the same control. So you could listen to MouseEnter and MouseLeave to perform additional actions.
Next let’s look at event parameters. To demonstrate this, we will add another button that increments the count by 2. In AppViewModel.cs we need to modify the IncrementCount method to include an integer parameter. This parameter will be used to change the Count property. The IncrementCount method will now look like this:
public void IncrementCount(int delta) { Count += delta; }
Back in AppView.xaml, update the existing repeat button by adding a Caliburn Micro Parameter to the ActionMessage like this:
<cal:ActionMessage MethodName="IncrementCount"> <cal:Parameter Value="1" /> </cal:ActionMessage>
Now when the button is pressed, it will pass a value of 1 as a parameter to the IncrementCount method. Add another button to the application with a parameter of 2 and then run up the application. Clicking on the different buttons will increment the count value according to their different parameters. The Value property of the Caliburn Micro Parameter is a dependency property, which means it also supports the usual WPF data binding. This allows you to use it in all sorts of different scenarios you come across.
Pro Tip: Because of the flexibity of using data binding to set the parameter value, it is possible to pass UI elements from the view into the view-model. You should try to avoid doing this as hard as you possibly can! UI elements in the view-model can fracture your MVVM archetecture and can cause maintenance issues in the future.
Short Syntax
Now to learn how to use the short syntax to do the same thing. To look into this, let’s start off with a fresh copy of the application that doesn’t have our recent long syntax experiments in it. Again we will start by modifying the application without changing its current behaviour. This time we only need to add the Caliburn Micro namespace, and replace the repeat button with this new one:
<RepeatButton Content="Up" Margin="15" VerticalAlignment="Top" cal:Message.Attach="[Event Click] = [Action IncrementCount]" />
All we have done this time is use one of Caliburn Micro’s attached properties (Message.Attach) to specify which event we are interested in, and which method to call.
Next we look at event parameters using this short syntax. Modify the IncrementCount method in same way we did for the long syntax. Including an event parameter using Message.Attach will look like this:
cal:Message.Attach="[Event Click] = [Action IncrementCount(1)]"
The event parameter is written in the brackets after the method name. I’m sure you can work out how to add a button that increments the value by 2.
The short syntax even supports a special form of data binding. To demonstrate this, let’s add a button that increments the count by the count value itself. In other words, a button that doubles the count value. You can remove the CanIncrementCount event guard mentioned in the previous blog post to make the value go higher than 100. The repeat button code would look something like this:
<RepeatButton Content="Double" Margin="15" cal:Message.Attach="[Event Click] = [Action IncrementCount(Count.Text)]" />
Here I have set the parameter to be Count.Text. This sets up a binding to the Text property of the TextBlock (named Count) which is displaying the current value. Notice that Caliburn Micro automatically converts string values that we want to pass into a method that takes a numerical value. Another shortcut that Caliburn Micro provides here is that it will automatically use an appropriate property on a user control if we do not specify a property. In the example above, we could just write the name of the TextBlock (“Count”) as the parameter and Caliburn Micro will bind to the Text property by default. Here is the what the application looks like so far:
Automatically Finding Parameters
To finish off this tutorial I’ll mention that Caliburn Micro even has conventions for automatically picking up parameters when you don’t explicitly set them. If you do not explicitly specify a parameter, Caliburn Micro will look at the parameter name in the method signiture and try find any user control in the view that matches this name (ignoring the case). If a matching user control is found, an appropriate property on the control will be used to provide the parameter. For example, if the user control is a TextBlock, the Text property value will be used as the parameter. Again, Caliburn Micro can automatically convert strings to ints and so on if necessary.
To understand this convention more easily, lets try this out in the application. Add a slider to the application and call it “Delta”. Then add another button called “IncrementCount”. As explained in the previous blog post, the button is going to automatically call the IncrementCount method when it is clicked. This time however, the method has a parameter, but we havn’t specified what value the button should use. Notice that the slider we added is the same name as the parameter (delta). Thus Caliburn Micro will automatically use the Value property of the slider as the parameter to the method whenever the button is clicked. Here is all the code we needed to add to do this:
<UniformGrid Columns="2" VerticalAlignment="Bottom"> <Slider Name="Delta" Minimum="0" Maximum="5" Margin="15" /> <Button Name="IncrementCount" Content="Increment" Margin="15" /> </UniformGrid>
Extra for Experts
Here I’ve only covered some of the support that Caliburn Micro provides for hooking up events. Some other topics of intrest include:
- Setting action targets
- Special parameter values for data binding
- Action bubbling
- Action guards with parameters
You can find more information about hooking up events using Caliburn Micro from the online documentation. I recommend reading through the documentation so you can better choose which approaches to use for the various event scenarios in your application. You’ll find there is a lot of helpful support that Caliburn Micro provides, and a lot of convenient conventions that will take work off your shoulders. The Cheat Sheet is a useful page to bookmark. You’ll also find that the HelloExplicitAction, HelloParameters and BubblingAction samples are a good source of knowledge.
You can download the application from this tutorial used to demonstrate the long syntax from here, and the short syntax from here.
Until next time, Happy Coding!
DataGrid customization with Elements 5: Sparklines, template selectors and more
Tagged as WPF ElementsFollowing on from earlier posts about our new DataGrid control in WPF Elements 5, today I’ll be demonstrating some deeper customization options by creating a financial data display demo. By making a Chart control with an embedded LineSeries and setting a couple of properties we can create a great looking Sparkline graph, which can then be used as a template for a DataGrid column consisting of those graphs. All of this is included in WPF Elements 5, and you can grab the 60 day fully featured trial here to get started. I’ll then look at creating a template selector to apply templates to cells depending on their data, and the demo will also use a bit of custom logic to highlight the largest and smallest values in the collections. The final result will end up like this:
To begin, declare a new DataGrid control in a XAML page and bind its ItemsSource property to a collection in a similar manner to Working with the Data Grid – Day 1. If we are to add charts to this DataGrid its model will need a property of a type that contains an ObservableCollection of DateTimeDouble objects, which the LineGraph will use to draw itself. Here’s an archive with example data structures illustrating the required behavior (which generate random points suitable for the purposes of this demo): DataModel.
Setting up the sparkline charts
Next, in the ResourceDictionary add the following DataTemplates containing the formatted charts. The Chart control in WPF Elements 5 has heaps of customization options, and with a few simple tweaks the LineSeries can display a great looking Sparkline chart. Here’s one possible look for a Sparkline template:
<DataTemplate x:Key="BidChartCell"> <ms:Chart LegendPosition="None" TitleTemplate="{x:Null}" Padding="3"> <ms:LineSeries ItemsSource="{Binding BidTrend.Data1}" AlwaysShowYAxisZero="False" YAxisDataBuffer="1000" /> <ms:Chart.XAxis > <ms:ChartAxis Visibility="Collapsed" /> </ms:Chart.XAxis> <ms:Chart.YAxis> <ms:ChartAxis Visibility="Collapsed" /> </ms:Chart.YAxis> </ms:Chart> </DataTemplate>
The chart declared in that DataTemplate is going to look rather unnatural in any place larger than a DataGrid cell, so let’s apply it to a column in our DataGrid by setting its DisplayTemplate property:
<ms:DataGrid ItemsSource="{Binding Data}" AllowEditing="False"> <ms:DataGrid.Columns> <ms:DataGridColumn PropertyName="BidTrend" DisplayTemplate="{StaticResource BidChartCell}" Header="Bid Trend"/> </ms:DataGrid.Columns> </ms:DataGrid>
Pretty easy! If you were to increase the rows in the model you’d notice the performance is speedy even with dozens of charts on screen, and stays that way during resizing, dynamic data updating and similar tasks.
Showing additional data with template selectors
Now how about formatting the Change columns to show an image based on the data in each cell? One solution would be to create a custom class that derives from DataTemplateSelector and overrides SelectTemplate(). Here’s a snippet of the implementation with logic that returns a template based on whether the cell’s Double is positive or negative:
public class ChangeDataTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { FrameworkElement element = container as FrameworkElement; if (element != null && item != null) { Entry entryItem = item as Entry; if (ChangeType == CellChangeType.Bid) { if (entryItem.BidChange < 0) { return NegativeChangeTemplate; } else if (entryItem.BidChange > 0) { return PositiveChangeTemplate; } } else { if (entryItem.AskChange < 0) { return NegativeChangeTemplate; } else if (entryItem.AskChange > 0) { return PositiveChangeTemplate; } } } return NoChangeTemplate; } public DataTemplate PositiveChangeTemplate { get; set; } }
The full code with the other two properties and the enum is contained in the archive at the bottom of this post. Back in the XAML, add the DataTemplates that are to be applied to the cell to the ResourceDictionary (here’s one of four required):
<DataTemplate x:Key="PositiveBidChangeTemplate"> <Grid HorizontalAlignment="Center" x:Name="PositiveBidCell"> <Grid.ColumnDefinitions> <ColumnDefinition Width="35" /> <ColumnDefinition Width="20" /> </Grid.ColumnDefinitions> <TextBlock Text="{Binding BidChange}" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,6,0" /> <Image Source="../Images/up.png" Width="16" Height="16" Grid.Column="1" /> </Grid> </DataTemplate>
We can now declare an instance of our DataTemplateSelector and set its properties to our DataTemplates. The Bid selector will look like this:
<local:ChangeDataTemplateSelector x:Key="BidChangeSelector" PositiveChangeTemplate="{StaticResource PositiveBidChangeTemplate}" NegativeChangeTemplate="{StaticResource NegativeBidChangeTemplate}" ChangeType="Bid" NoChangeTemplate="{StaticResource NoChangeBidTemplate}" />
Now that has been set up, it’s a simple matter of setting the DisplayTemplateSelector property on the appropriate DataGridColumn that you wish to apply the templates to. We may as well make the column’s title look a bit nicer at the same time.
<ms:DataGridColumn PropertyName="BidChange" Header="Bid Change" DisplayTemplateSelector="{StaticResource BidChangeSelector}" />
That will get the Change and Trend columns looking like the screenshot at the top of this post. In a future post I’ll show how to extend the model to record the highest and lowest data, and use XAML triggers to format cells based upon that information. In the meantime, check out the archive below for the full code from this post.
DataGrid with sparklines and template selectors
And don’t forget to download the 60-day trial of WPF Elements and try out your own designs!
Categories
BrainDump (1)
Community Code (4)
Events (15)
F# (11)
General (50)
Lab Samples (2)
LightSpeed (249)
MegaPack (7)
News (68)
NHibernate Designer (18)
Nightly news (40)
Phone Elements (22)
Products (87)
Projects (5)
Screencast (6)
SharePoint (3)
Silverlight (14)
Silverlight Elements (59)
SimpleDB Management Tools (20)
Visual Studio (9)
VS File Explorer (7)
Web Workbench (20)
WPF (43)
WPF Diagrams (53)
WPF Elements (91)
WPF Property Grid (32)




Posted by Ivan Towlson on 26 January 2012 








