Blog

posts

'Twelve ways to make your apps suck less' presentation

0 Comments
By Fons Sonnemans, 21-10-2014

The Dutch and Belgium Windows and Windows Phone developers have organized the Lowlands Windows Phone Developer Day event on 18 October 2014. I have presented this 'Twelve ways to make your apps suck less' presentation. With this blog I like to share the slides and demo projects (download button below).

Twelve ways to make your apps suck less from Fons Sonnemans

I would like to thank Joost van Schaik, Nico Vermeir and Glenn Versweyveld for organizing this wonderful event.

Windows 8 XAML Tips - Trigger Behaviors

0 Comments
By Fons Sonnemans, 2-7-2014

I use Behaviors in my XAML apps all the time. I have already written a few blog post about this subject. In Silverlight and WPF there was a clear distinction between Actions, Triggers and Behaviors. Triggers are used to invoke an Action. You can use the EventTrigger, StoryBoardCompleteTrigger, KeyTrigger, TimerTrigger, PropertyChangedTrigger, DataTrigger and DataStoreTrigger. And you can easily write your own by using the Trigger 'New Item' template in Blend.

In the Windows 8.1 'Behavior SDK' the Triggers are replaced by Trigger Behaviors. You only get the DataTriggerBehavior and EventTriggerBehavior but you can write your own. With this blog post I will try to explain how to do this. I will use a TimerTriggerBehavior and a SwipeTriggerBehavior which you can use to execute actions when you active a swipe gesture on a UIElement.

TimerTriggerBehavior

Before I can explain my TimerTriggerBehavior I first have to re-introduce my Behavior<T> class which I use as a base class for all my behaviors.

public abstract class Behavior<T> : DependencyObject, IBehavior 
    where T : DependencyObject {

    [EditorBrowsable(EditorBrowsableState.Never)]
    public T AssociatedObject { get; set; }

    protected virtual void OnAttached() {
    }

    protected virtual void OnDetaching() {
    }

    public void Attach(DependencyObject associatedObject) {
        if (associatedObject == this.AssociatedObject || 
            DesignMode.DesignModeEnabled) {
            return;
        }

        this.AssociatedObject = (T)associatedObject;
        OnAttached();
    }

    public void Detach() {
        if (!DesignMode.DesignModeEnabled) {
            OnDetaching();
        }
    }

    DependencyObject IBehavior.AssociatedObject {
        get { return this.AssociatedObject; }
    }
}

The TimerTriggerBehavior class is derives from this Behavior<T> class and contains DispatcherTimer. It has a MilliSecondsPerTick and IsEnabled properties. The MilliSecondsPerTick property is used to set the Interval of the Property. The IsEnabled property is used to start and stop the timer. It is an DependencyProperty so you can DataBind it. In Tick event is subscribed in the OnAttached() method and unsubscribed in the OnDetached() method. The Timer_Tick() event handler calls the Execute() method which invokes all triggers. The class also contains an Actions DependencyProperty and a Execute() method and the class is decorated with the ContentPropertyAttribute. This will be used by Blend for Visual Studio to allow Drag&Drop of Actions onto the Behavior.

[ContentProperty(Name = "Actions")]
public class TimerTriggerBehavior : Behavior<DependencyObject> {

    private DispatcherTimer _timer = new DispatcherTimer();

    private int _millisecondPerTick = 1000;

    public int MilliSecondsPerTick {
        get { return _millisecondPerTick; }
        set {
            _millisecondPerTick = value;
            _timer.Interval = TimeSpan.FromMilliseconds(_millisecondPerTick);
        }
    }

    #region Actions Dependency Property

    /// <summary> 
    /// Actions collection 
    /// </summary> 
    public ActionCollection Actions {
        get {
            var actions = (ActionCollection)base.GetValue(ActionsProperty);
            if (actions == null) {
                actions = new ActionCollection();
                base.SetValue(ActionsProperty, actions);
            }
            return actions;
        }
    }

    /// <summary> 
    /// Backing storage for Actions collection 
    /// </summary> 
    public static readonly DependencyProperty ActionsProperty =
        DependencyProperty.Register("Actions",
                                    typeof(ActionCollection),
                                    typeof(SwipeTriggerBehavior),
                                    new PropertyMetadata(null));

    #endregion Actions Dependency Property

    protected void Execute(object sender, object parameter) {
        Interaction.ExecuteActions(sender, this.Actions, parameter);
    }

    protected override void OnAttached() {
        base.OnAttached();
        _timer.Tick += timer_Tick;
        if (this.IsEnabled) {
            _timer.Start();
        }
    }

    private void timer_Tick(object sender, object e) {
        this.Execute(this, null);
    }

    protected override void OnDetaching() {
        base.OnDetaching();
        _timer.Stop();
        _timer.Tick -= timer_Tick;
    }

    #region IsEnabled Dependency Property

    /// <summary> 
    /// Get or Sets the IsEnabled dependency property.  
    /// </summary> 
    public bool IsEnabled {
        get { return (bool)GetValue(IsEnabledProperty); }
        set { SetValue(IsEnabledProperty, value); }
    }

    /// <summary> 
    /// Identifies the IsEnabled dependency property. 
    /// This enables animation, styling, binding, etc...
    /// </summary> 
    public static readonly DependencyProperty IsEnabledProperty =
        DependencyProperty.Register("IsEnabled",
                typeof(bool),
                typeof(TimerTriggerBehavior),
                new PropertyMetadata(true, OnIsEnabledPropertyChanged));

    /// <summary>
    /// IsEnabled changed handler. 
    /// </summary>
    /// <param name="d">TimerTriggerBehavior that changed its IsEnabled.</param>
    /// <param name="e">DependencyPropertyChangedEventArgs.</param> 
    private static void OnIsEnabledPropertyChanged(DependencyObject d, 
                            DependencyPropertyChangedEventArgs e) {
        var source = d as TimerTriggerBehavior;
        if (source != null) {
            var value = (bool)e.NewValue;
            if (value) {
                source._timer.Start();
            } else {
                source._timer.Stop();
            }
        }
    }

    #endregion IsEnabled Dependency Property

SwipeTriggerBehavior

The SwipeTriggerBehavior has a Direction property which you can set the swipe direction which will trigger the Actions. The ManipulationCompleted event on the UIElement is used to detect the swipe gesture. The ManipulationCompletedRoutedEventArgs.Velocities.Linear.X and Y are used to check the direction. I use this Between() extension method to check it is between 0.3 and 100. These values work for me but maybe not for you. Maybe I should make these flexible using properties (next version).

[ContentProperty(Name = "Actions")]
public class SwipeTriggerBehavior : Behavior<UIElement> {

    /// <summary>
    /// Get/Sets the direction of the Swipe gesture 
    /// </summary>
    public SwipeDirection Direction { get; set; }

    #region Actions Dependency Property

    /// <summary> 
    /// Actions collection 
    /// </summary> 
    public ActionCollection Actions {
        get {
            var actions = (ActionCollection)base.GetValue(ActionsProperty);
            if (actions == null) {
                actions = new ActionCollection();
                base.SetValue(ActionsProperty, actions);
            }
            return actions;
        }
    }

    /// <summary> 
    /// Backing storage for Actions collection 
    /// </summary> 
    public static readonly DependencyProperty ActionsProperty =
        DependencyProperty.Register("Actions",
                                    typeof(ActionCollection),
                                    typeof(SwipeTriggerBehavior),
                                    new PropertyMetadata(null));

    #endregion Actions Dependency Property

    protected void Execute(object sender, object parameter) {
        Interaction.ExecuteActions(sender, this.Actions, parameter);
    }

    protected override void OnAttached() {
        base.OnAttached();

        this.AssociatedObject.ManipulationMode = 
            this.AssociatedObject.ManipulationMode | 
            ManipulationModes.TranslateX | 
            ManipulationModes.TranslateY;

        this.AssociatedObject.ManipulationCompleted += OnManipulationCompleted;
    }

    protected override void OnDetaching() {
        base.OnDetaching();
        this.AssociatedObject.ManipulationCompleted -= OnManipulationCompleted;
    }

    private void OnManipulationCompleted(object sender, 
                                        ManipulationCompletedRoutedEventArgs e) {

        bool isRight = e.Velocities.Linear.X.Between(0.3, 100);
        bool isLeft = e.Velocities.Linear.X.Between(-100, -0.3);

        bool isUp = e.Velocities.Linear.Y.Between(-100, -0.3);
        bool isDown = e.Velocities.Linear.Y.Between(0.3, 100);

        switch (this.Direction) {
            case SwipeDirection.Left:
                if (isLeft && !(isUp || isDown)) {
                    this.Execute(this.AssociatedObject, null);
                }
                break;
            case SwipeDirection.Right:
                if (isRight && !(isUp || isDown)) {
                    this.Execute(this.AssociatedObject, null);
                }
                break;
            case SwipeDirection.Up:
                if (isUp && !(isRight || isLeft)) {
                    this.Execute(this.AssociatedObject, null);
                }
                break;
            case SwipeDirection.Down:
                if (isDown && !(isRight || isLeft)) {
                    this.Execute(this.AssociatedObject, null);
                }
                break;
            case SwipeDirection.LeftDown:
                if (isLeft && isDown) {
                    this.Execute(this.AssociatedObject, null);
                }
                break;
            case SwipeDirection.LeftUp:
                if (isLeft && isUp) {
                    this.Execute(this.AssociatedObject, null);
                }
                break;
            case SwipeDirection.RightDown:
                if (isRight && isDown) {
                    this.Execute(this.AssociatedObject, null);
                }
                break;
            case SwipeDirection.RightUp:
                if (isRight && isUp) {
                    this.Execute(this.AssociatedObject, null);
                }
                break;
            default:
                break;
        }
    }
}

public enum SwipeDirection {
    Left,
    Right,
    Up,
    Down,
    LeftDown,
    LeftUp,
    RightDown,
    RightUp,
}

This class also contains an Actions DependencyProperty and an Execute() method. Just like the TimerTrigger. I have tried to place them in an abstract base class TriggerBehavior<> but that caused problems in Blend. You couldn't drop an action on the Triggers deriving from this class. So I have chosen to have some duplicate code.

Triggers Demo Project

To demonstrate these behaviors I have written this 'Triggers Demo' project. I Blend for Visual Studio I have dropped a TimerTriggerBehavior onto the root Grid element of the MainPage.

On the TimerTriggerBehavior I have dropped a PlaySoundAction. The Source of this action is set to a Click.wav which I added to the \Assets\Sounds folder of the project.

The Grid also contains a ToggleSwitch. The IsOn property is databound to the IsEnabled property of the timer trigger.

<ToggleSwitch Header="TimeTrigger"
                HorizontalAlignment="Left"
                Margin="114,-6,0,0"
                Grid.Row="1"
                VerticalAlignment="Top"
                OnContent="Enabled"
                OffContent="Disabled"
                IsOn="{Binding IsEnabled, ElementName=MyTimerTrigger, Mode=TwoWay}" />

I have dropped the SwipeTriggerBehavior 4 times on a blue Grid. Each with a different Direction: Up, Down, Left, Right. Inside each trigger I have dropped a ChangePropertyAction. The Value of the Text property of a TextBlock is set to the direction

<Grid Grid.Row="2"
        Margin="120,0,40,40"
        Background="#0096FF">

    <Interactivity:Interaction.Behaviors>
        <Behaviors:SwipeTriggerBehavior Direction="Up">
            <Core:ChangePropertyAction PropertyName="Text"
                                        TargetObject="{Binding ElementName=tbDemo}"
                                        Value="Up" />
        </Behaviors:SwipeTriggerBehavior>
        <Behaviors:SwipeTriggerBehavior Direction="Down">
            <Core:ChangePropertyAction PropertyName="Text"
                                        TargetObject="{Binding ElementName=tbDemo}"
                                        Value="Down" />
        </Behaviors:SwipeTriggerBehavior>
        <Behaviors:SwipeTriggerBehavior Direction="Left">
            <Core:ChangePropertyAction PropertyName="Text"
                                        TargetObject="{Binding ElementName=tbDemo}"
                                        Value="Left" />
        </Behaviors:SwipeTriggerBehavior>
        <Behaviors:SwipeTriggerBehavior Direction="Right">
            <Core:ChangePropertyAction PropertyName="Text"
                                        TargetObject="{Binding ElementName=tbDemo}"
                                        Value="Right" />
        </Behaviors:SwipeTriggerBehavior>
    </Interactivity:Interaction.Behaviors>

    <TextBlock Margin="50"
                HorizontalAlignment="Center"
                VerticalAlignment="Top"
                Style="{StaticResource HeaderTextBlockStyle}"
                Text="Swipe Up, Down, Left or Right" />

    <TextBlock x:Name="tbDemo"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Style="{StaticResource HeaderTextBlockStyle}" />

</Grid>

The result is a Page in which you hear a click sound play every 2 seconds. You can turn the sound off using the ToggleSwitch. If you swipe the blue box the swipe direction is shown in the center of this box.

Closure and download

I hope you like my solution. Feel free to use it in your projects. You can download the sample project below.

Cheers,

Fons

Events and code examples

0 Comments
By Roy Janssen, 2-7-2014

The last couple of months I have been speaking at a couple of events. For those who visited these events or for those who want to know more about the subject I will give a brief summary of the talks and post the slides / sample code here for you.

Azure mobile services

At the StoreAppsUG end of februari and at the SDN event last march I have been talking about Azure mobile services. In this talk I explained how to use Azure mobile services in combination with Windows 8 and Windows Phone 8. The example I have build for this is a clean example on how to do this in a simple way. You can find the slides (in Dutch) and example code here:

- Slides 

- Example code 

Kinect for Windows v2

At the TechDays in the Netherlands last april I have been talking about the new Kinect for Windows v2. As a participant in the Developer preview I had early access to the hardware and SDK. During this talk I showed a lot of the possibilities of the new Kinect for Windows sensor. You can watch my presentation online at the Channel 9 site.

Connecting hardware to Windows Phone 8

At the SDN event last june I spoke about connecting hardware to a Windows Phone 8 application. During this session I showed how you can connect and control Arduino hardware with your own Windows Phone 8 application. The Arduino hardware featured a lot of nice shining LED lights with the use of the Windows Phone application you could decide which to turn on or off. And even select the color of the RGB LED's. For now I'm only sharing the slides (in Dutch) since the code needs a little bit of cleaning up. But if you are interested in the rough code please contact me.

- Slides 

Tags: TechDays

TechDays 2014 videos and presentations

0 Comments
By Fons Sonnemans, 31-5-2014

Op 16 en 17 april heb ik weer bij het TechDays 2014 event van Microsoft een aantal sessies gepresenteerd. Via deze blog wil ik de videos en presentaties met u delen.

What’s new in XAML and Tooling for Windows 8.1?

Channel 9 Video

SlideShare presentatie

Making money with Apps

Channel 9 Video

SlideShare presentatie

Designing XAML Apps using Blend for Visual Studio 2013

Channel 9 Video

SlideShare presentatie

 

Cheers,

Fons

Tags: TechDays, Apps, Blend, Xaml

Windows 8.1 XAML Style for an AccentButton

0 Comments
By Fons Sonnemans, 14-4-2014

When you create a XAML application in Windows 8.1, you get a few built-in styles for TextBlock controls, such as: HeaderTextBlockStyle, TitleTextBlockStyle and SubtitleTextBlockStyle. Unfortunately there is no AccentButtonStyle. An AccentButton is a button with a special accent background color. I thought I’d try to create this Style. You can apply this Style to a Button. Optionally, you can set the Background property of the Button to a custom color.

AccentButtons sample

In the above example I have two StackPanels; the first with the RequestedTheme set to Dark, the second to Light. All Buttons in the StackPanel have the AccentButtonStyle. The bottom buttons have no Background property set. The 'Disabled' buttons have an IsEnabled property set to false.

<Page x:Class="AccentButtonDemo.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:local="using:AccentButtonDemo"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
              RequestedTheme="Dark">
            <TextBlock Style="{StaticResource SubtitleTextBlockStyle}"
            <StackPanel HorizontalAlignment="Center"
                        VerticalAlignment="Center">
                <Button HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Background="Red"
                        Content="Red"
                        Style="{StaticResource AccentButtonStyle}" />
                <Button HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Background="Blue"
                        Content="Blue"
                        Style="{StaticResource AccentButtonStyle}" />
                <Button HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Background="LightGray"
                        Content="Gray"
                        Style="{StaticResource AccentButtonStyle}" />
                <Button HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Background="Blue"
                        Content="Disabled Blue"
                        IsEnabled="False"
                        Style="{StaticResource AccentButtonStyle}" />
                <Button HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Content="Default"
                        Style="{StaticResource AccentButtonStyle}" />
            </StackPanel>
        </Grid>
        <Grid Grid.Column="1"
              Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
              RequestedTheme="Light">
            <StackPanel HorizontalAlignment="Center"
                        VerticalAlignment="Center">
                <Button HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Background="Red"
                        Content="Red"
                        Style="{StaticResource AccentButtonStyle}" />
                <Button HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Background="Blue"
                        Content="Blue"
                        Style="{StaticResource AccentButtonStyle}" />
                <Button HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Background="LightGray"
                        Content="Gray"
                        Style="{StaticResource AccentButtonStyle}" />
                <Button HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Background="Blue"
                        Content="Disabled Blue"
                        IsEnabled="False"
                        Style="{StaticResource AccentButtonStyle}" />
                <Button HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Content="Default"
                        Style="{StaticResource AccentButtonStyle}" />
            </StackPanel>
        </Grid>

    </Grid>
</Page>

AccentButtonStyle

The AccentButtonStyle is distributed in a resource dictionary through NuGet to make it easy to add it to your project and apply to your buttons. You will have to add this AccentButton.xaml ResourceDictionaries to the MergedDictionaries of your app.xaml or your pages or your controls.

<Application
    x:Class="AccentButtonDemo.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:AccentButtonDemo">
	<Application.Resources>
        
		<ResourceDictionary>

            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="AccentButton.xaml" />
			</ResourceDictionary.MergedDictionaries>

        </ResourceDictionary>
        
	</Application.Resources>

</Application>

 

Closure and download

I hope you like my solution. You can download the sample project below.

Cheers,

Fons

Tags: XAML, Windows8

Windows 8 XAML Tips - Combining Converters

1 Comments
By Fons Sonnemans, 23-12-2013

XAML is a declarative UI language; it's most powerful feature is surely data binding. In XAML you can set a converter on any binding. You use this when you need to display data in a format that differs from how it is stored. But you can only set ONE converter. So if you for instance want to convert a date using a FormatConverter and you want to convert the result to uppercase using a UppercaseConverter you are stuck. To solve this problem I have created a ValueConverterGroup class. It is a converter which contains multiple converters, it is a List of IValueConverter objects and it implements the IValueConverter interface. The Convert() method calls the Convert() method of all containing value converters. I haven't implement the ConvertBack() method because I won't be using it.

ValueConverterGroup

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;

namespace ReflectionIT.Windows8.Converters {

    public class ValueConverterGroup : List<IValueConverter>, IValueConverter {

        public object Convert(object value, Type targetType, object parameter, 
                                  string language) {
            return this.Aggregate(value, (current, converter) =>
                current == DependencyProperty.UnsetValue ? 
                    current : 
                    converter.Convert(current, targetType, parameter, language)
            );
        }

        public object ConvertBack(object value, Type targetType, object parameter, 
                                  string language) {
            System.Diagnostics.Debugger.Break(); // Not Implemented
            throw new NotImplementedException();
        }
    }
}

Example

The following sample page contains a DatePicker control and two TextBlock controls. The Text property of the TextBlocks are databound to the Date property of the DatePicker. The first (red) TextBlock uses a FormatConverter to convert the date to dd-MMM-yyyy string. The second (blue) TextBlock uses my ValueConverterGroup to combine a FormatConverter and an UppercaseConverter.

The two converters are static resources which are defined in the Page resources.

<Page x:Class="ConvertersDemo.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:ConvertersDemo"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:c="using:ReflectionIT.Windows8.Converters"
      mc:Ignorable="d">


    <Page.Resources>
        <c:FormatConverter x:Key="DateFormat"
                           FormatString="{}{0:dd-MMM-yyyy}" />

        <c:ValueConverterGroup x:Key="UppercaseDateFormat">
            <c:FormatConverter FormatString="{}{0:dd-MMM-yyyy}" />
            <c:UppercaseConverter />
        </c:ValueConverterGroup>
    </Page.Resources>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <DatePicker x:Name="datePicker"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Top"
                    Margin="136,85,0,0" />
        <TextBlock HorizontalAlignment="Left"
                   TextWrapping="Wrap"
                   Text="{Binding Date, Converter={StaticResource DateFormat},
                                   ElementName=datePicker}"
                   VerticalAlignment="Top"
                   Margin="136,164,0,0"
                   FontSize="64"
                   Foreground="Red" />
        <TextBlock HorizontalAlignment="Left"
                   TextWrapping="Wrap"
                   Text="{Binding Date, Converter={StaticResource UppercaseDateFormat},
                                   ElementName=datePicker}"
                   VerticalAlignment="Top"
                   Margin="136,283,0,0"
                   FontSize="64"
                   Foreground="Blue" />
    </Grid>
</Page>

As you can see in the next screenshot the blue TextBlock is showing the date in a dd-MMM-yyyy format in uppercase.

CombiningConverters

FormatConverter

The code of the FormatConverter class used in the example.

using System;
using System.Globalization;
using Windows.UI.Xaml.Data;

namespace ReflectionIT.Windows8.Converters {

    public class FormatConverter : IValueConverter {

        public string FormatString { get; set; }

        public object Convert(object value, Type typeName, object parameter, 
                                   string language) {

            string formatterString = (parameter as String) ?? FormatString;

            if (!string.IsNullOrEmpty(formatterString)) {
                return string.Format(formatterString, value);
            }

            return System.Convert.ToString(value);
        }

        public object ConvertBack(object value, Type typeName, object parameter, 
                                  string language) {
            System.Diagnostics.Debugger.Break(); // Not Implemented
            throw new NotImplementedException();
        }

    }
}

UppercaseConverter

The code of the UppercaseConverter class used in the example.

using System;
using Windows.UI.Xaml.Data;

namespace ReflectionIT.Windows8.Converters {

    class UppercaseConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, 
                                   string language) {
            return System.Convert.ToString(value).ToUpper();
        }

        public object ConvertBack(object value, Type targetType, object parameter, 
                                   string language) {
            System.Diagnostics.Debugger.Break(); // Not Implemented
            throw new NotImplementedException();
        }
    }
}

 

Closure and download

I hope you like my solution. Combining multiple converters is now very easy. You can download my code below.

Cheers,

Fons

Windows 8 XAML Tips - Popup.ShowAsync()

2 Comments
By Fons Sonnemans, 12-11-2013

In XAML applications you can use a Popup control to displays content on top of existing content. To show a Popup you must set the IsOpen property to true. You can subscribe yourself to the Closed eventhandler which is fired when the IsOpen property is (re)set to false. You can use this event to execute extra logic when the Popup is closed.

To make this easier I have created an ShowAsync() extension method which does this for you. I got my inspiration for this solution from this Awaiting Storyboard completion blog post by Nigel Sampson. He uses this technique to begin a storyboard using a BeginAsync() extension method.

private async void ButtonShowAsync_Click(object sender, RoutedEventArgs e) {
    (sender as Button).Content = "Clicked at " + DateTime.Now.ToString("HH:mm:ss");
    await this.popupTest.ShowAsync();
    (sender as Button).Content = "Closed at " + DateTime.Now.ToString("HH:mm:ss");
}

private void ButtonPopupIsOpen_Click(object sender, RoutedEventArgs e) {
    (sender as Button).Content = "Clicked at " + DateTime.Now.ToString("HH:mm:ss");
    this.popupTest.IsOpen = true;
    // You don't know when the popup was closed!
}

The ShowAsync() extension method uses an TaskCompletionSource. It allows us to create tasks behind the scenes and control whether they are completed, cancelled or failed. With this task you can build up some really handy mechanisms to improve the readability of your code.

static class Extensions {

    public static Task ShowAsync(this Popup popup) {

        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

        EventHandler<object> onClosed = null;
        onClosed = (s, e) => {
            popup.Closed -= onClosed;
            tcs.SetResult(true);
        };
        popup.Closed += onClosed;
        popup.IsOpen = true;

        return tcs.Task;
    }

}

The XAML used for this demo.

<Page x:Class="App4.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:App4"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel Margin="20">

            <Button Content="Popup.IsOpen"
                    Click="ButtonPopupIsOpen_Click" />

            <Button Content="Popup.ShowAsync"
                    Click="ButtonShowAsync_Click" />

        </StackPanel>

        <Popup x:Name="popupTest"
               Margin="150"
               IsLightDismissEnabled="True">
            <Grid Background="Red"
                  Width="200"
                  Height="200">
                <Button Content="Close"
                        HorizontalAlignment="Center"
                        Click="ButtonClose_Click" />
            </Grid>
        </Popup>
    </Grid>
</Page>

ExtensionMethod.net website

I have published this extension method on www.extensionmethod.net. It is a website where c#, vb.net, f# and javascript extension methods are shared. You can also find my Chooser.ShowAsync() extension method which you can use to show a Windows Phone Chooser (AddressChooserTask, EmailAddressChooserTask, PhoneNumberChooserTask, PhotoChooserTask) using this technique.

private async void Button_Click(object sender, RoutedEventArgs e) {
    try {
        var c = new PhotoChooserTask();
        var result = await c.ShowAsync();
        var bi = new BitmapImage();
        bi.SetSource(result.ChosenPhoto);
        imagePhoto.Source = bi;
    } catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
}

Closure and download

I hope you like my solution. My demo is writen as a Windows Store app but you can also use it in Windows Phone, Silverlight and WPF. You can download my code below.

Cheers,

Fons

Windows 8 XAML Tips - Conditional Behaviors

2 Comments
By Fons Sonnemans, 21-10-2013

A few weeks ago I have written a blog post about how you can write your own Behaviors and Actions for Windows 8.1. I noticed that the Windows 8.1 Actions are not compatible with the Silverlight and Windows Phone Actions. Those actions have a IsEnabled property.

The Windows 8.1 Actions don't have an IsEnabled property.

Luckily I got a tip from the Microsoft XAML Tools team. A new feature that is added to the Behaviors SDK is that Actions can return results as well as have its own ActionLists. This helps in relaying execution results or building conditional behaviors. 

IsEnabledCondition

A have written a simple class called IsEnabledCondition. This class implements the IAction interface which makes it an Action. It has two dependency properties: IsEnabled and Actions. The Actions property is set as the ContentProperty using the ContentPropertyAttribute on the class. The Execute() method only executes the contained actions when the IsEnabled property is set. I learned this ActionList from reading Mark Smith Behaviors in Windows 8.1 Store Apps blog post.

using System;
using Microsoft.Xaml.Interactivity;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Markup;

namespace ConditionalBehaviorsDemo.Behaviors {

    [ContentProperty(Name = "Actions")]
    public class IsEnabledCondition : DependencyObject, IAction {


        #region IsEnabled Dependency Property

        /// <summary> 
        /// Get or Sets the IsEnabled dependency property.  
        /// </summary> 
        public bool IsEnabled {
            get { return (bool)GetValue(IsEnabledProperty); }
            set { SetValue(IsEnabledProperty, value); }
        }

        /// <summary> 
        /// Identifies the IsEnabled dependency property. 
        /// This enables animation, styling, binding, etc...
        /// </summary> 
        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.Register("IsEnabled",
                                        typeof(bool),
                                        typeof(IsEnabledCondition),
                                        new PropertyMetadata(true));

        #endregion IsEnabled Dependency Property

        #region Actions Dependency Property

        /// <summary>
        /// Actions collection
        /// </summary>
        public ActionCollection Actions {
            get {
                var actions = (ActionCollection)base.GetValue(ActionsProperty);
                if (actions == null) {
                    actions = new ActionCollection();
                    base.SetValue(ActionsProperty, actions);
                }
                return actions;
            }
        }

        /// <summary>
        /// Backing storage for Actions collection
        /// </summary>
        public static readonly DependencyProperty ActionsProperty =
            DependencyProperty.Register("Actions", 
                                        typeof(ActionCollection), 
                                        typeof(IsEnabledCondition), 
                                        new PropertyMetadata(null));

        #endregion Actions Dependency Property

        public object Execute(object sender, object parameter) {
            if (this.IsEnabled) {
                return Interaction.ExecuteActions(sender, this.Actions, parameter);
            }
            return null;
        }
    }
}

I use this action as the parent of my previously used ControlStoryBoardAction. The IsEnabled property is databound to the IsOn property of the ToggleSwitch. Databinding is possible because the IsEnabled property is an Dependency Property. If you start the application you can click the button it moves to the right and then comes back. If you turn the 'Animate' switch Off an then click the button nothing happens.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button x:Name="button"
            Content="Button"
            HorizontalAlignment="Left"
            Height="97"
            Margin="90,72,0,0"
            VerticalAlignment="Top"
            Width="194"
            RenderTransformOrigin="0.5,0.5">
        <Button.RenderTransform>
            <CompositeTransform />
        </Button.RenderTransform>
        <Interactivity:Interaction.Behaviors>
            <Core:EventTriggerBehavior EventName="Click">
                <Behaviors:IsEnabledCondition 
                    IsEnabled="{Binding IsOn, ElementName=toggleSwitchAnimate}">
                    <Media:ControlStoryboardAction 
                        Storyboard="{StaticResource Storyboard1}" />
                </Behaviors:IsEnabledCondition>
            </Core:EventTriggerBehavior>
        </Interactivity:Interaction.Behaviors>
    </Button>
    <ToggleSwitch x:Name="toggleSwitchAnimate"
                    Header="Animate"
                    HorizontalAlignment="Left"
                    Margin="87,220,0,0"
                    VerticalAlignment="Top"
                    IsOn="True" />

</Grid>

Closure and download

I hope you like my solution. Maybe you can use it in your apps too. I plan to write many more conditional actions so check out my blogs for more posts. You can download my code below.

Cheers,

Fons

Windows Phone Week - Slides

0 Comments
By Fons Sonnemans, 8-10-2013

Op 5 oktober heb ik een 'Designing WP apps UI using Blend' presentatie verzorgt op de Windows Phone Developer Day. Deze dag was perfect georganiseerd door Joost van Schaik, Tom Verhoeff en Dennis Vroegop. Er waren ruim 60 deelnemers en de locatie bij Macaw was natuurlijk top. Meer info op http://www.dotned.nl/register/66/zaterdag-5-oktober--windows-phone-developer-day-.aspx

De slides zijn via onderstaande download link te bekijken. Voor vragen kan je natuurlijk altijd contact met mij opnemen.

Fons

Windows 8 XAML Tips - Creating Blend Behaviors

0 Comments
By Fons Sonnemans, 16-9-2013

The new version of Blend for Visual Studio 2013 RC now supports Behaviors. I have used Behaviors for developing Silverlight and Windows Phone applications a lot. Now you can use them for you Windows Store XAML apps too. Two type of Behaviors are supported: Behaviors and Actions. Triggers are "dropped" and can/should now be implemented using Behaviors. 

There are 7 build-in Actions: CallMethodAction, ChangePropertyAction, ControlStoryboardAction, GoToStateAction, InvokeCommandAction, NavigateToPageAction and PlaySoundAction. Many were already available in Silverlight. The NavigateToPageAction is new.

There are 3 build-in Behaviors: DataTriggerBehavior, EventTriggerBehavior and IncrementalUpdateBehavior.

You can create your own Actions and Behaviors.  Before you can do that you must add a reference to the 'Behaviors SDK'.

Creating Actions

You create an Action by adding a class to your project which derives from the DependencyObject class and implements the IAction interface. In Silverlight there was a TriggerAction base class, but that no longer exists. The IAction interface has only one Execute() method you should implement.

As an example I have created a simple ShowMessageAction. It contains a Text dependency property which you can set or databind. The Execute() method will show this Text in a MessageDialog.

using Microsoft.Xaml.Interactivity;
using System;
using Windows.UI.Popups;
using Windows.UI.Xaml;

namespace BehaviorsDemo.Behaviors {
    
    public class ShowMessageAction : DependencyObject, IAction {

        #region Text Dependency Property

        /// <summary> 
        /// Get or Sets the Text dependency property.  
        /// </summary> 
        public string Text {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        /// <summary> 
        /// Identifies the Text dependency property. This enables animation, styling, 
        /// binding, etc...
        /// </summary> 
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text",
                                        typeof(string),
                                        typeof(ShowMessageAction),
                                        new PropertyMetadata(string.Empty));

        

        #endregion Text Dependency Property

        public object Execute(object sender, object parameter) {
#pragma warning disable 4014
            new MessageDialog(this.Text).ShowAsync();
#pragma warning restore
            return null;
        }
    }
}

Use ShowMessageAction

After you have compiled the application you should switch to Blend to add this behavior to a control. I my case I have created a simple page containing a TextBox and a Button. In the 'Assets' window you should select the 'Behaviors'. You should see the 'ShowMessageAction' at the bottom of the list. Drag this action and drop it on the Buttton. The Text property of the action is databound to the Text property of the TextBox.

The ShowMessageAction is placed in an EventTriggerBehavior which has its EventName set to 'Click'. You can of course select a different event if you want. You can also select a different SourceObject. This is the object whose event is handled to trigger the action. The EventTriggerBehavior replaces the EventTrigger of Silverlight.

The XAML of this page.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:BehaviorsDemo"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
      xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
      xmlns:Behaviors="using:BehaviorsDemo.Behaviors"
      x:Class="BehaviorsDemo.MainPage"
      mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
          DataContext="{Binding Source={StaticResource SampleDataSource}}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="85*" />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <TextBox x:Name="textBoxDemo"
                     HorizontalAlignment="Left"
                     TextWrapping="Wrap"
                     Text="Hello World"
                     Width="400" />
            <Button Content="Show"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Top">
                <Interactivity:Interaction.Behaviors>
                    <Core:EventTriggerBehavior EventName="Click">
                        <Behaviors:ShowMessageAction Text="{Binding Text, ElementName=textBoxDemo}" />
                    </Core:EventTriggerBehavior>
                </Interactivity:Interaction.Behaviors>
            </Button>
        </StackPanel>
    </Grid>
</Page>

When you run the app and click the Button the text of the TextBox is shown in a MessageDialog. I think this is very cool. Designers can now add interactivity to the app without writing code.

Creating Behaviors

3 years ago I wrote this blog post Keyboard selection on Silverlight ListBox and ComboBox. It describes a Behavior which I used in my Silverlight apps. You could drop the Behavior on a ListBox or ComboBox. This enabled keyboard selection. So, if you pressed the key 'X', the ListBox/ComboBox would select the first row which started with the letter X. I always found this Behavior very userful. So I converted it to the new Windows 8.1 Behaviors. This allows me to use it for the Windows 8 DataControls (GridView, ListView and FlipView) without any extra programming effort.

You create a Behavior by adding a class to your project which derives from the DependencyObject class and implements the IBehavior interface. In Silverlight there was a Behavior and Behavior<T> base class, but that no longer exists. To make my conversion easier I re-created the Behavior<T> base class. It is an abstract class with an AssociatedObject (oftype T) property and two virtual methods OnAttached() and OnDetatching().

using Microsoft.Xaml.Interactivity;
using System;
using Windows.UI.Xaml;

namespace BehaviorsDemo.Behaviors {

    public abstract class Behavior<T> : DependencyObject, IBehavior where T : DependencyObject {

        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
        public T AssociatedObject { get; set; }

        protected virtual void OnAttached() {
        }

        protected virtual void OnDetaching() {
        }

        public void Attach(Windows.UI.Xaml.DependencyObject associatedObject) {
            this.AssociatedObject = (T)associatedObject;
            OnAttached();
        }

        public void Detach() {
            OnDetaching();
        }

        DependencyObject IBehavior.AssociatedObject {
            get { return this.AssociatedObject; }
        }
    }
}

The KeyboardSelectionBehavior class is almost a one-on-one port of my Silverlight code. I just changed some namespaces and cleaned up some code. The ListBoxItem is now replaced by a SelectorItem.

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;

namespace BehaviorsDemo.Behaviors {

    /// <summary>
    /// This behavior can be attached to a ListBox or ComboBox to 
    /// add keyboard selection
    /// </summary>
    public class KeyboardSelectionBehavior : Behavior<Selector> {

        private bool _boundToComboBoxItemsPanelRoot;

        /// <summary>
        /// Gets or sets the Path used to select the text
        /// </summary>
        public string SelectionMemberPath { get; set; }

        /// <summary>
        /// Attaches to the specified object: subscribe on KeyDown event
        /// </summary>
        protected override void OnAttached() {
            base.OnAttached();
            this.AssociatedObject.KeyDown += DoKeyDown;

            // subscribe on KeyDown event of the ItemsPanelRoot
            // of a ComboBox when it is opened
            var cb = this.AssociatedObject as ComboBox;
            if (cb != null) {
                cb.DropDownOpened += ComboBox_DropDownOpened;
            }
        }

        /// <summary>
        /// subscribe on KeyDown event of ItemsPanelRoot of a ComboBox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ComboBox_DropDownOpened(object sender, object e) {
            var itemsPanelRoot = this.AssociatedObject.ItemsPanelRoot;
            if (_boundToComboBoxItemsPanelRoot == false && itemsPanelRoot != null) {
                _boundToComboBoxItemsPanelRoot = true;
                itemsPanelRoot.KeyDown += DoKeyDown;
            }
        }

        /// <summary>
        /// Detaches to the specified object: Unsubscribe on KeyDown event(s)
        /// </summary>
        protected override void OnDetaching() {
            this.AssociatedObject.KeyDown -= DoKeyDown;
            
            var cb = this.AssociatedObject as ComboBox;
            if (cb != null) {
                cb.DropDownOpened -= ComboBox_DropDownOpened;
                if (_boundToComboBoxItemsPanelRoot) {
                    var itemsPanelRoot = this.AssociatedObject.ItemsPanelRoot;
                    if (itemsPanelRoot != null) {
                        _boundToComboBoxItemsPanelRoot = false;
                        itemsPanelRoot.KeyDown -= DoKeyDown;
                    }
                }
            }
            base.OnDetaching();
        }

        /// <summary>
        /// Select the correct item
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void DoKeyDown(object sender, KeyRoutedEventArgs e) {
            // Create a list of strings and indexes
            int index = 0;
            IEnumerable<Item> list = null;

            var path = SelectionMemberPath ??
                this.AssociatedObject.DisplayMemberPath;

            var evaluator = new BindingEvaluator();
            if (path != null) {
                list = this.AssociatedObject.Items.OfType<object>()
                    .Select(item => {
                        // retrieve the value using the supplied Path
                        var binding = new Binding();
                        binding.Path = new PropertyPath(path);
                        binding.Source = item;

                        BindingOperations.SetBinding(evaluator,
                            BindingEvaluator.TargetProperty, binding);
                        var value = evaluator.Target;

                        return new Item {
                            Index = index++,
                            Text = Convert.ToString(value)
                        };
                    });
            } else {
                list = this.AssociatedObject.Items.OfType<SelectorItem>()
                    .Select(item => new Item {
                        Index = index++,
                        Text = Convert.ToString(item.Content)
                    });
            }
            // Sort the list starting at next selectedIndex to the end and 
            // then from the beginning
            list = list.OrderBy(item => item.Index <=
                this.AssociatedObject.SelectedIndex ?
                item.Index + this.AssociatedObject.Items.Count : item.Index);

            // Find first starting with 
            var text = e.Key.ToString();
            var first = list.FirstOrDefault(item => item.Text.StartsWith(text,
                StringComparison.CurrentCultureIgnoreCase));

            if (first != null) {
                // found
                this.AssociatedObject.SelectedIndex = first.Index;
            }
        }

        /// <summary>
        /// Helper class
        /// </summary>
        private class Item {
            public int Index { get; set; }
            public string Text { get; set; }
        }

        /// <summary>
        /// Helper class used for property path value retrieval
        /// </summary>
        private class BindingEvaluator : FrameworkElement {

            public static readonly DependencyProperty TargetProperty =
                DependencyProperty.Register(
                    "Target",
                    typeof(object),
                    typeof(BindingEvaluator), null);

            public object Target {
                get { return GetValue(TargetProperty); }
                set { SetValue(TargetProperty, value); }
            }

        }
    }
}

Use KeyboardSelectionBehavior

To demonstrate the KeyboardSelectionBehavior I added some sample data containing Employees to the Project. An Employee has a Name, Salary and Image property. I created a GridView in which the ItemSource is data bound to the Employees sample data.

Next, I dragged the KeyboardSelectionBehavior from the Assets Window and dropped it on the GridView.

The behavior has a SelectionMemberPath property to specify which property to use for selection. In this example it is set to the Name of the databound Employee.

The XAML of this page.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:BehaviorsDemo"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
      xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
      xmlns:Behaviors="using:BehaviorsDemo.Behaviors"
      x:Class="BehaviorsDemo.MainPage"
      mc:Ignorable="d">
    <Page.Resources>
        <DataTemplate x:Key="EmployeesItemTemplate">
            <Grid Height="110"
                  Width="480"
                  Margin="10">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}"
                        Width="110"
                        Height="110">
                    <Image Source="{Binding Image}"
                           Height="110"
                           Width="110" />
                </Border>
                <StackPanel Grid.Column="1"
                            Margin="10,0,0,0">
                    <TextBlock Text="{Binding Name}"
                               Style="{StaticResource TitleTextBlockStyle}" />
                    <TextBlock Text="{Binding Salary}"
                               Style="{StaticResource CaptionTextBlockStyle}"
                               TextWrapping="NoWrap" />
                </StackPanel>
            </Grid>
        </DataTemplate>
    </Page.Resources>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
          DataContext="{Binding Source={StaticResource SampleDataSource}}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="85*" />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <TextBox x:Name="textBoxDemo"
                     HorizontalAlignment="Left"
                     TextWrapping="Wrap"
                     Text="Hello World"
                     Width="400" />
            <Button Content="Show"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Top">
                <Interactivity:Interaction.Behaviors>
                    <Core:EventTriggerBehavior EventName="Click">
                        <Behaviors:ShowMessageAction Text="{Binding Text, ElementName=textBoxDemo}" />
                    </Core:EventTriggerBehavior>
                </Interactivity:Interaction.Behaviors>
            </Button>

        </StackPanel>
        <GridView ItemTemplate="{StaticResource EmployeesItemTemplate}"
                  ItemsSource="{Binding Employees}"
                  IsSwipeEnabled="False"
                  Grid.Row="1"
                  SelectionMode="Single">
            <Interactivity:Interaction.Behaviors>
                <Behaviors:KeyboardSelectionBehavior SelectionMemberPath="Name" />
            </Interactivity:Interaction.Behaviors>
        </GridView>

    </Grid>
</Page>

Run the app and focus the GridView. You can then press the key 'C' when and it will select 'Carpenter, Terry' employee.

Closure and download

I hope you like my solution. Maybe you can use it in your apps too. You can download my code below. My colleague MVP Timmy Kokke has created the http://www.blendbehaviors.net/ website which is used to share Behaviors and Actions. You will soon be able to download my ShowMessageAction and KeyBoardSelectionBehavior there as well.

Cheers,

Fons

All postings/content on this blog are provided "AS IS" with no warranties, and confer no rights. All entries in this blog are my opinion and don't necessarily reflect the opinion of my employer or sponsors. The content on this site is licensed under a Creative Commons Attribution By license.