Beware oh beware of the Nullable type #uwp

Having done limited rollout yesterday I noticed a strange pattern. A huge number of crashes with “System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw

The most interesting bit was that the failures were only mostly on phones and not on desktop devices.

devices

What the heck!! looking inside didn’t help much. The crash group on HockeyApp also mentioned ‘invalidoperation_novalue‘ Okay this was strange.. In another instance I had a similar invalidoperation_novalue but somewhat different location ‘System.Nullable$1.get_Value

In a few places I was using nullable int. that translates to System.UInt32

int? pos = null;

// elsewhere read it
var item = list[pos.HasValue ? pos.Value : 0];

// in other places I encountered some exceptions - can't remember what and I used null check rather than HasValue
var item2 = list[pos != null ? pos.Value : 0]; 

//or in newer iteration of csharp
var item3 = list[pos?.Value??0];

Somehow I was directly using instance of nullable directly. A few posts helped. I was sure that was the problem. Thanks to Carsten Schuette for showing the use of GetValueOrDefault

InvalidOperationException in DeviceUtils.DiagonalSize
System.InvalidOperationException must contain value for ViewModel

So in the latest build, I have replaced above usage with

int? pos = null;

// elsewhere read it
var item = list[pos.GetValueOrDefault(0)];

Only hoping that I identified and fixed the one that was causing the issue. Stack trace with .NET Native can be painful.

Exception Type:  System.InvalidOperationException
Crashed Thread:  2

Application Specific Information:
InvalidOperation_NoValue. For more information, visit http://go.microsoft.com/fwlink/?LinkId=623485

Exception Stack:
SharedLibrary!<BaseAddress>+0x388719
MOL-Desktop!<BaseAddress>+0x121e122
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
SharedLibrary!<BaseAddress>+0x353fa2
SharedLibrary!<BaseAddress>+0x353a0e
SharedLibrary!<BaseAddress>+0x38387a
MOL-Desktop!<BaseAddress>+0x121d783
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
SharedLibrary!<BaseAddress>+0x3c2c09
SharedLibrary!<BaseAddress>+0x35369a
MOL-Desktop!<BaseAddress>+0xf08a62
MOL-Desktop!<BaseAddress>+0xf0b397
MOL-Desktop!<BaseAddress>+0xf0b2ef
Microsoft.HockeyApp.Extensibility.Windows.UnhandledExceptionTelemetryModule.CoreApplication_UnhandledErrorDetected(Object sender, ApplicationModel.Core.UnhandledErrorDetectedEventArgs e)

Thread 2 Crashed:
0   SharedLibrary                        0x0000000002908719 0x0000000002580000 + 3704601
1   MOL-Desktop                          0x0000000001e1e122 0x0000000000c00000 + 18997538
2   SharedLibrary                        0x00000000028d3fcc 0x0000000002580000 + 3489740
3   SharedLibrary                        0x00000000028d3fa2 0x0000000002580000 + 3489698
4   SharedLibrary                        0x00000000028d3a0e 0x0000000002580000 + 3488270
5   SharedLibrary                        0x000000000290387a 0x0000000002580000 + 3684474
6   MOL-Desktop                          0x0000000001e1d783 0x0000000000c00000 + 18995075
7   SharedLibrary                        0x00000000028d3fcc 0x0000000002580000 + 3489740
8   SharedLibrary                        0x0000000002942c09 0x0000000002580000 + 3943433
9   SharedLibrary                        0x00000000028d369a 0x0000000002580000 + 3487386
10  MOL-Desktop                          0x0000000001b08a62 0x0000000000c00000 + 15764066
11  MOL-Desktop                          0x0000000001b0b397 0x0000000000c00000 + 15774615
12  MOL-Desktop                          0x0000000001b0b2ef 0x0000000000c00000 + 15774447
13  MOL-Desktop                          0x0000000001dd44db 0x0000000000c00000 + 18695387
Advertisement

All new Daily Mail Online #UWP #Windows10 app now available in store

In November 2015, I joined MailOnline and created their first Windows Phone and Windows 10 app. It was a standard XAML app following MVVM pattern etc etc. The design was tried and tested first on iOS and then on Android. There were discussion on a clean new design and being the smallest platform, new design Windows 10 app were approved in March 2016. Fast forward 9 months and Windows 10 app rework has been pushed to store today with a limited rollout 5% users

I mentioned that the design is different – it follows the curated style on the website closely. Not only that I have followed a new style myself – I created this app as an SPA (Single Page Application). With WinRT API page caching is disabled by default and maintaining scroll positions etc is PITA. In past I have seen ListView behaving oddly when page caching is turned on. To get away from this, I created this app as an SPA. No forward backward navigation – its more like show / hide correct content. Its a big experiment on my side. Above and beyond all else two libraries played key role in creating this app

ReactiveUI My first go at using RX ever. It has made many things so simple. I still use event wiring in a few places but I will try to remove those over coming versions.
UWP Community Toolkit In previous version trying to tune the caching was a pain. In this version thanks to the toolkit I have multiple caches (image, video and json) and image ready for offline usage.

I should thank my colleagues George Medve, Jan Knotek and VK. I should also thank my ex-colleagues Zeno Foltin, Kristian Angyal and Rui Peres. They all helped out in many ways including happily getting trolled in the process.

Here are some of the screenshots.

screenshot-24
screenshot-29
screenshot-27
screenshot-25
screenshot-32

Its an adaptive app and adapts to mobile devices.
wp_ss_20170117_0001
wp_ss_20170117_0002
wp_ss_20170117_0004
wp_ss_20170117_0005
wp_ss_20170117_0006

There much more that needs to be done. This is only the beginning.

More on #UWPCommunityToolkit CacheBase #uwpdev

In the first version of UWP Community Toolkit, we only had ImageCache which had its origin in Windows App Studio. A few issues were raised to optimise it and one mentioned extensible cache that can be used to create any case.

FileCache, ImageCache, VideoCache, JsonCache.. you name it.. Yesterday I mentioned CacheBase. FileCache and ImageCache that ship with UWP Community Toolkit are implementations of CacheBase by giving it a specific type.

Today I had to implement ability to pull configuration settings from our server. I tried using current prod version of FileCache but my implementation was somewhat wrong there. It would try to create File from Stream and return null and then fail internally (fixed in current dev branch) however I needed something today. Enter ConfigCache.. well JsonCache really

public class ConfigCache : CacheBase<ConfigurationSetting>
{
    JsonSerializer jsonSerializer = new JsonSerializer();

    /// <summary>
    /// Private singleton field.
    /// </summary>
    private static ConfigCache _instance;

    /// <summary>
    /// Gets public singleton property.
    /// </summary>
    public static ConfigCache Instance => _instance ?? (_instance = new ConfigCache() { MaintainContext = false });

    protected override async Task<ConfigurationSetting> InitializeTypeAsync(StorageFile baseFile)
    {
        using (var stream = await baseFile.OpenStreamForReadAsync())
        {
            return InitializeTypeAsync(stream);
        }
    }

    protected override Task<ConfigurationSetting> InitializeTypeAsync(IRandomAccessStream stream)
    {
        var config = InitializeTypeAsync(stream.AsStream());
        return Task.FromResult<ConfigurationSetting>(config);
    }

    private ConfigurationSetting InitializeTypeAsync(Stream stream)
    {
        var reader = new StreamReader(stream);

        using (var jsonReader = new JsonTextReader(reader))
        {
            return jsonSerializer.Deserialize<ConfigurationSetting>(jsonReader);
        }
    }
}

In this case I am using a specific type to deserialise json to. How do I use it ?

ConfigCache.Instance.CacheDuration = TimeSpan.FromDays(1);

this.ConfigurationSettings = await ConfigCache.Instance.GetFromCacheAsync(new Uri(urlPath));

This would ensure that if configuration is older than a day, it will be downloaded again. Either way the caller will get deserialised data.

VideoCache #uwp #uwpdev

Earlier today (10 mins ago), we were discussing looping animated previews (rolling video frames) for articles and that maybe we should create a cache to prevent it being downloaded over and over again.

Back in UWP Community Toolkit, we created a CacheBase – a generic base implementation of Cache. This can be used to create just about any type of data cache.

This CacheBase was then used to implement ImageCache and finally FileCache just to show it can be done with other types too. So this is what I did.

public class VideoCache : CacheBase<MediaSource>
{
    /// <summary>
    /// Private singleton field.
    /// </summary>
    private static VideoCache _instance;

    /// <summary>
    /// Gets public singleton property.
    /// </summary>
    public static VideoCache Instance => _instance ?? (_instance = new VideoCache() { MaintainContext = true });

    protected override Task<MediaSource> InitializeTypeAsync(StorageFile baseFile)
    {
        return Task.Run(() => MediaSource.CreateFromStorageFile(baseFile));
    }

    protected override Task<MediaSource> InitializeTypeAsync(IRandomAccessStream stream)
    {
        return Task.Run(() => MediaSource.CreateFromStream(stream, "video/mp4"));
    }
}

Previously in my video player (see my previous blog post), I created a MediaSource from Uri.. now this to use the Cache

//MediaSource mediaSource = MediaSource.CreateFromUri(this.Video.Uri);
MediaSource mediaSource = await VideoCache.Instance.GetFromCacheAsync(this.Video.Uri);

Now the animated previews are not only cached and reused but they are also available offline.

To ensure that you do not build a large set, always make sure you set CacheDuration and remove expired items.

// somewhere in your App.xaml.cs
VideoCache.Instance.CacheDuration = TimeSpan.FromDays(1);

elsewhere in your cleanup code

await VideoCache.Instance.RemoveExpiredAsync();

Took me about 2 mins to roll out and get it running.

Media playback controls and strange behaviour of transport controls #uwp

Windows 10 WinRT API introduced ability to query whether a certain class, method, property etc were supported during run-time or not. This would allow applications to conditionally do things rather than crashing out due to unsupported API.

Since the initial release, many APIs have been introduced, Composition layer has seen many enhancements. Controls like MediaElementPlayer which return the load on UI thread by directly targeting GPU have been introduced. Prior to that developers used MediaElement control that was introduced in Windows 8 / Windows Phone 8.1 and was included in UWP API 10.0.10240.0. To take advantage of better performing control on updated devices, we need to use newer control.

private bool UseMediaPlayerElement => ApiInformation.IsTypePresent("Windows.UI.Xaml.Controls.MediaPlayerElement");

At this point we know whether we can use MediaElementPlayer or we need to fallback to MediaElement. Following the guidelines provided by Microsoft to an extent, I created a user control that dynamically injects the right control

public sealed partial class VideoPlayerUC : UserControl
{
    FrameworkElement mediaControl = null;

    private bool UseMediaPlayerElement => 
        ApiInformation.IsTypePresent("Windows.UI.Xaml.Controls.MediaPlayerElement");

    public VideoPlayerUC()
    {
        this.InitializeComponent();
            
        if (this.UseMediaPlayerElement)
        {
            mediaControl = new MediaPlayerElement();
        }
        else
        {
            mediaControl = new MediaElement();
        }

        this.Root.Children.Add(mediaControl);
    }

    public Video Video
    {
        get { return (Video)GetValue(VideoProperty); }
        set { SetValue(VideoProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Video.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty VideoProperty =
        DependencyProperty.Register("Video", 
        typeof(Video), 
        typeof(VideoPlayerUC), 
        new PropertyMetadata(null, OnVideoChanged));

    private static void OnVideoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = d as VideoPlayerUC;
        control?.HandleVideoChange();
    }

    private void HandleVideoChange()
    {
        if (this.Video == null)
        {
            return;
        }

        MediaSource mediaSource = MediaSource.CreateFromUri(this.Video.Uri);

        MediaPlaybackItem playbackItem = new MediaPlaybackItem(mediaSource);

        if (this.UseMediaPlayerElement)
        {
            var mpe = mediaControl as MediaPlayerElement;

            mpe.Stretch = Stretch.Uniform;
            mpe.AreTransportControlsEnabled = this.Video.ShowControls;
            mpe.Source = playbackItem;
            mpe.PosterSource = new BitmapImage() { UriSource = this.Video.Images.Still.Uri };
            mpe.AutoPlay = Video.AutoPlay;

            if (mpe.MediaPlayer != null)
            {
                mpe.MediaPlayer.IsLoopingEnabled = Video.IsLooping;
            }
        }
        else
        {
            var me = mediaControl as MediaElement;

            me.Stretch = Stretch.Uniform;
            me.AreTransportControlsEnabled = this.Video.ShowControls;
            me.SetPlaybackSource(playbackItem);
            me.PosterSource = new BitmapImage() { UriSource = this.Video.Images.Still.Uri };
            me.AutoPlay = Video.AutoPlay;
            me.IsLooping = Video.IsLooping;
        }
    }
}

what I however noticed was that the playback controls (aptly called Transport controls) were very flaky.. Here’s an example.. they’d work some times and not at other times (read most of the times)

I was really baffled by this behaviour.. I reworked the user control a few times. I moved to using PlayerFramework but its styling is Windows 8 and that was rather annoying trying to style.

So I decided to try creating custom transport controls. Step one I created a custom template control that just derived from MediaTransportControls

public sealed class VideoControls : MediaTransportControls
{
    public VideoControls()
    {
        this.DefaultStyleKey = typeof(VideoControls);
    }
}

Set the XAML to default MediaTransport Style.
Now instantiate this and add that to the MediaPlayerElement / MediaElement and all was good except it was looking a bit rough. So time to style it like my design team wanted it to look. Here’s the final style

VideoControls controls = new VideoControls();

mpe.TransportControls = controls;

<Style TargetType="view:VideoControls">
    <Setter Property="IsTabStop" Value="False" />
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="FlowDirection" Value="LeftToRight" />
    <Setter Property="UseSystemFocusVisuals" Value="True" />
    <Setter Property="IsTextScaleFactorEnabled" Value="False" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="view:VideoControls">
                <Grid x:Name="RootGrid" Background="Transparent">
                    <Grid.Resources>

                        <!-- New AppBar button style 48x48 pixels in size -->

<Style x:Key="AppBarButtonStyle" TargetType="AppBarButton">
                            <Setter Property="Width" Value="{ThemeResource MTCMediaButtonWidth}" />
                            <Setter Property="Height" Value="{ThemeResource MTCMediaButtonHeight}" />
                            <Setter Property="Background" Value="#FF919191" />
                            <Setter Property="Foreground" Value="#FFFFFFFF" />
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="AppBarButton">
                                        <Grid x:Name="Root" MinWidth="{TemplateBinding MinWidth}" MaxWidth="{TemplateBinding MaxWidth}" Background="{TemplateBinding Background}">
                                            <StackPanel x:Name="ContentRoot" MinHeight="{ThemeResource AppBarThemeCompactHeight}">
                                                <ContentPresenter x:Name="Content" Height="20" Margin="0,14,0,4" HorizontalAlignment="Stretch" AutomationProperties.AccessibilityView="Raw" Content="{TemplateBinding Icon}" Foreground="{TemplateBinding Foreground}" />
                                                <TextBlock x:Name="TextLabel" Margin="0,0,0,6" FontFamily="{TemplateBinding FontFamily}" FontSize="12" Foreground="{TemplateBinding Foreground}" Text="{TemplateBinding Label}" TextAlignment="Center" TextWrapping="Wrap" />
                                            </StackPanel>

                                            <TextBlock x:Name="OverflowTextLabel" Margin="12,0,12,0" Padding="0,5,0,7" HorizontalAlignment="Stretch" VerticalAlignment="Center" FontFamily="{TemplateBinding FontFamily}" FontSize="15" Foreground="{TemplateBinding Foreground}" Text="{TemplateBinding Label}" TextAlignment="Left" TextTrimming="Clip" TextWrapping="NoWrap" Visibility="Collapsed" />
                                            <VisualStateManager.VisualStateGroups>
                                                <VisualStateGroup x:Name="ApplicationViewStates">
                                                    <VisualState x:Name="FullSize" />
                                                    <VisualState x:Name="Compact">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Visibility">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                    <VisualState x:Name="Overflow">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="Visibility">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Visibility">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                    <VisualState x:Name="OverflowWithToggleButtons">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="Visibility">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Visibility">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Margin">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="38,0,12,0" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                </VisualStateGroup>
                                                <VisualStateGroup x:Name="CommonStates">
                                                    <VisualState x:Name="Normal">
                                                        <Storyboard>
                                                            <PointerUpThemeAnimation Storyboard.TargetName="OverflowTextLabel" />
                                                        </Storyboard>
                                                    </VisualState>
                                                    <VisualState x:Name="PointerOver">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="#FF616161" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="#FFFFFFFF" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <PointerUpThemeAnimation Storyboard.TargetName="OverflowTextLabel" />
                                                        </Storyboard>
                                                    </VisualState>
                                                    <VisualState x:Name="Pressed">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <PointerDownThemeAnimation Storyboard.TargetName="OverflowTextLabel" />
                                                        </Storyboard>
                                                    </VisualState>
                                                    <VisualState x:Name="Disabled">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextLabel" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="OverflowTextLabel" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                </VisualStateGroup>
                                                <VisualStateGroup x:Name="InputModeStates">
                                                    <VisualState x:Name="InputModeDefault" />
                                                    <VisualState x:Name="TouchInputMode">
                                                        <VisualState.Setters>
                                                            <Setter Target="OverflowTextLabel.Padding" Value="0,11,0,13" />
                                                        </VisualState.Setters>
                                                    </VisualState>
                                                </VisualStateGroup>
                                            </VisualStateManager.VisualStateGroups>
                                        </Grid>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>


                        <!-- New CommandBar Style -->

<Style x:Key="CommandBarStyle" TargetType="CommandBar">
                            <Setter Property="Height" Value="{ThemeResource MTCMediaButtonHeight}" />
                            <Setter Property="Background" Value="Transparent" />
                        </Style>


                        <!-- Style for Error Message text -->

<Style x:Key="MediaTextBlockStyle" TargetType="TextBlock">
                            <Setter Property="VerticalAlignment" Value="Center" />
                            <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />
                            <Setter Property="FontSize" Value="{ThemeResource MTCMediaFontSize}" />
                            <Setter Property="FontFamily" Value="{ThemeResource MTCMediaFontFamily}" />
                            <Setter Property="IsTextScaleFactorEnabled" Value="False" />
                        </Style>



                        <!-- Style for Position slider used in Media Transport Controls -->

<Style x:Key="MediaSliderStyle" TargetType="Slider">
                            <Setter Property="Background" Value="{ThemeResource SystemControlForegroundBaseMediumLowBrush}" />
                            <Setter Property="BorderThickness" Value="{ThemeResource SliderBorderThemeThickness}" />
                            <Setter Property="Foreground" Value="{ThemeResource SystemControlHighlightAccentBrush}" />
                            <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
                            <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
                            <Setter Property="ManipulationMode" Value="None" />
                            <Setter Property="UseSystemFocusVisuals" Value="True" />
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="Slider">
                                        <Grid Margin="{TemplateBinding Padding}">
                                            <Grid.Resources>

<Style x:Key="SliderThumbStyle" TargetType="Thumb">
                                                    <Setter Property="BorderThickness" Value="0" />
                                                    <Setter Property="Background" Value="{ThemeResource SystemControlForegroundAccentBrush}" />
                                                    <Setter Property="Foreground" Value="{ThemeResource SystemControlBackgroundChromeMediumBrush}" />
                                                    <Setter Property="Template">
                                                        <Setter.Value>
                                                            <ControlTemplate TargetType="Thumb">
                                                                <Ellipse x:Name="ellipse" Fill="{TemplateBinding Foreground}" Stroke="{TemplateBinding Background}" StrokeThickness="2" />
                                                            </ControlTemplate>
                                                        </Setter.Value>
                                                    </Setter>
                                                </Style>


<Style x:Key="MediaSliderProgressBarStyle" TargetType="ProgressBar">
                                                    <Setter Property="Height" Value="{ThemeResource SliderTrackThemeHeight}" />
                                                    <Setter Property="Minimum" Value="0" />
                                                    <Setter Property="Maximum" Value="100" />
                                                    <Setter Property="Foreground" Value="{ThemeResource SystemControlHighlightChromeAltLowBrush}" />
                                                    <Setter Property="Background" Value="Transparent" />
                                                    <Setter Property="BorderBrush" Value="Transparent" />
                                                    <Setter Property="BorderThickness" Value="1" />
                                                </Style>

                                            </Grid.Resources>
                                            <Grid.RowDefinitions>
                                                <RowDefinition Height="Auto" />
                                                <RowDefinition Height="*" />
                                            </Grid.RowDefinitions>
                                            <ContentPresenter x:Name="HeaderContentPresenter" Margin="{ThemeResource SliderHeaderThemeMargin}" x:DeferLoadStrategy="Lazy" Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" FontWeight="{ThemeResource SliderHeaderThemeFontWeight}" Foreground="{ThemeResource SystemControlForegroundBaseHighBrush}" Visibility="Collapsed" />
                                            <Grid x:Name="SliderContainer" Grid.Row="1" Background="Transparent" Control.IsTemplateFocusTarget="True">
                                                <Grid x:Name="HorizontalTemplate" MinHeight="44">
                                                    <Grid.ColumnDefinitions>
                                                        <ColumnDefinition Width="Auto" />
                                                        <ColumnDefinition Width="Auto" />
                                                        <ColumnDefinition Width="*" />
                                                    </Grid.ColumnDefinitions>
                                                    <Grid.RowDefinitions>
                                                        <RowDefinition Height="18" />
                                                        <RowDefinition Height="Auto" />
                                                        <RowDefinition Height="18" />
                                                    </Grid.RowDefinitions>
                                                    <Rectangle x:Name="HorizontalTrackRect" Grid.Row="1" Grid.ColumnSpan="3" Height="{ThemeResource SliderTrackThemeHeight}" Fill="{TemplateBinding Background}" />
                                                    <ProgressBar x:Name="DownloadProgressIndicator" Grid.Row="1" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" VerticalAlignment="Center" Style="{StaticResource MediaSliderProgressBarStyle}" />
                                                    <Rectangle x:Name="HorizontalDecreaseRect" Grid.Row="1" Fill="{TemplateBinding Foreground}" />
                                                    <TickBar x:Name="TopTickBar" Grid.ColumnSpan="3" Height="{ThemeResource SliderOutsideTickBarThemeHeight}" Margin="0,0,0,4" VerticalAlignment="Bottom" Fill="{ThemeResource SystemControlForegroundBaseMediumLowBrush}" Visibility="Collapsed" />
                                                    <TickBar x:Name="HorizontalInlineTickBar" Grid.Row="1" Grid.ColumnSpan="3" Height="{ThemeResource SliderTrackThemeHeight}" Fill="{ThemeResource SystemControlBackgroundAltHighBrush}" Visibility="Collapsed" />
                                                    <TickBar x:Name="BottomTickBar" Grid.Row="2" Grid.ColumnSpan="3" Height="{ThemeResource SliderOutsideTickBarThemeHeight}" Margin="0,4,0,0" VerticalAlignment="Top" Fill="{ThemeResource SystemControlForegroundBaseMediumLowBrush}" Visibility="Collapsed" />
                                                    <Thumb x:Name="HorizontalThumb" Grid.Row="0" Grid.RowSpan="3" Grid.Column="1" Width="24" Height="24" AutomationProperties.AccessibilityView="Raw" Background="{ThemeResource SystemControlForegroundAccentBrush}" DataContext="{TemplateBinding Value}" Style="{StaticResource SliderThumbStyle}" />
                                                </Grid>

                                                <Grid x:Name="VerticalTemplate" MinWidth="44" Visibility="Collapsed">
                                                    <Grid.RowDefinitions>
                                                        <RowDefinition Height="*" />
                                                        <RowDefinition Height="Auto" />
                                                        <RowDefinition Height="Auto" />
                                                    </Grid.RowDefinitions>
                                                    <Grid.ColumnDefinitions>
                                                        <ColumnDefinition Width="18" />
                                                        <ColumnDefinition Width="Auto" />
                                                        <ColumnDefinition Width="18" />
                                                    </Grid.ColumnDefinitions>
                                                    <Rectangle x:Name="VerticalTrackRect" Grid.RowSpan="3" Grid.Column="1" Width="{ThemeResource SliderTrackThemeHeight}" Fill="{TemplateBinding Background}" />
                                                    <Rectangle x:Name="VerticalDecreaseRect" Grid.Row="2" Grid.Column="1" Fill="{TemplateBinding Foreground}" />
                                                    <TickBar x:Name="LeftTickBar" Grid.RowSpan="3" Width="{ThemeResource SliderOutsideTickBarThemeHeight}" Margin="0,0,4,0" HorizontalAlignment="Right" Fill="{ThemeResource SystemControlForegroundBaseMediumLowBrush}" Visibility="Collapsed" />
                                                    <TickBar x:Name="VerticalInlineTickBar" Grid.RowSpan="3" Grid.Column="1" Width="{ThemeResource SliderTrackThemeHeight}" Fill="{ThemeResource SystemControlBackgroundAltHighBrush}" Visibility="Collapsed" />
                                                    <TickBar x:Name="RightTickBar" Grid.RowSpan="3" Grid.Column="2" Width="{ThemeResource SliderOutsideTickBarThemeHeight}" Margin="4,0,0,0" HorizontalAlignment="Left" Fill="{ThemeResource SystemControlForegroundBaseMediumLowBrush}" Visibility="Collapsed" />
                                                    <Thumb x:Name="VerticalThumb" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Width="8" Height="24" AutomationProperties.AccessibilityView="Raw" Background="{ThemeResource SystemControlForegroundAccentBrush}" DataContext="{TemplateBinding Value}" Style="{StaticResource SliderThumbStyle}" />
                                                </Grid>
                                            </Grid>
                                            <VisualStateManager.VisualStateGroups>
                                                <VisualStateGroup x:Name="CommonStates">
                                                    <VisualState x:Name="Normal" />
                                                    <VisualState x:Name="Pressed">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalThumb" Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlForegroundAccentBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalThumb" Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlForegroundAccentBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalThumb" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlForegroundAccentBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalThumb" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlForegroundAccentBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                    <VisualState x:Name="Disabled">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderContentPresenter" Storyboard.TargetProperty="Foreground">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalDecreaseRect" Storyboard.TargetProperty="Fill">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledChromeDisabledHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalTrackRect" Storyboard.TargetProperty="Fill">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledChromeDisabledHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalDecreaseRect" Storyboard.TargetProperty="Fill">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledChromeDisabledHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalTrackRect" Storyboard.TargetProperty="Fill">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledChromeDisabledHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalThumb" Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledChromeDisabledHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalThumb" Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledChromeDisabledHighBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TopTickBar" Storyboard.TargetProperty="Fill">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BottomTickBar" Storyboard.TargetProperty="Fill">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LeftTickBar" Storyboard.TargetProperty="Fill">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RightTickBar" Storyboard.TargetProperty="Fill">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                    <VisualState x:Name="PointerOver">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalTrackRect" Storyboard.TargetProperty="Fill">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalTrackRect" Storyboard.TargetProperty="Fill">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalThumb" Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightChromeAltLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalThumb" Storyboard.TargetProperty="Background">
                                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightChromeAltLowBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                </VisualStateGroup>
                                            </VisualStateManager.VisualStateGroups>
                                        </Grid>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>


                        <!-- Style for Volume Flyout used in Media Transport Controls -->

<Style x:Key="FlyoutStyle" TargetType="FlyoutPresenter">
                            <Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeMediumBrush}" />
                            <Setter Property="Padding" Value="0" />
                        </Style>


                    </Grid.Resources>

                    <Border x:Name="ControlPanel_ControlPanelVisibilityStates_Border">
                        <Grid x:Name="ControlPanelGrid" VerticalAlignment="Bottom" Background="Transparent" RenderTransformOrigin="0.5,0.5">
                            <Grid.RenderTransform>
                                <TranslateTransform />
                            </Grid.RenderTransform>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="*" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Border x:Name="ErrorBorder" Grid.ColumnSpan="3" Width="320" Height="96" HorizontalAlignment="Center" Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}" Visibility="Collapsed">
                                <TextBlock x:Name="ErrorTextBlock" Margin="12" Style="{StaticResource MediaTextBlockStyle}" TextWrapping="WrapWholeWords" />
                            </Border>
                            <Border x:Name="MediaTransportControls_Timeline_Border" Grid.Row="1" Grid.Column="1" Background="Transparent">
                                <Grid x:Name="MediaTransportControls_Timeline_Grid">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition />
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition />
                                        <RowDefinition Height="Auto" />
                                    </Grid.RowDefinitions>
                                    <Slider x:Name="ProgressSlider" Height="33" MinWidth="80" Margin="12,0" VerticalAlignment="Center" IsThumbToolTipEnabled="False" Style="{StaticResource MediaSliderStyle}" />
                                    <ProgressBar x:Name="BufferingProgressBar" Height="4" Margin="0,2,0,0" VerticalAlignment="Top" IsHitTestVisible="False" IsIndeterminate="True" Visibility="Collapsed" />
                                    <Grid x:Name="TimeTextGrid" Grid.Row="1" Height="15" Margin="12,0">
                                        <TextBlock x:Name="TimeElapsedElement" Margin="0" HorizontalAlignment="Left" Style="{StaticResource MediaTextBlockStyle}" Text="00:00" />
                                        <TextBlock x:Name="TimeRemainingElement" HorizontalAlignment="Right" Style="{StaticResource MediaTextBlockStyle}" Text="00:00" />
                                    </Grid>
                                </Grid>
                            </Border>
                            <Border x:Name="LeftSidePlayBorder" Grid.Row="1" Grid.Column="0" Visibility="Collapsed">
                                <AppBarButton x:Name="PlayPauseButtonOnLeft" Margin="0" VerticalAlignment="Center" Style="{StaticResource AppBarButtonStyle}">
                                    <AppBarButton.Icon>
                                        <SymbolIcon x:Name="PlayPauseSymbolLeft" Symbol="Play" />
                                    </AppBarButton.Icon>
                                </AppBarButton>
                            </Border>
                            <Border x:Name="MediaTransportControls_Command_Border" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center">
                                <CommandBar x:Name="MediaControlsCommandBar" Margin="0,0,0,24" Style="{StaticResource CommandBarStyle}">
                                    <CommandBar.PrimaryCommands>
                                        <AppBarButton x:Name="StopButton" Icon="Stop" MediaTransportControlsHelper.DropoutOrder="1" Style="{StaticResource AppBarButtonStyle}" Visibility="Collapsed" />
                                        <AppBarButton x:Name="RewindButton" MediaTransportControlsHelper.DropoutOrder="2" Style="{StaticResource AppBarButtonStyle}" Visibility="Collapsed">
                                            <AppBarButton.Icon>
                                                <FontIcon Glyph="" />
                                            </AppBarButton.Icon>
                                        </AppBarButton>
                                        <AppBarButton x:Name="CastButton" MediaTransportControlsHelper.DropoutOrder="7" Style="{StaticResource AppBarButtonStyle}">
                                            <AppBarButton.Icon>
                                                <FontIcon Glyph="" />
                                            </AppBarButton.Icon>
                                        </AppBarButton>
                                        <AppBarButton x:Name="ZoomButton" MediaTransportControlsHelper.DropoutOrder="6" Style="{StaticResource AppBarButtonStyle}">
                                            <AppBarButton.Icon>
                                                <FontIcon Glyph="" />
                                            </AppBarButton.Icon>
                                        </AppBarButton>
                                        <AppBarButton x:Name="AudioTracksSelectionButton" Icon="Character" MediaTransportControlsHelper.DropoutOrder="5" Style="{StaticResource AppBarButtonStyle}" Visibility="Collapsed" />
                                        <AppBarButton x:Name="PlayPauseButton" MediaTransportControlsHelper.DropoutOrder="11" Style="{StaticResource AppBarButtonStyle}">
                                            <AppBarButton.Icon>
                                                <SymbolIcon x:Name="PlayPauseSymbol" Symbol="Play" />
                                            </AppBarButton.Icon>
                                        </AppBarButton>
                                        <AppBarButton x:Name="CCSelectionButton" MediaTransportControlsHelper.DropoutOrder="9" Style="{StaticResource AppBarButtonStyle}" Visibility="Collapsed">
                                            <AppBarButton.Icon>
                                                <FontIcon Glyph="" />
                                            </AppBarButton.Icon>
                                        </AppBarButton>
                                        <AppBarButton x:Name="VolumeMuteButton" MediaTransportControlsHelper.DropoutOrder="10" Style="{StaticResource AppBarButtonStyle}">
                                            <AppBarButton.Flyout>
                                                <Flyout x:Name="VolumeFlyout" FlyoutPresenterStyle="{StaticResource FlyoutStyle}">
                                                    <StackPanel Orientation="Horizontal">
                                                        <AppBarButton x:Name="AudioMuteButton" Margin="12" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource AppBarButtonStyle}">
                                                            <AppBarButton.Icon>
                                                                <SymbolIcon x:Name="AudioMuteSymbol" Symbol="Volume" />
                                                            </AppBarButton.Icon>
                                                        </AppBarButton>
                                                        <Slider x:Name="VolumeSlider" Width="{ThemeResource MTCHorizontalVolumeSliderWidth}" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center" IsThumbToolTipEnabled="False" Value="50" />
                                                        <TextBlock x:Name="VolumeValue" Width="24" Margin="12" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource MediaTextBlockStyle}" Text="{Binding ElementName=VolumeSlider, Path=Value}" />
                                                    </StackPanel>
                                                </Flyout>
                                            </AppBarButton.Flyout>
                                            <AppBarButton.Icon>
                                                <SymbolIcon x:Name="VolumeMuteSymbol" Symbol="Volume" />
                                            </AppBarButton.Icon>
                                        </AppBarButton>
                                        <AppBarButton x:Name="FullWindowButton" MediaTransportControlsHelper.DropoutOrder="8" Style="{StaticResource AppBarButtonStyle}">
                                            <AppBarButton.Icon>
                                                <SymbolIcon x:Name="FullWindowSymbol" Symbol="FullScreen" />
                                            </AppBarButton.Icon>
                                        </AppBarButton>
                                        <AppBarButton x:Name="FastForwardButton" MediaTransportControlsHelper.DropoutOrder="3" Style="{StaticResource AppBarButtonStyle}" Visibility="Collapsed">
                                            <AppBarButton.Icon>
                                                <FontIcon Glyph="" />
                                            </AppBarButton.Icon>
                                        </AppBarButton>
                                        <AppBarButton x:Name="PlaybackRateButton" MediaTransportControlsHelper.DropoutOrder="4" Style="{StaticResource AppBarButtonStyle}" Visibility="Collapsed">
                                            <AppBarButton.Icon>
                                                <FontIcon Glyph="" />
                                            </AppBarButton.Icon>
                                        </AppBarButton>
                                    </CommandBar.PrimaryCommands>
                                </CommandBar>
                            </Border>
                        </Grid>
                    </Border>

                    <VisualStateManager.VisualStateGroups>

                        <!-- ControlPanel Visibility states -->
                        <VisualStateGroup x:Name="ControlPanelVisibilityStates">
                            <VisualState x:Name="ControlPanelFadeIn">
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ControlPanel_ControlPanelVisibilityStates_Border" Storyboard.TargetProperty="Opacity">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="0" />
                                        <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="1" />
                                    </DoubleAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="ControlPanelFadeOut">
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ControlPanel_ControlPanelVisibilityStates_Border" Storyboard.TargetProperty="Opacity">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="1" />
                                        <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0" />
                                    </DoubleAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ControlPanel_ControlPanelVisibilityStates_Border" Storyboard.TargetProperty="IsHitTestVisible">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="False" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <!-- ControlPanel Visibility states -->

                        <!-- Media state visual states -->
                        <VisualStateGroup x:Name="MediaStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="Buffering">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BufferingProgressBar" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Loading">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BufferingProgressBar" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <DoubleAnimation Storyboard.TargetName="ProgressSlider" Storyboard.TargetProperty="Opacity" To="0" Duration="0" />
                                    <DoubleAnimation Storyboard.TargetName="MediaControlsCommandBar" Storyboard.TargetProperty="Opacity" To="0" Duration="0" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Error">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ErrorBorder" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled">
                                <Storyboard />
                            </VisualState>
                        </VisualStateGroup>
                        <!-- Media state visual states -->

                        <!-- Audio Selection Button visibility states -->
                        <VisualStateGroup x:Name="AudioSelectionAvailablityStates">
                            <VisualState x:Name="AudioSelectionAvailable">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="AudioTracksSelectionButton" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="AudioSelectionUnavailable" />
                        </VisualStateGroup>
                        <!-- Video volume visibility states -->

                        <!-- Closed Captioning Selection Button visibility states -->
                        <VisualStateGroup x:Name="CCSelectionAvailablityStates">
                            <VisualState x:Name="CCSelectionAvailable">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="CCSelectionButton" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="CCSelectionUnavailable" />
                        </VisualStateGroup>
                        <!-- Closed Captioning visibility states -->

                        <!-- Focus states -->
                        <VisualStateGroup x:Name="FocusStates">
                            <VisualState x:Name="Focused">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="FocusVisualWhite" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
                                    <DoubleAnimation Storyboard.TargetName="FocusVisualBlack" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Unfocused" />
                            <VisualState x:Name="PointerFocused" />
                        </VisualStateGroup>
                        <!-- Focus states -->
                        <VisualStateGroup x:Name="MediaTransportControlMode">
                            <VisualState x:Name="NormalMode" />
                            <VisualState x:Name="CompactMode">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LeftSidePlayBorder" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="TimeTextGrid" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="MediaTransportControls_Command_Border" Storyboard.TargetProperty="(Grid.Column)">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="2" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="MediaTransportControls_Command_Border" Storyboard.TargetProperty="(Grid.Row)">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="1" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="MediaControlsCommandBar" Storyboard.TargetProperty="Margin">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="0" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlayPauseButton" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>

                        <!-- PlayPause states -->
                        <VisualStateGroup x:Name="PlayPauseStates">
                            <VisualState x:Name="PlayState" />
                            <VisualState x:Name="PauseState">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlayPauseSymbolLeft" Storyboard.TargetProperty="Symbol">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Pause" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlayPauseSymbol" Storyboard.TargetProperty="Symbol">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Pause" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <!-- VolumeMute states -->
                        <VisualStateGroup x:Name="VolumeMuteStates">
                            <VisualState x:Name="VolumeState" />
                            <VisualState x:Name="MuteState">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="AudioMuteSymbol" Storyboard.TargetProperty="Symbol">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Mute" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="VolumeMuteSymbol" Storyboard.TargetProperty="Symbol">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Mute" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <!-- FullWindow states -->
                        <VisualStateGroup x:Name="FullWindowStates">
                            <VisualState x:Name="NonFullWindowState" />
                            <VisualState x:Name="FullWindowState">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FullWindowSymbol" Storyboard.TargetProperty="Symbol">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="BackToWindow" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

It looks good now.

2017 – MVP award – Great Start

On 1st of Jan 2017 I got a mail from Microsoft stating that I have been awarded an MVP award for my community contributions for Windows Development.
mvp

I am honoured to have been nominated and to have been awarded this. For a developer in Microsoft technologies this is the highest honour (sort of). Thank you @WindowsDev and @MVPAward

I think 2016 was a mixed bag and technically I did little to have deserved this honour. I have been a contributor to the UWP Community Toolkit and that was the primary driver. I am sure I did substantially more from 2011 – 2015 but hey maybe that’s what it took 🙂 still feels surreal

Going ahead I will try to blog more about #UWP and #UWPDev in 2017. Happy new year all

Json Formatter Edge Extension #Windows10

The only reason I install Chrome now and again is to use extensions like Json Formatter extension. Recently Microsoft released Windows 10 Anniversary update.
Edge browser on this update supports extensions. This list of extensions on store is still limited. The team is analysing the performance and publishing them accordingly.

Can’t wait any longer. I started by cloning Json-Formatter repo and used Microsoft Edge Extension Toolkit to port the extension to work on Edge.

You can download the repo and install the extension after enabling Extension developer mode from ‘about:flags’edge-extension-developer-featuresload-extensions

The repo is on Github https://github.com/hermitdave/json-formatter-edge along with instructions

An example geonames json service can be found here

By default the json is displayed like this on Edge browser.Screenshot (43)

With the extension installed, it is displayed at belowScreenshot (42)Screenshot (44)

To port another extension use the Micosoft Edge Extension Toolkit available on Store

Customise Scroll Bar in #uwp

Update (20th April 2017):

Sample app with horizontal scrollbar customisation can be found at https://github.com/hermitdave/ScrollBarCustomisation

 

Controls like ListView / GridView contain a ScrollViewer which hosts scrollable content. The ScrollViewer contains two ScrollBar controls one for each scroll type (horizontal and vertical).

Getting to a control’s template can be painful.. why not just head to
Default control styles and templates and download the templates you need

If you want to do it the hard way..
You can get to control’s ScrollViewer by right clicking on it and click Edit Template > Edit a Copy
Screenshot (39)

Looking at the template you can see the ScrollViewer but there’s little you can do right now.

<ControlTemplate TargetType="ListView">
    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
        <ScrollViewer x:Name="ScrollViewer" AutomationProperties.AccessibilityView="Raw" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" TabNavigation="{TemplateBinding TabNavigation}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
            <ItemsPresenter FooterTransitions="{TemplateBinding FooterTransitions}" FooterTemplate="{TemplateBinding FooterTemplate}" Footer="{TemplateBinding Footer}" HeaderTemplate="{TemplateBinding HeaderTemplate}" Header="{TemplateBinding Header}" HeaderTransitions="{TemplateBinding HeaderTransitions}" Padding="{TemplateBinding Padding}"/>
        </ScrollViewer>
    </Border>
</ControlTemplate>

You need to go and Edit the template for ScrollViewer next.
You can right click on the ListView, tap Esc key which then moves focus on ScrollViewer. Click control’s Border and right click > Edit Template > Edit a copy

<ControlTemplate TargetType="ScrollViewer">
    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
        <Grid Background="{TemplateBinding Background}">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <ScrollContentPresenter x:Name="ScrollContentPresenter" Grid.ColumnSpan="2" ContentTemplate="{TemplateBinding ContentTemplate}" Margin="{TemplateBinding Padding}" Grid.RowSpan="2"/>
            <ScrollBar x:Name="VerticalScrollBar" Grid.Column="1" HorizontalAlignment="Right" IsTabStop="False" Maximum="{TemplateBinding ScrollableHeight}" Orientation="Vertical" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{TemplateBinding VerticalOffset}" ViewportSize="{TemplateBinding ViewportHeight}"/>
            <ScrollBar x:Name="HorizontalScrollBar" IsTabStop="False" Maximum="{TemplateBinding ScrollableWidth}" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{TemplateBinding HorizontalOffset}" ViewportSize="{TemplateBinding ViewportWidth}"/>
            <Border x:Name="ScrollBarSeparator" Background="{ThemeResource SystemControlPageBackgroundChromeLowBrush}" Grid.Column="1" Grid.Row="1"/>
        </Grid>
    </Border>
</ControlTemplate>

In one instance I needed the ScrollBar to not render over the content. You can see that the ScrollViewer ScrollViewerPresenter has both ColSpan and RowSpan set. Just get rid of it so there is no overlay.
In Another instance I needed to customise it further. I needed Horizontal ScrollBar (to be of same height as the ListView) and I needed only the Left and Right buttons. So start by Setting ColSpan / RowSpan on ScrollBar as needed
Now lets get to ScrollBar template to customise it further.

<ControlTemplate x:Key="HorizontalIncrementTemplate" TargetType="RepeatButton">
    <Grid x:Name="Root">
        <Grid x:Name="HorizontalRoot" IsHitTestVisible="False">
            <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Rectangle x:Name="HorizontalTrackRect"
                        Grid.ColumnSpan="5"
                        Margin="0"
                        StrokeThickness="{ThemeResource ScrollBarTrackBorderThemeThickness}"
                        Fill="{ThemeResource SystemControlPageBackgroundChromeLowBrush}"
                        Stroke="{ThemeResource SystemControlForegroundTransparentBrush}" />
            <RepeatButton x:Name="HorizontalSmallDecrease"
                        Grid.Column="0"
                        MinHeight="12"
                        IsTabStop="False"
                        Interval="50"
                        Margin="0"
                        Template="{StaticResource HorizontalDecrementTemplate}"
                        Width="12"
                        VerticalAlignment="Center" />
            <RepeatButton x:Name="HorizontalLargeDecrease"
                        Grid.Column="1"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        IsTabStop="False"
                        Interval="50"
                        Template="{StaticResource RepeatButtonTemplate}"
                        Width="0" />
            <Thumb x:Name="HorizontalThumb"
                        Grid.Column="2"
                        Background="{ThemeResource SystemControlForegroundChromeHighBrush}"
                        Template="{StaticResource HorizontalThumbTemplate}"
                        Height="12"
                        MinWidth="12"
                        AutomationProperties.AccessibilityView="Raw" />
            <RepeatButton x:Name="HorizontalLargeIncrease"
                        Grid.Column="3"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        IsTabStop="False"
                        Interval="50"
                        Template="{StaticResource RepeatButtonTemplate}" />
            <RepeatButton x:Name="HorizontalSmallIncrease"
                        Grid.Column="4"
                        MinHeight="12"
                        IsTabStop="False"
                        Interval="50"
                        Margin="0"
                        Template="{StaticResource HorizontalIncrementTemplate}"
                        Width="12"
                        VerticalAlignment="Center" />
        </Grid>
        <Grid x:Name="HorizontalPanningRoot" MinWidth="24">
            <Border x:Name="HorizontalPanningThumb"
                    VerticalAlignment="Bottom"
                    HorizontalAlignment="Left"
                    Background="{ThemeResource SystemControlForegroundChromeDisabledLowBrush}"
                    BorderThickness="0"
                    Height="2"
                    MinWidth="32"
                    Margin="0,2,0,2"/>
        </Grid>
        <Grid x:Name="VerticalRoot" IsHitTestVisible="False">
            <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Rectangle x:Name="VerticalTrackRect"
                        Grid.RowSpan="5"
                        Margin="0"
                        StrokeThickness="{ThemeResource ScrollBarTrackBorderThemeThickness}"
                        Fill="{ThemeResource SystemControlPageBackgroundChromeLowBrush}"
                        Stroke="{ThemeResource SystemControlForegroundTransparentBrush}" />
            <RepeatButton x:Name="VerticalSmallDecrease"
                        Height="12"
                        MinWidth="12"
                        IsTabStop="False"
                        Interval="50"
                        Margin="0"
                        Grid.Row="0"
                        Template="{StaticResource VerticalDecrementTemplate}"
                        HorizontalAlignment="Center" />
            <RepeatButton x:Name="VerticalLargeDecrease"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Height="0"
                        IsTabStop="False"
                        Interval="50"
                        Grid.Row="1"
                        Template="{StaticResource RepeatButtonTemplate}" />
            <Thumb x:Name="VerticalThumb"
                        Grid.Row="2"
                        Background="{ThemeResource SystemControlForegroundChromeHighBrush}"
                        Template="{StaticResource VerticalThumbTemplate}"
                        Width="12"
                        MinHeight="12"
                        AutomationProperties.AccessibilityView="Raw" />
            <RepeatButton x:Name="VerticalLargeIncrease"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        IsTabStop="False"
                        Interval="50"
                        Grid.Row="3"
                        Template="{StaticResource RepeatButtonTemplate}" />
            <RepeatButton x:Name="VerticalSmallIncrease"
                        Height="12"
                        MinWidth="12"
                        IsTabStop="False"
                        Interval="50"
                        Margin="0"
                        Grid.Row="4"
                        Template="{StaticResource VerticalIncrementTemplate}"
                        HorizontalAlignment="Center" />
        </Grid>
        <Grid x:Name="VerticalPanningRoot" MinHeight="24">
            <Border x:Name="VerticalPanningThumb"
                    VerticalAlignment="Top"
                    HorizontalAlignment="Right"
                    Background="{ThemeResource SystemControlForegroundChromeDisabledLowBrush}"
                    BorderThickness="0"
                    Width="2"
                    MinHeight="32"
                    Margin="2,0,2,0"/>
        </Grid>
    </Grid>
</ControlTemplate>

In my case I only needed the two RepeatButton named HorizontalSmallDecrease and HorizontalSmallIncrease. Comment out the remaining controls (VerticalTrackRect, VerticalLargeDecrease, VerticalThumb, VerticalLargeIncrease)
For smoother scroll, modify RepeatButton’s Interval property, I set it to 5 rather than 50.

For further customisation I even created Attached Property that resizes the RepeatButton (the visibility is controlled by the ScrollBar so setting width while a hack works well.

public static class ScrollBarHelper
{
    static double InitialWidth = Double.MinValue;

    public static readonly DependencyProperty DCustomiseScrollBehaviourProperty =
    DependencyProperty.RegisterAttached("CustomiseScrollBehaviour", typeof(bool),
    typeof(ScrollBarHelper), new PropertyMetadata(false, OnCustomiseScrollBehaviourPropertyChanged));

    public static void SetCustomiseScrollBehaviour(DependencyObject d, bool value)
    {
        d.SetValue(DCustomiseScrollBehaviourProperty, value);
    }

    public static bool GetCustomiseScrollBehaviour(DependencyObject d)
    {
        return (bool)d.GetValue(DCustomiseScrollBehaviourProperty);
    }

    private static void OnCustomiseScrollBehaviourPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        if (!(bool)e.NewValue)
            return;

        var control = d as ScrollBar;
        if (control != null)
        {
            Observable.FromEventPattern<RoutedEventArgs>(control, "Loaded")
                .SubscribeOn(TaskPoolScheduler.Default)
                .ObserveOn(CoreDispatcherScheduler.Current)
                .Subscribe(args =>
                {
                    ProcessPosition(args.Sender);
                });

            Observable.FromEventPattern<ScrollEventArgs>(control, "Scroll")
                .Throttle(TimeSpan.FromMilliseconds(50))
                .SubscribeOn(TaskPoolScheduler.Default)
                .ObserveOn(CoreDispatcherScheduler.Current)
                .Subscribe(args =>
                {
                    ProcessPosition(args.Sender);
                });
        }
    }

    private static void ProcessPosition(object sender)
    {
        ScrollBar sb = (sender as ScrollBar);

        RepeatButton rbLeft = (RepeatButton)sb.FindDescendantByName("HorizontalSmallDecrease");
        RepeatButton rbRight = (RepeatButton)sb.FindDescendantByName("HorizontalSmallIncrease");

        if (rbLeft == null || rbRight == null)
            return;

        double pos = sb.Value;

        if (pos == 0 && InitialWidth == Double.MinValue)
        {
            InitialWidth = rbLeft.Width;
        }

        if (Math.Abs(pos - sb.Minimum) <= 15)
        {
            // hide the left scroll button
            rbLeft.Width = 0;
        }
        else if (Math.Abs(pos - sb.Maximum) <= 15)
        {
            // hide right scroll button
            rbRight.Width = 0;
        }
        else
        {
            rbLeft.Width = rbRight.Width = InitialWidth;
        }
    }
}

You could directly attached to ScrollBar’s Loaded / Scroll events but I used Reactive Extensions to throttle scroll changes as I wanted scroll experience to not degrade. The result.. not perfect but close to what I needed

GeoFence and #WinRT API

For some reason I find myself doing some Windows Phone 8.1 development in Silverlight.. I know its a dead end and all the rest but I am working on a small app and Silverlight API was more mature at least for Windows Phone 8.1. One of the things I was adding was GeoFencing. GeoFencing was introduced to Windows Phone 8.1 WinRT API and some of it was exposed to Silverlight API (whoever made the decision on what APIs were available in WinRT and what in Silverlight needs to be shot.. at least made to feel real pain.

The way you set it up is you create GeoFence instances and add them.. System managed associated with your app. The app can access it from foreground or background.. nice right ? The constructor for GeoFence states that it requires IGeoshape along with an identifier at the very least.. IGeoshape is an enum which has possible values of Point, Circle, BoundingBox and Path. The constructor for GeoFence explicitly states now and again that the IGeoshape has to be a valid GeoCircle.. I know documentation can be wrong.. I mean why would you go through the hassle of create an Interface and passing it again if you enforce explicit type ?

I was wrong.. I tried it both the Silverlight and through WinRT API.. nope documentation is correct.. the API though designed well has shite implementation 😐 So what next ?

Well DIY. Here is my implementation.. Create a Rect instance with NorthWest X1, Y1 and SouthEast and X2 Y2 and monitor the change in geo position. Check if the new point is within Rect or not.. easy peasy.. well it works too.. Here is my implementation.

 

public class GeoMonitoringService
{
    Geolocator _locator = null;
    Dictionary<GeoSite, Rect> _locationRectangles = null;

    DataService _dataService = null;

    public event RoutedPropertyChangedEventHandler<GeomonitorStateChangedEventArgs> GeomonitorStateChanged;
    public bool lastState = false;

    public void Initialise(DataService dataService)
    {
        _locator = new Geolocator();
        _locator.DesiredAccuracy = PositionAccuracy.High;
        _locator.MovementThreshold = 1;
        _locator.ReportInterval = Convert.ToUInt32(TimeSpan.FromSeconds(5).TotalMilliseconds);

        this._locationRectangles = new Dictionary<GeoSite, Rect>();

        this._dataService = dataService;

        if (this._dataService?.SiteDictionary?.Count > 0)
        {
            foreach (var site in this._dataService.SiteDictionary.Values)
            {
                Rect r = new Rect(new Point(site.Latitude1, site.Longitude1), new Point(site.Latitude2, site.Longitude2));
                this._locationRectangles.Add(site, r);
            }
        }

        _locator.PositionChanged += GPSPositionChanged;
    }

    private void GPSPositionChanged(Geolocator sender, PositionChangedEventArgs args)
    {
        var geoPoint = args.Position.Coordinate.Point;
        Point p = new Point(geoPoint.Position.Latitude, geoPoint.Position.Longitude);

        KeyValuePair<GeoSite, Rect>? matchKVP = null;
        foreach (var entry in this._locationRectangles)
        {
            if (entry.Value.Contains(p))
            {
                matchKVP = entry;
                break;
            }
        }

        if (matchKVP.HasValue)
        {
            if (!lastState)
            {
                lastState = true;
                this.GeomonitorStateChanged?.Invoke(this, new RoutedPropertyChangedEventArgs<GeomonitorStateChangedEventArgs>(null, new GeomonitorStateChangedEventArgs(true, matchKVP.Value.Key)));
            }
        }
        else
        {
            if (lastState)
            {
                lastState = false;
                this.GeomonitorStateChanged?.Invoke(this, new RoutedPropertyChangedEventArgs<GeomonitorStateChangedEventArgs>(null, new GeomonitorStateChangedEventArgs(false, null)));
            }
        }
    }
}