Semantic Zoom and LINQ: Better Together 05 March 2013 Diederik-Krols Metro, WinRT With this short article, I want to show you the easy way to provide data to a semantic zoom in a Windows 8 Store app. I’ve seen too many developers trying to massage their business data to make it consumable for a semantic zoom, by pulling it through custom implementations of ISemanticZoomInformation or through other data adapter classes. You see this pattern even in the official XAML GridView grouping and SemanticZoom sample. All you need to remember from this article, is that such infrastructure is not necessary: the grouped data source for the CollectionViewSource that populates the two zoom levels of a semantic zoom control, can be generated by a simple LINQ query that your ViewModel can pull straight out of your Models. As usual, I built a simple MVVM app to illustrate my point. It comes with two Model classes: Item and Category, where each item has a category. I do realize that this will not help me win the Oscar for the most original scenario. The data access layer provides a list of both. The only View in the app just shows a semantic zoom that pulls its data (items with a category) from a property in the main ViewModel. Here’s how the two levels of the semantic zoom look like at runtime. Zoomed in: Zoomed out: The CollectionViewSource is defined as a resource in XAML, and bound to the zoomed-in view of the semantic zoom: <Page.Resources> <CollectionViewSource x:Name="collectionViewSource" IsSourceGrouped="True" Source="{Binding ItemsByCategory}" /> </Page.Resources> <!-- ... --> <SemanticZoom x:Name="semanticZoom"> <SemanticZoom.ZoomedInView> <GridView ItemsSource="{Binding Source={StaticResource collectionViewSource}}" SelectionMode="None"> <!-- ... --> </GridView> </SemanticZoom.ZoomedInView> <!-- ... --> </SemanticZoom> The CollectionViewSource gets its data from the viewmodel through a LINQ query that yields the items, grouped by category: itemsByCategory = from item in Items orderby item.Name group item by item.Category into g orderby g.Key.Name select g; By the way, this is how that same query looks like in the official sample: internal List<GroupInfoList<object>> GetGroupsByCategory() { List<GroupInfoList<object>> groups = new List<GroupInfoList<object>>(); var query = from item in Collection orderby ((Item)item).Category group item by ((Item)item).Category into g select new { GroupName = g.Key, Items = g }; foreach (var g in query) { GroupInfoList<object> info = new GroupInfoList<object>(); info.Key = g.GroupName; foreach (var item in g.Items) { info.Add(item); } groups.Add(info); } return groups; } That's a lot of obsolete code. For the sake of simplicity, I spare you from the definition of the -also obsolete- GroupInfoList class. Looking at this code, one can only agree when a tweet like this one pops up in his timeline: Enough ranting, let's go back to the sample. The LINQ query returns an IEnumerable<IGrouping<Category, Item>>. And that’s enough to provide a source for all semantic zoom bindings. The zoomed-out view of the semantic zoom has several templates. The item template is bound to each item, so the binding expressions are straightforward: <GridView.ItemTemplate> <DataTemplate> <!-- Bound to an Item --> <StackPanel> <Image Source="{Binding Image}" ... /> <Border ... > <TextBlock Text="{Binding Name}" ... /> </Border> </StackPanel> </DataTemplate> </GridView.ItemTemplate> Each grouping (= category) has a group style header, of which the template is bound to an IGrouping. That interface only provides a Key attribute, but that's enough to provide the title: <GroupStyle.HeaderTemplate> <DataTemplate> <!-- Bound to an IGrouping with Category as Key--> <Grid Margin="0"> <TextBlock Text='{Binding Key.Name}' ... /> </Grid> </DataTemplate> </GroupStyle.HeaderTemplate> The zoomed-in view of the semantic zoom is bound to the collection of groups in the data source. We (still) have to do this in code behind: protected override void OnNavigatedTo(NavigationEventArgs e) { // IObservableVector<IGrouping<Category, Item>> (this.semanticZoom.ZoomedOutView as ListViewBase).ItemsSource = collectionViewSource.View.CollectionGroups; } This is an ICollectionViewGroup, so it comes with Group and GroupItems properties. These properties come in handy to provide binding expressions. Group.Key returns the category instance, but you could also choose to just follow the links in the viewmodel from the items' perspective: <GridView.ItemTemplate> <DataTemplate> <!-- Bound to an ICollectionViewGroup --> <StackPanel> <Border> <TextBlock Text="{Binding Group.Key}" ... /> </Border> <Image Source="{Binding GroupItems[0].Category.Image}" ... /> </StackPanel> </DataTemplate> </GridView.ItemTemplate> As you see, you don’t need special infrastructure to populate a two-level semantic zoom. All bindings can be fulfilled with just your ViewModels and a little LINQ. Here’s the code: U2UConsult.Win8.SemanticZoomWithLinq.V2.zip (531.35 kb) Enjoy! Diederik
Building Custom Controls for Windows 8 Store apps 06 December 2012 Diederik-Krols Metro, WinRT This article explains how to build custom controls for Windows Store apps, using XAML and C#. Custom controls are the most powerful controls in the XAML department. Once you know how to design and build these, you’ll have no problems with their alternatives: user controls, derived controls, and extended controls. Let’s start with a definition: a custom control is a reusable templatable control that comes with a generic.xaml file and some code behind. Generally a custom control is stored in its own assembly to make it reusable in multiple apps. As a developer, you decorate a custom control with properties, methods, events, and a default style. The users of the control –developers who use your custom control in their apps- should live with the code behind, but are free to completely restyle the XAML part. Hello again, Simple Slider Almost a year ago, I built a custom slider control in an earlier version of Visual Studio and the Windows Runtime. A lot has changed since then – fortunately for the better. For this article, I decided to redo that slider. I’ll stick to its original anatomy: a horizontal slider is just a draggable Thumb in a Border. While dragging, a Rectangle is drawn to fill the space at the left side of the Thumb: Getting Started Recent versions of Visual Studio 2012 –including the free Express edition- come with a template to create a custom control. All you need to do to get started is adding a new item of the type ‘Templated Control’ to your project: It will create the code behind file as well as the generic.xaml in the Templates folder. Properties A custom control directly inherits from Control itself, the mother of all controls. It immediately comes with a couple of useful properties like Height, Width, and Visibility. Of course you would want to add your own properties. A slider control e.g. should have at least properties to represent its minimum, maximum and current value. Since we’re interested in data binding, we will implement these as DependencyProperty instances. Using the propdp code snippet, you can rapidly define a property and provide its name, type, default value, and the function that will be called when the value changes. In the case of our slider, we are definitely interested in knowing when the value changed: it’s the sign to redraw the control. Here’s how the definition of the Value property looks like: public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value", typeof(double), typeof(Slider), new PropertyMetadata(0.0, OnValueChanged)); public double Value { get { return (double)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } private static void OnValueChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { // Recalculate part sizes. // ... } Styling The generic.xaml file will contain the default style for the control. While typing in that code, you have intellisense but no designer support. Here’s how the basic slider style looks like in XAML. <Style TargetType="local:Slider"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:Slider"> <Grid> <Border Height="40" VerticalAlignment="Stretch" Background="Gray" Margin="0" Padding="0" BorderThickness="0" /> <Canvas Margin="0" Height="40"> <Rectangle x:Name="PART_Rectangle" Height="38" Fill="SlateBlue" Margin="0 1" /> <Thumb x:Name="PART_Thumb" Background="LightSteelBlue" Width="40" Height="40" Margin="0" /> </Canvas> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> The default style is assigned to the control in its constructor: public Slider() { this.DefaultStyleKey = typeof(Slider); } This is a screenshot of the custom slider: In the style definition, the Thumb and Rectangle controls were given an x:Name value. This is because we need to manipulate them when (re)drawing the slider from code behind. That puts some constraints on the ‘templatability’ of the custom control: no matter how the designer wants to make the control look like, he or she needs to make sure that the template contains a Thumb and a Rectangle with the expected name. Fortunately you have some ways to notify these constraints to the designer. First there is a naming convention that specifies that the element’s name should start with ‘PART_’. More important is the fact that you can decorate the class with TemplatePart attributes. These will be recognized by tools like Expression Blend. Here’s the definition in C#: [TemplatePart(Name = ThumbPartName, Type = typeof(Thumb))] [TemplatePart(Name = RectanglePartName, Type = typeof(Rectangle))] public sealed class Slider : Control { private const string ThumbPartName = "PART_Thumb"; private const string RectanglePartName = "PART_Rectangle"; // ... } You find the named parts with the GetTemplateChild method. When using your control, a designer could have ignored the expected parts, so make sure you look them up defensively: protected override void OnApplyTemplate() { this.thumb = this.GetTemplateChild(ThumbPartName) as Thumb; if (this.thumb != null) { this.thumb.DragDelta += this.Thumb_DragDelta; } // ... base.OnApplyTemplate(); } This code is typically written in an override of the OnApplyTemplate method. Don’t use the Loaded event. The visual tree of a templated control might be still incomplete at that stage. Visual State Management Depending on its state (enabled, disabled, focused, snapped, etc.) a control will look and feel slightly or drastically different. This is where the VisualStateManager comes in action. The visual state manager invokes transformations when the state of the control changes. E.g. if the control is disabled, it will recolor it in fifty shades of gray. The states and transformations can be described declaratively in XAML: <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Thumb" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="LightSteelBlue" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Rectangle" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="SlateBlue" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Thumb" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="LightGray" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_Rectangle" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="DimGray" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> When the control is used inside a LayoutAwarePage, then it will listen automagically to state changes. But we can’t make assumptions on how and where our control is going to be used. Fortunately, in code behind it is possible to trigger the visual state manager programmatically. Here’s an example where we disable the control from C#: private void Slider_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) { if (this.IsEnabled) { VisualStateManager.GoToState(this, "Normal", true); } else { VisualStateManager.GoToState(this, "Disabled", true); }; } Here's the result when the app is running: Again, this puts some constraints on the templatability of the control: the designer has to make sure that the visual states that we invoke programmatically exist in the overridden style. Again we as developer can document these constraints by decorating the class with TemplateVisualState attributes: [TemplateVisualState(Name = "Normal", GroupName = "CommonStates")] [TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")] public sealed class Slider : Control { // ... } Templating The style in the generic.xaml is just a default style. It can be completely overridden, as long as the TemplatePart and VisualState constraints are respected. Here’s an example of how to give the default slider a brand new jacket: <cc:Slider> <cc:Slider.Template> <ControlTemplate TargetType="cc:Slider"> <Grid> <Border Height="80" VerticalAlignment="Stretch" Background="Transparent" /> <Line VerticalAlignment="Center" X1="0" Y1="0" X2="3000" Y2="0" StrokeThickness="7" Stroke="White" StrokeDashArray="1" /> <Canvas Margin="0" Height="80"> <Rectangle x:Name="PART_Rectangle" Height="12" Canvas.Top="34" Fill="DarkSlateBlue" /> <Thumb x:Name="PART_Thumb" Width="80" Height="80"> <Thumb.Template> <ControlTemplate> <Image Source="Assets/Pacman.png" Height="80" /> </ControlTemplate> </Thumb.Template> </Thumb> </Canvas> </Grid> </ControlTemplate> </cc:Slider.Template> </cc:Slider> Here’s how it looks like: Events To add an event to your control, just declare it and raise it at the appropriate time. I have decorated the slider with an event ‘BoundHit’ that is raised when the value hits minimum or maximum: public event EventHandler BoundHit; private void OnBoundHit(EventArgs e) { if (this.BoundHit != null) { this.BoundHit(this, e); } } private void Thumb_DragDelta(object sender, DragDeltaEventArgs e) { // ... this.OnBoundHit(EventArgs.Empty); // ... } The page that hosts the slider can now react to it: <cc:Slider BoundHit="ccSlider_BoundHit" /> This is what it does in the attached sample project: Admit it: you never saw a slider do this ;-) From Slider to Gauge This is basically all you need to know to roll your own custom controls. If you don’t believe me, feel free to dive into the attached source code of the following Radial Gauge control. It’s a new version of a control I built some months ago: you find its story here. Since then the .NET framework improved and so did my code. Now the radial gauge may be a bit more complex than the slider: there are some animations and converters involved. But apart from that, it only contains stuff we covered in this article: a default style in generic.xaml, an override of OnApplyTemplate, and a TemplatePart - no visual states. Functionally all that a radial gauge does is rotating a needle when its value changes. That basically makes it a templated … slider. Anyway if you’re looking for a basic radial gauge with a color scale, here you have one: Alternatives User Controls Custom controls are the most powerful controls to build, although not always the most developer-friendly: you don’t have support from Visual Studio’s designer when defining the style. Fortunately this is not the case with User Controls. For more details, check my previous blog item. Derived Controls Another alternative is to create a Derived Control, by creating a subclass of an existing control. You can then add properties, methods, and events at will, or override some of its methods. You find examples of derived controls in the Callisto framework. Among other useful controls, that framework contains the DynamicTextBlock control, a textblock that does trimming at word boundary. It inherits from ContentControl: public class DynamicTextBlock : ContentControl { // ... } Another example of a derived control can be found in the WinRT XAML Toolkit: the WatermarkTextBox inherits from the native TextBox, and adds a watermark. Extended Controls Using Attached Properties, you can add extra properties to existing instances, e.g. of controls. This allows you to create new controls without defining control subclasses. Again Callisto as well as WinRt XAML Toolkit have examples of such extensions. You’ll remember the TextBoxValidationExtensions from my blog post on input validation. These extensions allow you to add validation logic to a native textbox: <TextBox ext:TextBoxValidationExtensions.Format="NonEmptyNumeric" ext:TextBoxValidationExtensions.InvalidBrush="Salmon" /> You can take the concept of attached properties one step further to create a Behavior, like the ‘select-all-on-focus’ from another previous blog post: <TextBox Text="Eh~ Sexy lady. Op op op op oppan Gangnam Style."> <WinRtBehaviors:Interaction.Behaviors> <local:SelectAllOnFocusBehavior SelectAllOnFocus="True" /> </WinRtBehaviors:Interaction.Behaviors> </TextBox> The attached solution contains the source code for all mentioned alternative controls. Here’s how the corresponding sample page looks like: Code Code Code Here’s the full source code of all the featured controls in this article (o, and a free forward-button style). It was written in Visual Studio 2012 Ultimate, without SP1: U2UConsult.CustomControls.Sample.zip (256.78 kb). Enjoy! Diederik
Building User Controls for Windows 8 Store apps 07 November 2012 Diederik-Krols Metro, WinRT This article describes how to build user controls for XAML-based Windows 8 Store apps. User controls –or composite controls- are the easiest controls that you can roll yourself, since they're defined in plain XAML and come with design-time support in Visual Studio. Basically a user control is just a XAML panel on which you drag and drop a group of controls that belong together. You create a user control only if you want to reuse that XAML panel in multiple places in your app. If you want to reuse the group of controls in more than one app, then you store the user control in a separate library. Typical examples of user controls are a media player button bar (with play, pause and stop buttons), a paging control (with next, previous, goto buttons etc.) and an address panel (with labels, textboxes, and comboboxes for street, number, zip code, city, country, and so on). The sample control for this article will be a new version of my EnhancedSlider. It's a plain vanilla slider that is surrounded with some extra textblocks. The slider comes with support for direct input through a textbox that is enabled by a button. I've been using that group of controls quite often lately, so I decided to package it as a reusable user control. Here's how the original looks like, it started as a non-reusable bunch of controls on the main page of an app: Here’s how to roll your own user control. In a Windows Store app project –or a separate library- add an item of the type ‘User Control’. Visual Studio will create a class for you. It inherits from UserControl and comes with a XAML file and an associated code behind file. You can drag and drop individual controls into the XAML design surface. Here's how the simplified XAML for the enhanced slider looks like: <UserControl x:Class="U2UConsult_UserControls.EnhancedSlider"> <Grid> <TextBlock HorizontalAlignment="Left" /> <StackPanel HorizontalAlignment="Right"> <Button Style="{StaticResource EditRoundButtonStyle}" /> <TextBox /> <TextBlock /> </StackPanel> <Slider Grid.Row="1" /> <TextBlock HorizontalAlignment="Left" Grid.Row="2" /> <TextBlock HorizontalAlignment="Right" Grid.Row="2" /> </Grid> </UserControl> With a little luck the Visual Studio Designer will support you, but don't expect too much from it. In many cases you'll end up with a blank surface - but at least you have IntelliSense in the XAML and an operational properties editor: Your next step is to connect control properties through bindings. Use the ElementName property to define the source of the binding. In the EnhancedSlider, I hooked the Text property of the surrounding text controls to the corresponding properties of the central slider: <Slider x:Name="slider" /> <TextBlock Text="{Binding Minimum, ElementName=slider}" /> <TextBlock Text="{Binding Maximum, ElementName=slider}" /> The XAML is ready. Time to focus on the code behind. We embrace encapsulation, so your user control should behave as a black box to its hosting page or control. That page shouldn't see the individual controls, but only talk to the composite. In code behind, decorate your user control with the appropriate properties. Regular properties don't interact with the binding engine, you have to use Dependency Properties. The EnhancedSlider has the following properties: Minimum, Maximum, Value, Header, and ValueSuffix. ValueSuffix represents the unit measure and is displayed in a separate textblock in the upper right corner of the control. I’ve been trying very hard to use a StringFormatConverter in the textbox displaying the Value. That value should only be formatted when the texbox is disabled (when it looks like a label), not when the user is typing in it. Unfortunately, changing the converter or even the converter parameter programmatically doesn't work because bindings are immutable. So I had to pull the formatting out of the textbox and into an other control as a suffix. It will stil do the job in most scenario's... Anyway, here’s one example of a dependency property (tip: use the propdp code snippet to create these): public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(int), typeof(EnhancedSlider), new PropertyMetadata(0)); public int Minimum { get { return (int)GetValue(MinimumProperty); } set { SetValue(MinimumProperty, value); } } All you need to do now is to bind the subcontrol’s properties to the user control's dependency properties. You may be tempted to set the DataContext of the control to itself (with RelativeSource Self as binding source) to get this done, but then you loose the ability to bind it to something else (e.g. a ViewModel). It's better to give the control a name, and use yet another ElementName in the binding: <UserControl x:Class="U2UConsult_UserControls.EnhancedSlider" x:Name="userControl"> ... <Slider x:Name="slider" Minimum="{Binding Minimum, ElementName=userControl}" Maximum="{Binding Maximum, ElementName=userControl}" Value="{Binding Value, Mode=TwoWay, ElementName=userControl}" /> ... </UserControl> And there we are: we just built our own a reusable composite control. If you want to use the control inside a page or another control, all you need to do is declare the namespace in the hosting container: <Page x:Class="U2UConsult.UserControls.Sample.MainPage" xmlns:uc="using:U2UConsult_UserControls" > ... </Page> You're ready to use the control in the page. Don’t forget to set the bindings with the ViewModel: <uc:EnhancedSlider Value="{Binding Roasted, Mode=TwoWay}" Header="Roasted" Maximum="1000" Foreground="Orange" ValueSuffix=" civilizations" /> Again, don't expect too much help from the Visual Studio Designer. Here's how my main page looks at design time: Fortunately at runtime everything comes through. Here’s a screen shot of the attached sample application: The app contains two projects: a GUI, and a library with the user control. Oh, there’s something you should know about storing user controls in a separate assembly: that assembly may not have dots in its name. I assume that’s a bug that will be fixed very soon. Here’s the code for the sample solution. It was written in Visual Studio 2012 Express: U2UConsult.UserControls.Sample.zip (132.73 kb) Enjoy! Diederik
Using Behaviors in Windows 8 Store Apps 28 October 2012 Diederik-Krols Metro, WinRT This short article explains how to write and use behaviors in Windows 8 Store apps. Behaviors were introduced a couple of yahren ago, in Blend for Silverlight 3. Later on they also found their way to WPF and WP7. Technically, behaviors are nothing but an implementation of Attached Properties. Attached properties allow you to define properties in a parent element, and then let all child elements use their own value for these properties. The classroom examples of attached properties are the Grid.Row and Grid.Column that you can assign to any XAML element. The properties themselves are defined as Dependency Properties in the Grid class, but in your XAML you can assign individual Grid.Row and Grid.Column values to every StackPanel, TextBox, or whatever control. As already mentioned, Behaviors are an implementation of Attached Properties. In a Behavior, the values of the attached properties are used to configure one or more event handlers. The Behavior then hooks these event handlers to the control to which it is attached in XAML. This way you can e.g. create an encapsulated reusable 'AutoComplete' behavior that runs code when the text in a TextBox or ComboBox changes, without creating a separate control, without writing code-behind, and without modifying your viewmodels. On top of that, Behaviors can be combined. If you would like a textbox that does validation, selects all text when it receives the focus, and auto completes user input, then it suffices to create three separate behaviors, and apply these to a regular textbox. Please don’t build your own ValidatingSelectAllOnFocusAutoCompleteTextBox custom control. I hope I just convinced you that behaviors are really useful in the XAML world. Now here’s the bad news: behaviors are not available for Windows 8 Store apps. But don't panic: @LocalJoost resurrected behaviors and made the code available through CodePlex and Nuget. If you want to use behaviors in a Windows 8 Store app, all you need to do is link the WinRTBehaviors assembly to your project. As you know, I actually prefer embedding the source code directly: Let’s create the simplest of all behaviors: one that makes a textbox select all its content when it receives the focus, so you can easily overwrite it. The behavior is configured through a SelectAllOnFocus property, a Boolean. Here’s how it goes: Create a class and let it derive from Behavior<T> where T is the type of Control to which you want the behavior to be attached. In our sample, T is TextBox: public class SelectAllOnFocusBehavior : Behavior<TextBox> { // ... } Define and register the attached dependency properties, and provide the standard Get and Set accessors. These accessors are used to access the property values in code behind: public static readonly DependencyProperty SelectAllOnFocusProperty = DependencyProperty.RegisterAttached ( "SelectAllOnFocus", typeof(bool), typeof(SelectAllOnFocusBehavior), new PropertyMetadata(false) ); public static bool GetSelectAllOnFocus(DependencyObject obj) { return (bool)obj.GetValue(SelectAllOnFocusProperty); } public static void SetSelectAllOnFocus(DependencyObject obj, bool value) { obj.SetValue(SelectAllOnFocusProperty, value); } Override the OnAttached and OnDetaching event handlers. The decorated control is available as a strongly typed AssociatedObject of type T. Make sure you unregister event handlers in OnDetaching to avoid memory leaks: protected override void OnAttached() { base.OnAttached(); if (AssociatedObject != null) { if (GetSelectAllOnFocus(this)) { AssociatedObject.GotFocus += AssociatedObject_GotFocus; } } } protected override void OnDetaching() { if (AssociatedObject != null) { if (GetSelectAllOnFocus(this)) { AssociatedObject.GotFocus -= AssociatedObject_GotFocus; } } base.OnDetaching(); } All scaffolding is in place now. Just implement the core business logic: private void AssociatedObject_GotFocus(object sender, RoutedEventArgs e) { if (AssociatedObject != null) { AssociatedObject.SelectAll(); } } That’s all. For the sake of simplicity, I skipped the OnPropertyChanged handling in this article. You can define a handler as the second parameter of the DependencyProperty.RegisterAttached call. That handler will be called when a dependency property was modified, e.g. through data binding You’ll find some more elaborate examples here. All you now need to do is attach the behavior to a XAML element (a TextBox in this case) and set the properties. Note that you have to define a behavior collection and fill it with behavior instances, like this: <TextBox Text="Joined the Dark Side, I have." FontSize="18" Margin="8"> <WinRtBehaviors:Interaction.Behaviors> <local:SelectAllOnFocusBehavior SelectAllOnFocus="True" /> </WinRtBehaviors:Interaction.Behaviors> </TextBox> The following code does NOT work: <TextBox Text="Joined the Dark Side, I have." FontSize="18" Margin="8" local:SelectAllOnFocusBehavior SelectAllOnFocus="True" /> Here are some screenshots of the attached sample app. The first textbox has SelectAllOnFocus to true, its whole content is selected when it receives the focus: The second textbox has SelectAllOnFocus to false, no text is selected, the caret sits in front of the text: Here’s the code, it was written in Visual Studio 2012 Express: U2UConsult.WinRTBehaviors.Sample.zip (126.55 kb). Enjoy!Diederik
Input Validation in Windows 8 Store apps 09 October 2012 Diederik-Krols Metro, WinRT This article is an introduction to input validation in Windows Store apps. That sounds ambitious. On one hand, some apps really need decent data entry validation. On the other hand, the Store app runtime does not come with Data Annotations, and it does not come with the IDataErrorInfo and INotifyDataErrorInfo interfaces. In an ideal MVVM XAML world we would just define data constraints in the ViewModel, and then let the binding mechanism automatically update the Views. Controls would display their ErrorTemplate and an informative localized message as long as their respective value is invalid. The current Store runtime supports almost nothing of this out of the box, so let's expand the box. The View Let's first test drive some existing controls that allow validation in the View layer. Filip Skakun's WinRT XAML Toolkit on CodePlex has a couple of controls and extensions that faciliate input validation:- The WatermarkTextBox is a TextBox control with a watermark. OK, it doesn't really validate, but you can use the watermark text to provide guidance to the user.- TextBoxValidationExtensions is a set of extensions that allow to specify the format of the requested text input as well as brushes to use to highlight a TextBox with valid or invalid Text.- The NumericUpDown allows you to display and manipulate a numeric value through direct text input, buttons, or cool swipe manipulations. It derives from RangeBase (like the Slider) so it’s impossible to enter an illegal value. Here's how these controls look like in full action (for the moment, just ignore the validation messages at the bottom): If -just like me- you're reluctant to link and deploy giant dll’s with your app, then I have good news. You can easily pluck the relevant classes right out of the source code, and embed these in your app. That's exactly what I did: I do the same with other frameworks and toolkits. After all, if your app only uses RelayCommand and EventAggregator, you're not going to link to the entire MVVMLight *and* Caliburn.Micro, are you ? I know there are pros and cons to this approach, but you get good code samples to learn from, you can tweak the code to better suit your app’s need, and you have the full source code in the project. To a lot of customers, dependencies to large foreign dll’s are a real showstopper. Let's come back to the topic. Since the WaterMarkTextBox inherits from TextBox, the ValidationExtensions also apply to it. Here’s an example of the ‘Age’ textbox from the sample app. It’s mandatory, numeric, and it comes with an explanatory watermark. You can’t specify a whole ErrorTemplate (yet ?), but you can specify background colors for the valid and invalid states. That's a lot better than the TextBox that ships with the runtime: <ctl:WatermarkTextBox Text="{Binding Age, Mode=TwoWay}" WatermarkText="Enter age here. Required numeric field." Extensions:TextBoxValidationExtensions.Format="NonEmptyNumeric" Extensions:TextBoxValidationExtensions.InvalidBrush="#FFCC99" /> My favorite input control of the WinRT Xaml Toolkit is the NumericUpDown. It allows you to enter a value within a range. You can type directly in a TextBox, or press the up and down buttons. But you can also change the value through manipulation: tap on the textbox (or click left mouse button) and slide/drag upward to increase, or downward to decrease. That's a very intuitive and addictive gesture! The control also has a built-in value bar (like in Excel). Here’s how the XAML looks like: <ctl:NumericUpDown Value="0" Minimum="0" Maximum="15" SmallChange="1" ValueFormat="F0" ValueBarVisibility="Collapsed" /> The ViewModel That went easy, right? Let’s switch to second gear, and define data constraints in the ViewModel. For that, we need to resurrect ye olde IDataErrorInfo: namespace System.ComponentModel { public interface IDataErrorInfo { string Error { get; } string this[string columnName] { get; } } } I implemented the interface in the ViewModel in a classic straightforward way: the Error property is populated by concatenating the error messages from the property iterator: public string Error { get { /// Note from the author: there's an opportunity for refactoring here. I know. Really. string error = string.Empty; string property = this["FirstName"]; if (!string.IsNullOrEmpty(property)) { error += property + Environment.NewLine; } property = this["LastName"]; if (!string.IsNullOrEmpty(property)) { error += property + Environment.NewLine; } property = this["Age"]; if (!string.IsNullOrEmpty(property)) { error += property + Environment.NewLine; } return error.Trim(); } } The iterator allows for the appropriate validation messages: public string this[string columnName] { get { switch (columnName) { case "FirstName": if (string.IsNullOrEmpty(firstName)) { return "First Name is required."; } return string.Empty; case "LastName": if (string.IsNullOrEmpty(lastName)) { return "Last Name is required."; } return string.Empty; case "Age": if (string.IsNullOrEmpty(age)) { return "Age is required."; } if (!IsNumeric(age)) { return "Age should be numeric."; } return string.Empty; default: return string.Empty; } } } Here you see e.g. that the Age TextBox spawns another error message than in the previous screen shot: The (re-)calculation of the Error property is triggered by an event handler on PropertyChanged: public MainPageViewModel() { this.PropertyChanged += MainPageViewModel_PropertyChanged; } private void MainPageViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName != "Error" && e.PropertyName != "HasErrors") { this.OnPropertyChanged("Error"); this.OnPropertyChanged("HasErrors"); } } A little voice keeps telling me that it may well be possible to integrate most of the code into BindableBase, to form a DataErrorInfoBase or so. But I decided to ignore that little voice for the moment. I decorated the ViewModel with an HasError property to facilitate data binding: public bool HasErrors { get { return !string.IsNullOrEmpty(this.Error); } } The ‘thank you’ message in the sample app only appears when the whole ViewModel is valid: <TextBlock Text="Thank you very much. Existence as you know it, is over now." Visibility="{Binding HasErrors, Converter={StaticResource ReverseBooleanToVisibilityConverter}}"/> Here’s how it looks like: Conclusion Frankly, I just got closer to WPF validation than I expected and with a lot less code than I expected. This is a relief. I now strongly believe we will have enterprise level input validation in a very near future. The Code Here's the code for the sample app. It was written with Visual Studio 2012 Express: U2UConsult.Win8.TextBoxSample.zip (145.85 kb) Enjoy! Diederik
Enhancing the Win8 Slider experience 27 September 2012 Diederik-Krols Metro, WinRT This article describes a way to enhance the user friendliness of a standard slider control in a Windows 8 Store App. Problem In a touch oriented application, we often allow -or force- the user to set the value for an integer or an enumeration through a slider control. In most cases this is more comfortable and less error prone than working with the soft keyboard. Unfortunately it’s not always ideal: if the range of values becomes too huge, or the slider becomes too narrow (e.g. when in portrait or snapped mode), then it becomes too difficult for the user to position the slider at the correct value. In this scenario, a textbox is a much more appropriate input control. This article proposes a UX design –and implementation- that offers the best of both worlds, and lets the end user decide on it. Proposed solution A slider control never walks alone: it’s always surrounded by controls that display its topic, its minimum and maximum values, and its current value, like this: So there’s always a label that displays the current value. Wouldn’t it be nice to replace that simply it by a textbox? This gives the end user direct access to the desired value: Now this may look confusing, so by default we allow only input through the slider and display the current value as a label. Next to the label, we add a small button to activate the ‘direct input mode’, like this: When pressed, the button activates the direct input mode. The label transforms into a textbox, and if there's no keyboard attached, we pop up the soft keyboard (preferably a numeric one): When the user leaves the textbox by tapping somewhere else on the screen, the slider is updated - after validation of the input. This article ignores the validation part. Implementation Here's how the sample solution was implemented. I didn’t want to bring too much extra controls in the equation, so the current value is *always* displayed in the same textbox. In ‘slider input’ mode this textbox is simply disabled. It’s the style that makes it look like a textblock – default theme foreground, no border. Here's the relevant modification to the standard style: <VisualState x:Name="Disabled"> <Storyboard> <!-- ... --> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentElement"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ApplicationForegroundThemeBrush }" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderThickness" Storyboard.TargetName="BorderElement"> <DiscreteObjectKeyFrame KeyTime="0" Value="0" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> The look-and-feel of the small button is also defined by a style, a copy of the standard AppBarButtonStyle - just a bit smaller, and without a label. All styles are stored in a resource dictionary customstyles.xaml. The textbox’s text is bound to the sliders value. It also favors the numeric keyboard: <TextBox x:Name="TheTextBox" Text="{Binding Value, Mode=TwoWay, ElementName=TheSlider}" InputScope="Number" IsEnabled="False" LostFocus="TheTextBox_LostFocus" KeyUp="TheTextBox_KeyUp" TextAlignment="Right" Style="{StaticResource LabelTextBoxStyle}" /> The button’s only job is to enable the textbox and give focus to it. In most cases -I've noticed some buggy behavior here- that will pop up the numeric soft keyboard immediately: private void SliderButton_Click(object sender, RoutedEventArgs e) { this.TheTextBox.IsEnabled = true; this.TheTextBox.Focus(FocusState.Programmatic); } The textbox updates the current value when it loses focus, by updating the binding. We don't have to write code for that: it's the default behavior in Modern UI. However we still need to disable the textbox: private void TheTextBox_LostFocus(object sender, RoutedEventArgs e) { this.TheTextBox.IsEnabled = false; } Although it’s not a Modern UI standard, I still expect the value to be committed by pressing the Enter key, so here’s the routine to do that. Remember, it’s optional: private void TheTextBox_KeyUp(object sender, KeyRoutedEventArgs e) { if (e.Key == Windows.System.VirtualKey.Enter) { this.TheTextBox.IsEnabled = false; } } I was also thinking of implementing some undo logic behind the Escape key, but then discovered that there is no Escape key on the soft keyboard. Sample Here’s the source code of the sample project. It was built with the free Visual Studio 2012 Express Edition: U2UConsult.Win8.ExtendedSliderSample.zip (205.01 kb) Enjoy!
A C#/XAML FlipView Context Indicator for Windows 8 24 August 2012 Diederik-Krols Metro, WinRT This article presents a FlipView context indicator control for Windows 8 UI Style apps. FlipView is a Windows 8 items control that displays one item at a time. It allows traversing its collection of items through a horizontal flick gesture. There are some limitations in its usage. In an app, the maximum size of a flipview is the size of the page. If you make the FlipView wider than its container, you're just going to confuse your user (and probably also the runtime): does a horizontal flick triggers scrolling, or are we moving to the next (or previous) page ? This is one of the reasons why I personally prefer the single page GridView style over a FlipView. If you decide to stick to the FlipView, you're not only limited in the size of the data template. You'll also bump into another problem: how are you going to make it clear to your user that he can navigate to other items ? Well, the Guidelines for FlipView Controls prescribe the usage of a context indicator, but they don't specify how it should look like. The official FlipView Control Sample only has a HTML/JS version. There used to be XAML/C# sample for the Release Preview -my control templates are based on it. But that sample app seems to have been lost in RTM translation. So the best functional example of a FlipView Context Indicator can be found in the store: Here's how I built my control. Its design is very simple and so is the implementation. [Warning:spoiler in next statement] It is just a templated ListBox that is bound to the ItemsSource and SelectedItem of its associated FlipView. In Visual Studio, I created a new project of the type 'Windows Store Apps Class Library' and added a new 'Templated Control'. I made that control inherit from ListBox. In the Generic.xaml resource dictionary, I added the two styles from the (now disappeared) FlipView Control Sample: a style for the ListBox itself (just a rectangle), and a style for the ListBoxItem (another rectangle). That's a lot of XAML to just define two rectangles. I gave the control a dependency property -called FlipView- of the type ... FlipView: public static readonly DependencyProperty FlipviewProperty = DependencyProperty.Register("Flipview", typeof(FlipView), typeof(FlipViewIndicator), new PropertyMetadata(null, FlipView_Changed)); public FlipView Flipview { get { return (FlipView)GetValue(FlipviewProperty); } set { SetValue(FlipviewProperty, value); } } When the property is assigned or changed -e.g. through XAML- I set the ItemsSource of the context indicator to the ItemsSource of the FlipView. I also create a two-way binding to the SelectedItem. private static void FlipView_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { FlipViewIndicator that = d as FlipViewIndicator; FlipView flip = (e.NewValue as FlipView); that.ItemsSource = flip.ItemsSource; Binding binding = new Binding(); binding.Mode = BindingMode.TwoWay; binding.Source = flip; binding.Path = new PropertyPath("SelectedItem"); that.SetBinding(FlipViewIndicator.SelectedItemProperty, binding); } This way, the context indicator can be used to navigate through the items collection - just by tapping one of the small rectangles. That's why I made these rectangles wider than the ones in the Store. Here's how it looks like in the attached sample app. For the record: the flipview context indicator is the small bar in the lower left corner: This app is just a FlipView and Context Indicator on a list of Belgian Super Heroes. The description is in Dutch, which may look weird if you don't know the language. But I assure you: if you translate them in English, they will still look weird. The bottom line is that Belgian Super Heroes evolved from men in mini skirts in the 1970s, to men in fluorescent leather catsuits in the 2010s: O, I almost forgot: here's how to add the control on a page, and link it to a FlipView: <FlipView x:Name="heroFlipView" ItemsSource="{Binding Heroes}"> ... </FlipView> <controls:FlipViewIndicator Flipview="{Binding ElementName=heroFlipView}" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="8" /> That's all there is. Here's the code of the control and sample app. It was written in Visual Studio 2012 Ultimate, for the Windows 8 RTM: U2UConsult.Win8.FlipViewIndicatorSample.zip (587.48 kb) Update: This is the very first version of the FlipViewIndicator. A newer version of this control is embedded in Tim Heuer's Callisto framework, were it will continue its life cycle. Enjoy!
Transforming SVG graphics to XAML Metro Icons 27 July 2012 Diederik-Krols Metro, WinRT This short article shows how to pimp your Windows 8 Metro apps with native XAML icons that are created from W3C Scalable Vector Graphics. SVG graphics are XML documents, and hence should be easily translatable into an other XML schema, such as XPS (the technology formerly known as ... Metro). Just like Metro XAML, XPS is a subset of XAML. Unfortunately its full object model is not implemented in Silverlight or Metro. In Windows, since the-OS-that-should-not-be-named, XPS is also used as print spooler format. This means that you don't even have to write an XSLT transformation to translate SVG to XAML: let the printer driver do the heavy lifting. Here's how it goes. Find a graphic Grab a designer, or navigate to your favorite source of royalty free images - such as The Noun Project. Download the resource, as SVG: Transform it to XPS Open the SVG file in your browser, and print to an XPS file through the Microsoft XPS Document Writer: Find XAML Payload The XPS document is actually a ZIP-file. So just add .zip to its name: The XPS document contains page layout, headers, footers, embedded fonts, and so on. It also contains all left-overs from the tools that created the SVG. Not all SGV graphics are lean and mean on the inside. Some of the XML reminds me to the tons of obsolete HTML that used to be generated by Microsoft FrontPage. Anyway, you just have to find the place where the payload -the graphic- is hidden. It's most probably part of the first page of the first document, so \Documents\1\Pages\1.fpage would be the first place to look: Bingo! Here's the XAML that we're looking for - the one with all the PATH elements: Clean up XAML If you just copy/paste that bunch of Canvas elements from the FixedPage into a Grid in a Metro app, the Visual Studio XAML Designer may already recognize it and start displaying the icon. The very first Canvas on the page is probably the page boundary, so you may delete it. The Glyphs elements can also be removed. The now remaining Path elements are most probably the translated SVG. All you need to do is throw these in a Viewbox, like this Planet SVG: <Viewbox> <Grid VerticalAlignment="Center" HorizontalAlignment="Center"> <Path Data="F 1 M 46.857,18.462 C 29.654,18.462 15.658,32.457 15.658,49.66 15.658,66.863 29.654,80.858 46.857,80.858 64.06,80.858 78.056,66.863 78.056,49.66 78.056,32.457 64.06,18.462 46.857,18.462 Z M 46.857,74.819 C 32.983,74.819 21.697,63.534 21.697,49.66 21.697,35.787 32.984,24.5 46.857,24.5 60.73,24.5 72.018,35.787 72.018,49.66 72.018,63.534 60.73,74.819 46.857,74.819 Z" Fill="Gold" /> <Path Data="F 1 M 80.782,42.622 C 81.339,44.794 81.26,47.228 81.091,49.701 89.277,54.928 90.683,58.083 90.625,58.6 90.613,58.619 89.058,60.471 80.095,59.816 75.472,59.477 69.955,58.53 64.001,57.09 64.001,57.109 64.003,57.125 64.003,57.144 64.003,59.188 63.462,61.105 62.524,62.772 68.841,64.302 74.719,65.31 79.666,65.673 89.301,66.377 94.692,64.71 96.152,60.574 98.181,54.833 90.748,48.331 80.782,42.622 Z" Fill="Gold" /> <Path Data="F 1 M 43.045,50.566 C 33.593,46.987 25.045,42.873 18.653,38.804 10.379,33.539 8.963,30.361 9.021,29.84 9.033,29.821 10.344,27.84 19.296,28.492 20.495,26.281 22.416,24.499 24.4,23.092 23.142,22.943 21.311,22.865 19.983,22.768 10.347,22.063 4.953,23.73 3.493,27.866 1.934,32.281 5.624,37.325 14.774,43.291 21.589,47.733 30.796,52.21 41.022,56.078 41.211,54.04 41.932,52.158 43.045,50.566 Z" Fill="Gold" /> <Path Data="M 44.509,57.291 C 44.509,52.9832 48.0012,49.491 52.309,49.491 L 52.309,49.491 C 56.6168,49.491 60.109,52.9832 60.109,57.291 L 60.109,57.291 C 60.109,61.5988 56.6168,65.091 52.309,65.091 L 52.309,65.091 C 48.0012,65.091 44.509,61.5988 44.509,57.291 Z" Fill="Goldenrod" /> </Grid> </Viewbox> Oh wait, there's an easier way If that's too cumbersome, you can also upload your SVG to Graphspe's on-line SVG to XAML Converter. That's what I did with Andrew Forrester's awesome Death Star graphic, also from the Noun Project: It directly returns the Canvas with the Path. Just drop it in a ViewBox: <Viewbox> <Path Fill="#FF000000" Data="F1 M50.844,1.04L50.844,1.04 50.844,1.04C50.741,1.039 50.64,1.03 50.54,1.023 50.35,1.009 50.159,0.997 49.965,0.997 22.863,0.997 0.813999999999993,23.045 0.813999999999993,50.146 0.813999999999993,77.248 22.863,99.295 49.965,99.295 50.156,99.295 50.344,99.283 50.531,99.27 50.633,99.263 50.735,99.254 50.838,99.253 50.84,99.253 50.842,99.253 50.845,99.253 77.461,98.778 99.115,76.748 99.115,50.146 99.115,23.54 77.461,1.511 50.844,1.04z M58.051,94.223C58.466,93.766,58.868,93.299,59.271,92.833L59.538,92.525C59.749,92.283 59.959,92.042 60.163,91.795 60.63,91.23 61.077,90.65 61.523,90.071L61.785,89.737C61.94,89.542 62.094,89.346 62.242,89.147 62.835,88.349 63.429,87.507 64.01,86.643L64.176,86.406C64.77,85.516 65.369,84.565 65.957,83.578 66.073,83.383 66.184,83.184 66.293,82.986L66.509,82.603C66.902,81.916 67.258,81.293 67.593,80.659 67.732,80.394 67.864,80.129 67.996,79.861L68.192,79.468C68.493,78.869 68.793,78.27 69.075,77.663 69.236,77.314 69.389,76.965 69.542,76.615L69.65,76.368C69.908,75.779 70.165,75.189 70.406,74.593 70.578,74.166 70.741,73.737 70.904,73.305 71.153,72.648 71.372,72.055 71.578,71.456 71.738,70.994 71.891,70.528 72.041,70.061 72.233,69.462 72.416,68.862 72.591,68.256 72.728,67.784 72.861,67.313 72.987,66.837 73.149,66.225 73.3,65.608 73.444,64.991L73.474,64.859C73.575,64.4289999999999 73.674,64.0009999999999 73.765,63.569 73.898,62.934 74.016,62.297 74.13,61.657L74.192,61.317C74.255,60.965 74.32,60.6139999999999 74.376,60.261 74.477,59.617 74.559,58.971 74.641,58.323L74.7,57.85C74.74,57.539 74.781,57.23 74.813,56.918 74.891,56.172 74.945,55.419 74.997,54.667L75.028,54.261C75.049,54.023 75.068,53.784 75.081,53.545 75.143,52.348 75.173,51.236 75.173,50.146 75.173,48.35 75.088,46.469 74.921,44.544 75.592,44.415 76.253,44.229 76.923,43.985 82.302,42.016 85.113,36.683 83.919,30.715 82.993,26.089 79.793,21.875 75.356,19.444 72.966,18.133 70.406,17.441 67.954,17.441 67.457,17.441 66.953,17.472 66.429,17.537 66.207,17.151 65.983,16.767 65.752,16.387L65.313,15.678C64.986,15.15 64.653,14.627 64.31,14.11 64.14,13.854 63.97,13.599 63.797,13.346 63.443,12.826 63.08,12.311 62.711,11.801L62.248,11.161C61.722,10.451,61.185,9.751,60.63,9.063L60.543,8.959C59.98,8.267 59.456,7.649 58.922,7.04 58.922,7.04 58.154,6.184 58.051,6.07 79.202,9.94 94.814,28.407 94.814,50.146 94.814,71.882 79.201,90.349 58.051,94.223z M70.433,23.951C70.373,24.042 70.322,24.138 70.265,24.231 70.05,24.581 69.853,24.94 69.672,25.309 69.613,25.428 69.553,25.546 69.498,25.667 69.29,26.125 69.102,26.592 68.946,27.074 68.944,27.08 68.94,27.086 68.938,27.093 68.846,27.075 68.752,27.072 68.66,27.059 68.476,27.029 68.296,27.011 68.117,27.007 68.104,27.007 68.093,27.004 68.08,27.004 68.073,27.004 68.068,27.006 68.061,27.006 67.248,26.997 66.506,27.244 65.908,27.695 65.88,27.716 65.853,27.738 65.827,27.76 65.642,27.907 65.469,28.068 65.317,28.253 64.6489999999999,29.065 64.3939999999999,30.177 64.6169999999999,31.307 64.671,31.574 64.7499999999999,31.833 64.8489999999999,32.084 64.8819999999999,32.168 64.9289999999999,32.245 64.9669999999999,32.326 65.0429999999999,32.489 65.1159999999999,32.651 65.2089999999999,32.805 65.2649999999999,32.897 65.3329999999999,32.979 65.395,33.067 65.488,33.199 65.578,33.333 65.682,33.456 65.756,33.543 65.84,33.62 65.919,33.702 66.026,33.812 66.133,33.924 66.25,34.024 66.339,34.101 66.436,34.167 66.529,34.237 66.6499999999999,34.327 66.7689999999999,34.416 66.896,34.495 66.998,34.558 67.104,34.61 67.209,34.665 67.34,34.733 67.471,34.801 67.606,34.857 67.717,34.903 67.831,34.939 67.945,34.976 68.084,35.021 68.222,35.063 68.364,35.096 68.482,35.122 68.6,35.14 68.72,35.157 68.805,35.169 68.887,35.194 68.973,35.2 69.013,35.324 69.064,35.443 69.108,35.565 69.151,35.684 69.194,35.802 69.24,35.919 69.39,36.303 69.553,36.682 69.738,37.048 69.745,37.061 69.751,37.075 69.757,37.088 69.95,37.467 70.167,37.832 70.395,38.19 70.458,38.29 70.525,38.387 70.59,38.485 70.78,38.767 70.982,39.041 71.194,39.308 71.253,39.382 71.307,39.458 71.368,39.531 71.637,39.855 71.92,40.165 72.219,40.462 72.287,40.53 72.361,40.594 72.431,40.661 72.675,40.894 72.929,41.118 73.191,41.332 73.286,41.409 73.379,41.485 73.475,41.56 73.54,41.61 73.601,41.665 73.667,41.715 73.574,41.726 73.481,41.724 73.388,41.732 73.381,41.733 73.373,41.733 73.367,41.733 73.119,41.754 72.87,41.778 72.622,41.778 72.029,41.778 71.439,41.717 70.853,41.625 65.531,40.788 60.681,36.31 59.601,30.913 59.029,28.053 59.606,25.389 61.226,23.413 61.947,22.534 62.845,21.847 63.868,21.349 64.612,20.987 65.424,20.732 66.289,20.588 66.292,20.588 66.295,20.588 66.298,20.587 66.832,20.499 67.383,20.443 67.954,20.443 69.455,20.443 71.022,20.778 72.554,21.42 72.493,21.476 72.444,21.542 72.384,21.599 72.089,21.882 71.809,22.178 71.543,22.485 71.468,22.572 71.389,22.655 71.315,22.744 70.998,23.129 70.703,23.532 70.433,23.951z M70.87,31.674C70.871,31.75 70.863,31.822 70.854,31.895 70.851,31.93 70.85,31.965 70.844,31.999 70.807,32.206 70.731,32.394 70.614,32.557 70.387,32.873 70.017,33.081 69.57,33.142 69.568,33.142 69.567,33.143 69.565,33.143 69.563,33.143 69.561,33.143 69.559,33.143 69.455,33.158 69.359,33.184 69.324,33.213 68.086,33.213 66.829,32.159 66.579,30.915 66.471,30.37 66.571,29.875 66.862,29.521 67.136,29.187 67.569,29.002 68.08,29.002 68.156,29.002 68.232,29.018 68.309,29.025 68.571,29.066 68.858,29.152 69.175,29.306 69.175,29.306 69.176,29.306 69.176,29.307 69.807,29.615 70.315,30.113 70.605,30.676 70.614,30.695 70.625,30.712 70.633,30.731 70.722,30.914 70.789,31.102 70.829,31.294 70.829,31.296 70.83,31.299 70.831,31.302 70.856,31.43 70.867,31.554 70.87,31.674z" /> </Viewbox> The result Just look at these shiny tiles: Enjoy!
The taming of the Metro GridView 10 July 2012 Diederik-Krols Metro, WinRT This article describes how to restyle the Metro GridView to host a single page app like the sample Weather and Finance apps. I'll show you how to get rid of the default disco effects of this control - like the swiping behavior and the pressed animation. For this article, I started with my own lightweight version of the weather app, but I got bored very soon. So I upgraded the app to a tribute to the iconic rock band CPeX, with some pictures, some overflowing RichTextBox controls with lyrics, and WebView controls revealing the band's web site and wikipedia page; there's even a YouTube video in it: The GridView is a good candidate to host a single page Metro app: out-of-the-box it's layed out horizontally, and it supports panning through differently sized content pages. It was designed for selecting and moving items, so its default look-and-feel is way too busy. But Visual Studio 11 Release Candidate is the ideal environment to tame it. Visual Studio is now sharing some of its designers with Expression Blend. If you want to restyle a control on a page, all you have to do is right click in the XAML designer, and select "edit template" and "edit a copy". The control template will be pulled out of generic.xaml and applied to the control, after you decided where to save the style: That's exactly what I did to create new copies of the templates for the GridView and GridViewItem control. Here's the list of modifications to the default GridView style: I changed the IsSwipeEnabled property to false: <Setter Property="IsSwipeEnabled" Value="False" /> I added a default value for the SelectionMode property: <Setter Property="SelectionMode" Value="None" /> I changed the ItemsPanelTemplate to a horizontal StackPanel: <Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" /> </ItemsPanelTemplate> </Setter.Value> </Setter> Finally, I made the outer ScrollViewer snap to the GridViewItems: <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="GridView"> <Border ... > <ScrollViewer x:Name="ScrollViewer" ... HorizontalSnapPointsType="Optional"> <ItemsPresenter .../> </ScrollViewer> </Border> </ControlTemplate> </Setter.Value> </Setter> After a swipe, the GridView pans smoothly to the beginning of the next (or previous) page. Heck, even the Weather and Finance apps don't do this: Here's the list of modifications to the default GridViewItem style: I changed the margin, so that all pages touch the borders and each other: <Setter Property="Margin" Value="-4 -4 -4 0" /> I cleared the animations for the following visual states: PointerOver, Pressed, PointerOverPressed, and Focused: <VisualState x:Name="PointerOver"> <Storyboard /> </VisualState> When I was happy with the result, I moved the two styles to a separate resource dictionary: I added a reference to it in the app.xaml: <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Common/StandardStyles.xaml" /> <ResourceDictionary Source="Common/ZenStyles.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> Here's how the main GridView uses the styles: <GridView Style="{StaticResource ZenGridViewStyle}" ItemContainerStyle="{StaticResource ZenGridViewItemStyle}"> ... </GridView> Here's the sample project. It was developed with Visual Studio 11 Ultimate RC for the Windows 8 Release Preview: U2UConsult.Metro.GridViewZen.zip (1.26 mb) Enjoy!
Modal Dialogs in Windows 8 Metro 13 June 2012 Diederik-Krols Metro, WinRT This article describes how to create modal dialogs in a Windows 8 MVVM Metro-style app. Here's the use case: a main page opens a dialog and provides it with some information. The dialog is displayed in the center of the screen, and collects some information. As long as the dialog is open, the main page is inaccessible by the user interface. When the dialog is closed, the main page reads the result from the dialog, and continues processing. The Sample Here are some screenshots of the attached solution. You see the main page with a shop button to open the dialog, the dialog that allows you to select multiple items from a catalog and then checkout, and finally the main page displaying the purchased items after the dialog was closed: The Dialog The dialog is implemented as a regular Page. When it's displayed, it will occupy the whole screen to prevent access to the underlying main page: public CatalogDialog() { this.InitializeComponent(); var bounds = Window.Current.Bounds; this.RootPanel.Width = bounds.Width; this.RootPanel.Height = bounds.Height; } The dialog look-and-feel is created by using a semi-transparent background under a white border with a wide margin around the core content: <Page> <Grid x:Name="RootPanel" Opacity=".75" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <Border Background="White" Margin="120"> <Grid Background="Blue" Margin="8"> <GridView x:Name="CatalogGridView" ItemsSource="{Binding Cars}" SelectionMode="Multiple" SelectionChanged="CatalogGridView_SelectionChanged"> </GridView> <Button Content="Checkout" Click="CloseButton_Click"> </Button> </Grid> </Border> </Grid> </Page> The dialog notifies its end-of-life by raising a CloseRequested event, in the click event handler of the checkout-button. This is the kind of code that you would factor out into a Dialog base class: public event EventHandler CloseRequested; private void CloseButton_Click(object sender, RoutedEventArgs e) { if (this.CloseRequested != null) { this.CloseRequested(this, EventArgs.Empty); } } The viewmodel always reflects the dialog's state. Binding to the SelectedItems property is not possible, so we have to refrain from hard-core MVVM. We update the viewmodel each time the selection in the catalog gridview is changed: private void CatalogGridView_SelectionChanged(object sender, SelectionChangedEventArgs e) { foreach (var item in e.AddedItems) { PinkFerrari pf = item as PinkFerrari; pf.IsSelected = true; } foreach (var item in e.RemovedItems) { PinkFerrari pf = item as PinkFerrari; pf.IsSelected = false; } } The Main Page The main page has a button that opens the dialog, and a listview to display the result: <Page> <Page.DataContext> <local:MainPageViewModel /> </Page.DataContext> <Grid> <Button Content="Shop" Command="{Binding OpenDialogCommand}"> </Button> <ListView ItemsSource="{Binding ShoppingList}"> </ListView> </Grid> </Page> When the shop-button is clicked, a command is fired in the main page's viewmodel. That viewmodel creates a new instance of the dialog view. MVVM tifosi would prefer to use some kind of ViewLocator here, instead of a hard reference to the view's class. The dialog view is associated with a viewmodel - that's how the two viewmodels can exchange information. An event handler is hooked onto the CloseRequested event. Then the dialog view is wrapped in a Popup element, which is then opened: private void OpenDialog_Executed() { this.catalog = new CatalogViewModel(); CatalogDialog dialog = new CatalogDialog(); dialog.DataContext = this.catalog; dialog.CloseRequested += Dialog_CloseRequested; this.catalogPopup = new Popup(); this.catalogPopup.Child = dialog; this.catalogPopup.IsOpen = true; } When the dialog closes, the main page's viewmodel is updated: private void Dialog_CloseRequested(object sender, EventArgs e) { this.catalogPopup.IsOpen = false; this.shoppingList.Clear(); var query = from f in this.catalog.Cars where f.IsSelected select f; foreach (var item in query) { this.shoppingList.Add(item); } } That's all there is... The Result Last week our CEO used this app to order the new company cars. Here's a picture of our parking area this morning: The Code Here's the full source code of the sample solution. Is was build with Visual Studio 2012 Ultimate RC for the Windows 8 Release Preview: U2UConsult.Metro.DialogSample.zip (409,68 kb) Enjoy !