Coffeehouse Thread

28 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

Universal Windows App Programming -- not all it's cracked up to be.

Back to Forum: Coffeehouse
  • User profile image
    Dr Herbie

    A small rant ...

    Well I decided to dive in and take a look at re-writing one of my older Phone Apps as a Universal app for Windows 10.  Nothing too complicated, just a stopwatch and countdown timer.

    Came to the point of alerting the user.  Well, I thought, if it's able to vibrate the device that should happen.  So I looked up the code and found VibrationDevice.GetDefault().  Perfect, I thought, if there's a vibration device I'll use it and if there isn't a device I won't:

    VibrationDevice.GetDefault()?.Vibrate(TimeSpan.FromSeconds(1));

    Nope.

    If you call VibrationDevice.GetDefault() on a Windows device, it doesn't return null, it throws an exception. 

    An exception!?

    So trying to figure out if there is a vibration device available when there isn't one is an exceptional circumstance worthy of an error?

    FFS, framework team, for things to be properly 'universal' you're going to have do fix querying for device capabilities better than this! Let me know when the frameworks finished properly.

    I feel slightly better for getting that off my chest.  Thanks.

     

     

     

     

  • User profile image
    RamblingGeek​UK

    VibrationDevice testVibrationDevice = VibrationDevice.GetDefault();

    https://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn611853.aspx

  • User profile image
    Dr Herbie

    @RamblingGeekUK: Run that code on your desktop Windows 10 device and it will throw an exception. That is not very 'universal'.

     

     

  • User profile image
    Ian2

    Hopefully that is just an oversight and not typical of the Universal framework in general.

     

  • User profile image
    Bas

    Same thing when you're working with IOT stuff. You have to try-catch stuff like initializing SPI because when you're running your app on a non-IOT device and it has no SPI device, it'll just throw an exception, no obvious way to query it.

  • User profile image
    bondsbw

    Use the ApiInformation class to determine if the capability you need is registered on that device.  For your code:

    if (ApiInformation.IsTypePresent("Windows.Phone.Devices.Notification.VibrationDevice"))
    {
        VibrationDevice.GetDefault()?.Vibrate(TimeSpan.FromSeconds(1));
    }

  • User profile image
    cbae

    , bondsbw wrote

    Use the ApiInformation class to determine if the capability you need is registered on that device.  For your code:

    1
    2
    3
    4
    if (ApiInformation.IsTypePresent("Windows.Phone.Devices.Notification.VibrationDevice"))
    {
        VibrationDevice.GetDefault()?.Vibrate(TimeSpan.FromSeconds(1));
    }

    That seems like a ugly way to test a device's capabilities. Would that cause an exception if you wrapped the type in typeof().FullName if the device in question didn't have vibration capability?

  • User profile image
    magicalclick

    I guess the moral of the story is, do a capability checks for all the devices that you want to use in a self-build manager. Then, do those commands. I don't fault this kind of design pattern. Might as well have a nice resource report in your app for error reporting.

    Btw, what does that ? do?

    Leaving WM on 5/2018 if no apps, no dedicated billboards where I drive, no Store name.
    Last modified
  • User profile image
    kettch

    @magicalclick: The ? allows code execution to stop at the first null it finds without blowing up because a parent object is null and it's trying to find the child property.

    https://msdn.microsoft.com/en-us/library/dn986595.aspx

    In this case it replaces having to do something like this:

    var device = VibrationDevice.GetDefault();
    
    if(device != null)
    {
        device.Vibrate(TimeSpan.FromSeconds(1));
    }

     

  • User profile image
    bondsbw

    @cbae:  Actually you're right, I think there is a better way:

    if (ApiInformation.IsApiContractPresent("Windows.Phone.PhoneContract", 1, 0))
    {
        VibrationDevice.GetDefault()?.Vibrate(TimeSpan.FromSeconds(1));
    }

    Many applications would call that up front in order to decide whether to expose features.

    For anyone interested, here's a link describing what APIs that contract/version contains: https://msdn.microsoft.com/en-us/library/windows/apps/dn706176.aspx  Look to the left for more contracts.

  • User profile image
    Charles

    ?. is C# 6.0's Null Propagation Operator. As mentioned, it replaces to the need to write null checks explicitly (if x == null) return; ...

    x?.DoSomething() won't throw a NullReferenceException when x is null, nothing will happen, just like when you test for null explicitly and do nothing when the object in question is in fact null...

    Simple, but elegant language addition.

    There is nothing wrong with the pattern of testing for capabilities before trying to do something in a UWP. It's the precise reason this API exists...:) You don't expect a Desktop PC or Laptop to vibrate, so make a simple check to see if the device your code is running on supports the feature you're programming (you don't expect all Windows 10 devices to have a vibration facility, so program with this fact in mind).

    Now, one could argue that the underlying system could do theses checks automatically, but then what would the system do in the cases where the facility is not present? That is, you would want to program a UWP to react to missing device-specific capabilities, accordingly (in this case, if the device can't vibrate, change the background color of the current UI page or whatever makes sense in your design.).

    C

  • User profile image
    bondsbw

    , cbae wrote

    Would that cause an exception if you wrapped the type in typeof().FullName if the device in question didn't have vibration capability?

    No, I just tried it, that works fine.

  • User profile image
    cbae

    , bondsbw wrote

    *snip*

    No, I just tried it, that works fine.

    That's good. I don't like passing names of types as strings, which has similar issues that the new nameof() function solves vis-à-vis object property names. It would be nice if the nameof() function worked with types too, but I guess it's not that tedious to append the ".FullName" to the typeof() function call. 

  • User profile image
    Bas

    , Charles wrote

    ?. is C# 6.0's Null Propagation Operator.

    It is also known as The Greatest Thing Ever.

  • User profile image
    vesuvius

    , Bas wrote

    *snip*

    It is also known as The Greatest Thing Ever.

    ++

  • User profile image
    dotMorten

    >That seems like a ugly way to test a device's capabilities.

    @cbae:The API you're using are not part of the standard common universal API - you're using extended APIs that only come on some devices. I'm assuming you added a specific reference to the Mobile SDK, which means you now get access to extra APIs - but when doing that you now have to be careful and ensure you only call those APIs on the platforms that has those APIs.

    So in other words this has absolutely nothing to do with getting a default device - you don't even get that far. You're calling code that basically doesn't exist.

  • User profile image
    Dr Herbie

    I'm resurrecting this thread as I now find I have some time to write a wrapper to hide the (IMHO) appalling API design that is ApiInformation.IsApiContractPresent. If the wrapper is good enough, I'll open source it.

     

    So, opinions on how to design the library, taking the 'VibrationDevice' as the starting point. Which seems like the better API:

    1. A static class where you just call

    VibrationDevice.Vibrate(TimeSpan.FromSeconds(2));

    And if there is a vibration device it will be used, but if there isn't nothing will happen (optional return value indicating whether it happened or not).

    2. The same format as the MS VibrationDevice class where you call

    var device = VibrationDevice.GetDefault();
    device.Vibrate(TimeSpan.FromSeconds(2));

    But without the nasty exception throwing, using a NullObject replacement to perform the empty implementation.

     

    I'm currently leaning to option 1 as it seems cleaner to call (being just a hardware interface) rather than having to create an instance using a static factory method.

    Other opinions are sought.

  • User profile image
    magicalclick

    @Dr Herbie: Is it possible just to write a simple thing like public static <T> GetDevice(<T> device){} and just use that instead?

    Leaving WM on 5/2018 if no apps, no dedicated billboards where I drive, no Store name.
    Last modified

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.