Archive for the ‘WPF Elements’ category
Nightly news, 11 May 2012
A strange week at Mindscape HQ as the troops have been primarily focused on working out how to use the motion-activated candy dispenser… and then how to stop it again. But fear not, in between all the wild Kinect-style gesticulations, we have managed to bash out a good crop of features and fixes. Here’s what you’ll find in this week’s nightly builds.
WPF Elements
- Added DataGridColumn.Foreground property
- DataGridColumn.DisplayTemplate is now respected when using DisplayMemberBinding
- DataGridColumn.DisplayMemberBinding now supports StringFormat
- DataGridColumn now respects DisplayNameAttribute when using PropertyName or DisplayMemberBinding
- Added ToolTipBinding property for charting data series
- Scatter charts now support missing data points (when a value is null or NaN)
- You can now set the starting (Minimum) value of a logarithmic axis scale
- Charting performance improvements
- Added built-in nullable type editors to DataGrid and PropertyGrid
Web Workbench
- CoffeeScript compiler now warns if a file contains mixed tabs and spaces
- Fix for Less compiler error when calling colour functions on a named (not hex) colour
- Fix for performance problem when using Pro Power Tools Enhanced Scroll Bar with the ‘show bookmarks and breakpoints’ option
- Fixed a couple of highlighting errors
LightSpeed
- Added MarkPropertyChanged method so that properties can be manually marked as dirty — for example, when changing properties of a mutable user-defined type. Mutable value objects! Forsooth!
WPF Diagrams
- DiagramBitmapRenderer now handles dynamic resources
As usual the free editions of the nightly builds are available right now from the downloads page, and the full editions from the store.
Nightly news, 4 May 2012
LightSpeed
- Updated SQLite provider to 1.0.80
- Fix for cascade delete across a STI hierarchy where the cascade enters the hierarchy in a derived class and we were trying to proceed through an association declared in a sibling class
Web Workbench
- Added JSHint support
- Fixed syntax highlighting for identifiers starting with an underscore
- Fixed incorrect ‘less than or equal to’ operator in Less mixin guards
- Added highlighting support for inline data URLs
- Fixed highlighting when using a comparison expression was used as a function argument
- Fixed highlighting of interpolated variables in URLs
- Fixed highlighting when a function call contained arguments that were spaced lists, and a nonfinal element of such a list was another function call
- Switched Sass compiler from IronRuby to ‘proper’ Ruby
WPF Diagrams
- Fixed a bug with connection point positions in a rotated nested node
- Added sample of removing a groupable node from its parent
WPF Elements
- Fixed a couple of issues when changing DataGrid.ItemsSource from null to a collection instance
- Fixed a hit testing issue with DataGrid cells
- Fixed an issue when a DataGrid contains a mix of star-sizing and absolute-sizing columns
- DataGrid DisplayMemberBinding now supports UpdateSourceTrigger of LostFocus
- Fixed a validation bug in DisplayMemberBinding
- Fixed the TrackingElement sample to support duplicate values
- Fixed an error if a chart XBinding or YBinding was set to a nonexistent property
Silverlight Elements
- First drop of spell checking for the HTML rich text editor
- Ctrl+Left and Ctrl+Right in the HTML editor now respect symbols
- Fixed a bug in ContextMenu where if it was forced closed due to the browser window being resized, it would never open again
All these updates are in the current nightly builds — free editions from the downloads page, full editions from the store.
Using WPF Elements from F#
WPF and F#? It’s not a natural mix — Visual Studio doesn’t provide templates or tooling for F# WPF projects, and WPF’s implicit architecture normally implies mutable view models which are at odds with F#’s preference for immutable data types. But sometimes a project comes along which seems like a great fit for F#, and for a WPF front end. A great example is data visualisation. Retrieving and processing the data is exactly what F# does well, and innovative ways of presenting data are much easier to implement on WPF than on any other platform; and in a visualisation scenario the main view model is typically immutable.
I’m going to look at two ways of combining F# and WPF. I’ll be using the Chart control from WPF Elements as my main example, but a lot of what I talk about here is equally applicable to any other WPF control, built-in or third-party.
Solution 1: Hybrid C# and F# Solution
The traditional way of using F# in a WPF application is to put the F# code into a class library, then invoke that class library from a C# or Visual Basic WPF application. This works very easily — a C# application can call a F# class library just as easily as it can a C# class library, with full intellisense and debugging and everything else you’d expect.
For this example, I’m going to keep the F# class library very simple. In reality, you probably wouldn’t create a separate class library for something this basic. F# really starts to shine when you’re doing a bit more processing on your data, but to keep things simple I’m not going to do much more than download it.
The data I’m going to use is the London Borough Profiles from the Windows Azure Datamarket. This is dead easy to use in F# 3.0 thanks to the OData type provider:
open Microsoft.FSharp.Data.TypeProviders type Boroughs = ODataService<"https://api.datamarket.azure.com/GreaterLondonAuthority/LondonBoroughProfiles/"> let dataContext = Boroughs.GetDataContext() dataContext.Credentials <- System.Net.NetworkCredential(YourUserName, YourAccountKey)
For my view model, I want to extract just a subset of this data, so I define a couple of F# types to surface it:
open System.Collections.Generic type BoroughInfo = { Area : string MaleLifeExpectancy : float FemaleLifeExpectancy : float Employment : float } type ViewModel = { Boroughs : List<BoroughInfo> // not BoroughInfo list -- see below National : BoroughInfo }
These are F# immutable record types. We don’t need to modify the data, so immutable types are easier to write and we don’t need to muck around with all that tedious INotifyPropertyChanged stuff. The view model is going to include a list of entries for individual boroughs, plus a ‘dummy’ borough representing national averages so I can display them alongside the per-borough data.
One gotcha is that the WPF Elements charting DataSeries expects an IList as its ItemsSource. The F# list type doesn’t implement IList, so we have to be sure to make ViewModel.Boroughs a BCL List instead of a F# list.
Now we can build our view model:
let (national, boroughs) = dataContext.LondonBoroughProfiles |> Seq.filter (fun r -> r.MaleLifeExpectancy20072009.HasValue && r.FemaleLifeExpectancy20072009.HasValue) |> Seq.map (fun r -> { Area = r.Area; MaleLifeExpectancy = r.MaleLifeExpectancy20072009.Value; FemaleLifeExpectancy = r.FemaleLifeExpectancy20072009.Value; Employment = r.EmploymentRate2009.Value }) |> Seq.toList |> List.partition (fun b -> b.Area = "National Comparator") let viewModel = { Boroughs = List<_>(boroughs); National = List.head national }
Most of this should be self-explanatory — we are downloading all the borough data from the data context provided by the OData type provider, filtering out a couple of containers that don’t have data, and mapping away the nullable values. (We could have done some of this using F# query expressions, but it’s not worth it for this data set.) The only thing that may be unfamiliar is List.partition, which splits a list into two lists, the first containing things that satisfy the predicate and the second containing things that don’t. The assignment therefore puts the ‘National Comparator’ pseudo-borough into the ‘national’ list, and the real boroughs into the ‘boroughs’ list.
The end result of all this is a value called ‘viewModel’ of type ViewModel, and we can now consume this from a C# application:
// Code-behind for MainWindow.xaml -- or of course you could automatically // wire it up using Caliburn Micro. public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = Data.viewModel; } }
<e:Chart Margin="12"> <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding MaleLifeExpectancy}" SeriesBrush="Navy" /> <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding FemaleLifeExpectancy}" SeriesBrush="Red" /> <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding Employment}" YAxisTitle="Employment (%)" SeriesBrush="Green" /> <e:Chart.XAxis> <e:ChartAxis LabelRotation="90" LabelStep="1" MajorTickSpacing="1" /> </e:Chart.XAxis> <e:Chart.YAxis> <e:ChartAxis Minimum="65" Maximum="90" Title="Life Expectancy (yr)" /> </e:Chart.YAxis> <e:Chart.AlternativeYAxes> <e:ChartAxis Minimum="50" Maximum="100" Title="Employment (%)" /> </e:Chart.AlternativeYAxes> </e:Chart>
Solution 2: All F# Solution
With F# 3.0, though, it’s now feasible to build WPF applications entirely in F#, without needing to put the user interface into C#. In practice I know most readers of this blog will probably feel more at home in C# than in F# so they’ll want to use F# only for the core data processing anyway — but I think it’s interesting to know how F# 3.0 enables XAML support, plus there are a couple of things that may not be quite so obvious! (This example is based on Steffen Forkmann’s WPF Designer for F# announcement, which is in turn based on Johann Deneux’ XAML type provider.)
The first thing we need to do is create a Windows Application F# project. There isn’t a template for this, but we can take our class library project, go into Properties > Application, and change the Output Type to Windows Application (and add a Program.fs file to contain the application code). Or we can create a new F# Application project and change the Output Type from Console Application to Windows Application.
Next we need the XAML type provider. This is available as a NuGet package from the FSharpx folks. Right-click the F# project, choose Manage NuGet Packages, search for FSharpx.TypeProviders and click Install. (Learn more about FSharpx here.)
We also need to add references to the WPF assemblies (WindowsBase, PresentationCore, PresentationFramework and System.Xaml) and to the WPF Elements DLL.
The last piece of plumbing we need is to handle the licensed controls in WPF Elements. Copy the licenses.licx file from the WPF Elements Sample Explorer to the F# project directory, include it in the F# project and set its Build Action to Embedded Resource.
Now we’re ready to roll, where by ‘roll’ I mean create an actual WPF window.
Right-click the project and choose Add New Item. There’s no XAML template but just choose XML File and change the file extension to .xaml, e.g. MainWindow.xaml. Replace the contents of the .xaml file with the following:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:e="clr-namespace:Mindscape.WpfElements.Charting;assembly=Mindscape.WpfElements" Title="MainWindow" Height="500" Width="900"> <e:Chart> <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding MaleLifeExpectancy}" SeriesBrush="Navy" /> <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding FemaleLifeExpectancy}" SeriesBrush="Red" /> <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding Employment}" YAxisTitle="Employment" SeriesBrush="Green" /> <e:Chart.XAxis> <e:ChartAxis LabelRotation="90" LabelStep="1" MajorTickSpacing="1" /> </e:Chart.XAxis> <e:Chart.YAxis> <e:ChartAxis Minimum="65" Maximum="90" /> </e:Chart.YAxis> <e:Chart.AlternativeYAxes> <e:ChartAxis Minimum="50" Maximum="100" Title="Employment" /> </e:Chart.AlternativeYAxes> </e:Chart> </Window>
One little nasty to watch out for: the F# XAML type provider currently handles only ‘clr-namespace’ namespaces. So we have to refer to the Mindscape.WpfElements.Charting namespace by name, instead of using the URI. Other than that this is the same XAML as in the C# application.
Finally we need to write some code to launch this window and associate it with our view model. In C#, the project template handled this for us but in F# we need to do it ourselves. Fortunately all the hard work is done by the XAML type provider:
open System open System.Windows open FSharpx type MainWindow = XAML<"MainWindow.xaml"> // creates the MainWindow type from the MainWindow.xaml file let loadWindow() = let window = MainWindow() // creates a new instance of MainWindow window.Root.DataContext <- Data.viewModel window.Root [<STAThread>] (new Application()).Run(loadWindow()) |> ignore
You can now build and run the application, and you’ll find it works just like the C# one. Of course, it has taken a bit more effort to set up, but that’s a one-off, and you can now enjoy using F# for your interaction logic as well as your business logic.
You can download the source for the F# WPF Elements demo project here. You will need Visual Studio 11 Beta, and a copy of Mindscape WPF Elements (download the free edition including a 60-day trial of the charting controls). (To run the program, you’ll also need to sign up for the free London Borough Profiles data set on Azure Datamarket.) If you have any questions or problems, post in the comments or the support forum!
Nightly news, 27 April 2012
WPF Elements
- Charting performance improvements
- The Chart control now provides a FinishedPlotting event
- Fixed a bug with displaying lots of data in a stacked chart
- Added support for customising the scheduler recurrence dialogs
- ScheduleFormatter now provides an option for customising the default name of newly created schedule items
- Fixed a bug in the TimePicker control
- You can now customise the background of individual cells, rows and columns of a DataGrid
- The DataGrid no longer performs highlighting on mouse-over in RowAndCell mode, except when the mouse is over the row header
- Added validation support to DataGrid DisplayMemberBinding
- If you set the Value directly on a numeric text box, it now constrains the value to the permitted range instead of throwing an exception
LightSpeed
- Fix for error during database update if a design-time assembly could not be found
- Fix for error in SaveChanges under heavy load
- Improvements to grouping support: better support for functions and traversals in grouping keys
- Change to allow non-nullable GUID, DateTime and blob columns to be added to existing SQLite tables
Web Workbench
- Added an option to show generated files when choosing files to merge during minification
NHibernate Designer
- Added support for table per subclass inheritance
- Added support for creating MySQL MEDIUMTEXT and LONGTEXT columns
All these features and fixes are in the current nightly builds — free editions from the Downloads page, full editions from the store.
Customizing the WPF scheduler dialog boxes
Tagged as WPF ElementsOne of the controls in our WPF Elements control suite is the familiar Outlook styled Scheduler. This lets users add, edit and view appointments that are scheduled to occur at a particular date and time. Some of these actions such as editing a recurrence pattern are performed by the user changing values in a dialog box as seen below.
In the current nightly build we have made it easier to customize the template of these dialog boxes. By customizing the dialog boxes you can change the colors and styles of the various controls to suit the needs of you application. This also means you can localize the dialogs by changing the text labels. The best way to create a custom dialog style is to start with the code for the default style and then alter it however you need. Below is the default styling code for the dialog used for adding schedule items.
<ms:BooleanToObjectConverter x:Key="RecurrenceButtonContentConverter" TrueObject="Edit Recurrence" FalseObject="Add Recurrence" /> <Style x:Key="ScheduleItemDialogStyle" TargetType="ms:ScheduleItemDialog"> <Setter Property="Title" Value="New Appointment" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Grid x:Name="LayoutRoot" Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="70" /> <ColumnDefinition Width="10" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="22" /> <RowDefinition Height="10" /> <RowDefinition Height="22" /> <RowDefinition Height="10" /> <RowDefinition Height="22" /> <RowDefinition Height="10" /> <RowDefinition Height="22" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Button Command="{x:Static ms:SchedulerCommands.EditRecurrenceCommand}" Grid.Column="2" Width="100" HorizontalAlignment="Left" Content="{Binding HasRecurrence, Converter={StaticResource RecurrenceButtonContentConverter}, RelativeSource={RelativeSource TemplatedParent}}" /> <TextBlock TextAlignment="Right" VerticalAlignment="Center" Grid.Row="2">Subject:</TextBlock> <TextBox Text="{Binding Subject, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Row="2" Grid.Column="2" /> <TextBlock TextAlignment="Right" VerticalAlignment="Center" Grid.Row="4">Start time:</TextBlock> <StackPanel Orientation="Horizontal" Grid.Row="4" Grid.Column="2"> <ms:DropDownDatePicker Width="205" Margin="0,0,10,0" Value="{Binding StartDate}" Format="Custom" CustomFormat="dd/MM/yyyy" /> <ms:TimePicker Width="80" SelectedTime="{Binding StartTime}" ItemsSource="{Binding StartTimeList}" /> </StackPanel> <TextBlock TextAlignment="Right" VerticalAlignment="Center" Grid.Row="6">End time:</TextBlock> <StackPanel Orientation="Horizontal" Grid.Row="6" Grid.Column="2"> <ms:DropDownDatePicker Width="205" Margin="0,0,10,0" Value="{Binding EndDate}" Format="Custom" CustomFormat="dd/MM/yyyy" /> <ms:TimePicker Width="80" SelectedTime="{Binding EndTime}" ItemsSource="{Binding EndTimeList}" /> </StackPanel> <StackPanel Orientation="Horizontal" Grid.Row="7" Grid.Column="2"> <Button Command="{x:Static ms:SchedulerCommands.OkCommand}" Content="Save & Close" Width="95" Height="23" Margin="0,18,0,0" /> <Button Command="{x:Static ms:SchedulerCommands.CancelCommand}" Content="Cancel" Width="75" Height="23" Margin="10,18,0,0" /> </StackPanel> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
The default styling code for all 3 dialog box templates can be downloaded here. You may notice that each style is also setting the Title property using a setter. This changes the title of the dialog window which is convenient for localization or to simply provide a different title. In order for the Scheduler control to use your custom styles, you just need to create an instance of the SchedulerFormatter and set the appropriate properties. This is demonstrated in the code below.
<ms:SchedulerFormatter x:Key="Formatter" ScheduleItemDialogStyle="{StaticResource ScheduleItemDialogStyle}" RecurrenceDialogStyle="{StaticResource RecurrenceDialogStyle}" DeleteRecurrenceDialogStyle="{StaticResource DeleteRecurrenceDialogStyle}" DefaultScheduleItemName="New Schedule Item" /> <ms:Scheduler Formatter="{StaticResource Formatter}" />
Here I am also setting the DefaultScheduleItemName property which is also new in the latest nightly build. This lets you change the default name of newly created schedule items, which again is convenient for localization.
The current nightly build for the trial version can be downloaded from here, or you can go to your account page if you’re already a customer.
And that’s all you need to know to start creating your own custom dialog styles for the Scheduler. If you have any questions or need assistance with any of this, then we’d love to hear from you in the forum!
Categories
BrainDump (1)
Community Code (4)
Events (16)
F# (14)
General (53)
Lab Samples (2)
LightSpeed (268)
MegaPack (8)
News (71)
NHibernate Designer (26)
Nightly news (53)
Phone Elements (24)
Products (87)
Projects (5)
Screencast (6)
SharePoint (3)
Silverlight (14)
Silverlight Elements (66)
SimpleDB Management Tools (20)
Visual Studio (9)
VS File Explorer (7)
Web Workbench (39)
WPF (44)
WPF Diagrams (57)
WPF Elements (110)
WPF Property Grid (32)




Posted by Ivan Towlson on 10 May 2012 





