XamarinForms – Overriding a ContentPage with a custom PageRenderer on Android

The short version:

If you want to have default behavior on all platforms except for Android. Do the following

  • Create your content page with all of it’s goodies
  • Create a custom PageRenderer
  • In the OnElementChanged function
    • Cast the Context property of the renderer to the Activity type associated
    • Take that value and execute the SetContentView method while passing in your new view!

The awesome story version:

I’m building a Xamarin Forms application which has a default implementation in most platforms and a special snowflake behavior on Android. While working through the Xamarin documentation I realized that custom renderers were the way to go.

The default behavior for all platforms is performed through a WebView, which has some custom logic when pages are navigated. While the functionality still works, it doesn’t feel seamless. However, in Android there is already native functionality that really improves the user experience, so I wanted to make sure that if I was on the Android platform, I would not display that web view and I would go straight to the native view.

While navigating through the sea of googlementation(http://bfy.tw/7ljK), I saw various examples on how to do stuff with custom renderers and I walked through them one by one hoping to hit my use case. Most search results demonstrated how to replace the view when doing a custom renderer on a control element with the SetNativeControl method. However, this was a page renderer. So it was time for experiments!

The behavior that I got was that the default view was still rendering and my custom view was not. If commented out the content on the default ContentPage then it would successfully output the custom view. However that in turn meant no default behavior. There was no winning! It was like arguing with a cat!

Hours later, I was able to debug and discover that I had access to the Android Activity. Using the activity, I was able to replace the main content with the SetContentView method like so.

...
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(FooPage), typeof(FooPageRenderer))]
namespace FooApp.Droid.Renderer
{
    public class FooPageRenderer : PageRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs e)
        {
            base.OnElementChanged(e);
            var activity = this.Context as MainActivity;
            var newView = activity.FindViewById(Resource.Layout.foo);
            activity.SetContentView(newView);
        }

    }
}

I hope this helps other people save a few hours in their quests of building awesome things.

Keep on coding on friends!

C# – How the Null Conditional Operator works with Nullable types

The short answer:

The null conditional operator also unwraps the nullable variable. So after the operator, the “Value” property is no longer needed.

ex:

DateTimeOffset? startAt;
...
System.Writeline(startAt?.TimeOfDay);

The longer story:

I had a scenario with a Nullable DateTimeOffset and I was trying to perform something like the following.

DateTimeOffset? startAt;
...
public DateTime? StartDate { get { return startAt.Value.DateTime; } }

As I tested, I immediately ran into a situation where that date was null, the program threw an exception and I needed to null check it. So I thought I wanted to use that latest, hottest stuff that Microsoft had to offer in C#.

The null conditional operator. 

I changed my code to the following

public DateTime? StartDate { get { return startAt?.Value.DateTime; } }

But instead it just got angry with me and for whatever reason I wasn’t looking at the obvious clues. I immediately ran off to search the interwebs on how to use this operator with Nullable types and found a solution that said to use

public DateTime? StartDate { get { return startAt.GetValueOrDefault().DateTime; } }

However, that wouldn’t give me the desired results I wanted. I want a null value back, if my original value was null. It would instead give me the default value of a DateTime. So off I went to go back to old school methods of making it happen and I change the code to look something like this

public DateTime? StartDate { get { return (startAt == null) ? null : startAt.Value.DateTime; } }

However, the compiler was still angry, giving me the error “Type of conditional expression cannot be determined because there is no implicit conversion between ‘<null>’ and ‘DateTime’. Which further confused me because when I then broke it down to basic techniques

public DateTime? StartDate { get { if (startAt == null) { return null; } else { return startAt.Value.DateTime; } } }

This worked. So I reset my frame of mind, performed a few more searches with newer clues and I discovered that to make the conditional operator work I had to provide an explicit conversion on the null return value to make it look like the following

public DateTime? StartDate { get { return (startAt == null) ? (DateTime?)null : startAt.Value.DateTime; } }

Then I created a few tests to break down each example and confirm my expected outcomes. When I created a simple example just to revisit using the null conditional operator one more time, I then finally noticed the output of the intellisense after typing the operator. This awesome operator also unwrapped the variable so that you could get straight to business.

I’m including the tests that I wrote to somewhat illustrate how my mind was processing this problem as I went through it. The tests were really just my scratch pad, for anyone who’s concerned about the best ways of writing unit tests.

Bonne nuit!

using System;
using Xunit;

namespace Test.Stuff
{
    public class Nullables
    {
        [Fact]
        public void Test_ConditionalOperator_NullValue()
        {
            DateTimeOffset? foo = null;

            var result = (foo == null) ? (DateTime?)null : foo.Value.Date;
            Assert.Null(result);
        }

        [Fact]
        public void Test_IfStatements_NullValue()
        {
            DateTimeOffset? foo = null;
            DateTime? result = null;

            if (foo == null) { result = null; } else { result = foo.Value.Date; }
            Assert.Null(result);
        }

        [Fact]
        public void Test_NullConditional_NullValue()
        {
            DateTimeOffset? foo = null;
            DateTime? result = null;

            result = foo?.Date;
            Assert.Null(result);
        }

        [Fact]
        public void Test_ConditionalOperator_WithValue()
        {
            DateTimeOffset? foo = new DateTimeOffset(2016, 09, 11, 01, 49, 00, TimeSpan.Zero);

            var result = (foo == null) ? (DateTime?)null : foo.Value.Date;
            Assert.Equal(2016, result.Value.Year);
            Assert.Equal(09, result.Value.Month);
            Assert.Equal(11, result.Value.Day);
            Assert.Equal(0, result.Value.Hour);
            Assert.Equal(0, result.Value.Minute);
        }

        [Fact]
        public void Test_IfStatements_WithValue()
        {
            DateTimeOffset? foo = new DateTimeOffset(2016, 09, 11, 01, 49, 00, TimeSpan.Zero);
            DateTime? result = null;

            if (foo == null) { result = null; } else { result = foo.Value.Date; }
            Assert.Equal(2016, result.Value.Year);
            Assert.Equal(09, result.Value.Month);
            Assert.Equal(11, result.Value.Day);
            Assert.Equal(0, result.Value.Hour);
            Assert.Equal(0, result.Value.Minute);
        }

        [Fact]
        public void Test_NullConditional_WithValue()
        {
            DateTimeOffset? foo = new DateTimeOffset(2016, 09, 11, 01, 49, 00, TimeSpan.Zero);
            DateTime? result = null;

            var blah = foo?.DateTime;

            result = foo?.Date;
            Assert.Equal(2016, result?.Year);
            Assert.Equal(09, result?.Month);
            Assert.Equal(11, result?.Day);
            Assert.Equal(0, result?.Hour);
            Assert.Equal(0, result?.Minute);
        }
    }
}

Jenkins & Git & Windows Server – oh my!

Got a weird freezing issue in Jenkins when attempting to pull the tags from a git repository. Turns out that the credential manager was the interactive windows popup and it just locked the build process. The fix was as simple as going into the following location and removing the credential helper

[Git Install Folder]\mingw64\etc\gitconfig

Example from this
[credential]
helper = manager

to this
[credential]
# helper = manager

Much respect to all inventors of #QUALCOMM #WhyWait Invent-off!

WhyWait - Contestants

The last episode of the invent-off is available to view!

Regardless of the results, I feel privileged to have had an opportunity to work with all of those incredibly talented and passionate inventors. The competition was really fun and I finally got to dip my toes into IOT/IOE.

http://whywait.kinja.com/and-we-have-a-winner-the-invent-off-finale-is-here-1723341729

As promised, I created a video tutorial on preparing your own Arduino Yun’s to run AllJoynJS and I plan on creating more content for other aspiring inventors to build amazing things.

http://www.ninjacrab.com/alljoyning/setting-up-an-arduino-yun-for-alljoynjs/

Success!! Ok and some failures with AllJoynJS #WhyWait #QuallComm #AllJoyn

DSC_0019

The third episode of the hackathon has been published. As the deadline of the contest is looming, I’m definitely creating synthetic stress upon myself. There are awesome advantages to using AllJoyn in our project, but also a few problems created by friction of complexity. Regardless, we’ll push through!

http://whywait.kinja.com/what-bright-idea-will-the-teams-create-in-the-whywait-1718090122

I know the episodes are short, but I hope you guys enjoy them!

In the meantime, I wanted to share this post with those who run into the nefarious message while working with AllJoynJS, the Arduino Yun and any input output pins. If you see the following message

ALERT: Error: Failed to configure digital output pin: 022
ajs_io.c:211
light_00409bf0_0002 light strict preventsyield
global .js:10 preventsyield

It’s possible that you just need to run the following script

/usr/bin/lininoio start

To get things going again.

The comprehensive setup will come real soon, I promise! In the meantime, enjoy!

Shocking surprise in the 2nd Episode of the #WhyWait #Qualcomm challenge!

Episode two has been released and this “voted” component thing truly is a shocker! I’m already losing sleep without any additional features, but I suppose you play with the hand that you are dealt with.

More things to read up on and in the end, that means more content to create tutorials for!

Enjoy all!

http://whywait.kinja.com/meet-the-innovators-competing-to-win-the-whywait-inven-1717554111

Episode 1 of the #WhyWait Hackathon is available to watch!

The first episode of the hackathon is out. I’m not entirely aware of how much of the build it will show as the episodes are brief, but fear not! Once it’s all done, I will create tutorials and walkthroughs!

http://whywait.kinja.com/watch-two-teams-of-innovators-compete-in-the-whywait-i-1716856087

Otherwise, enjoy!

Selected to be part of the #Qualcomm #WhyWait Hackathon!

WhyWait Medium

Recently I was selected to be a contestant of a hackathon sponsored by Qualcomm to build basically any green fielded idea pairing an Arduino Yun and an Android phone. The first episode will be aired online in the next week or so. Please support me by spreading the word, to any nerd!

I’m super excited for this opportunity to play mad scientist with some IOT/IOE devices and hope we win!

Following the series, I plan on making various tutorials on how we accomplished what we did and frameworks involved from the coding side. I’ll try to do my best to explain the fabrication side, but that’s what I’m leaning on my team mates for!

Resurrecting Persistent Windows

Well, my amazing Wife gave me the green light on ordering 3x Dell P2415Q 4K monitors. So I enthusiastically connected them all via DisplayPort on my NVidia 970GTX card on my desktop and low and behold the windows are exhibiting the crazy re-arranging behavior!

Thus, I’m reviving the project and now since I’ll be able to test it immediately(Instead of building it at home, running it on my work desktop, shipping log files home back home to diagnose), I should be able to improve it even more.

Stay tuned for updates!