Tuesday, April 19, 2016

The program that went “ding”!

I started with a simple requirement: build a timer program that, after 25 minutes, does a little “ding” sound, using the Universal Windows platform.

Making a sound is simple

The “make a sound” is simple enough; the fundamental API is the MediaElement, and it has a Play method that takes a stream.  Universal is a little awkward with streams; the final code:
  • Get the Windows.ApplicationModel.Package
    .Current.InstalledLocation
  • from the InstalledLocation do a GetFileAsync passing in the normal  @“\Assets\Sounds\ding.wav” format.  Note my use of the @ in front of the quote.
  • given the file do an OpenAsync()
  • On the MediaElement do a SetSource() of the stream
  • Finally, you can Play().

Except when you don’t have focus

Unfortunately this runs into two problems, both discovered by an end user.  Firstly, it won’t ding when the app isn’t the foreground. Secondly, it doesn’t ding when the app is minimized.  You might think this is the same problem, but it’s not.
To work in the background you need to set the AudioCategory of the MediaElement to BackgroundCapableMedia.  This won’t work until you’ve also registered some callbacks to control the sound level; this is a requirement of the Windows OS.  Since all my sounds are short, I cheated, and the callbacks do nothing.
As a short aside, the other option is Communications; it’s the only other setting that works in the background.  However, my ding sounds are too short and don’t work properly.  Existing music would be faded out so users could hear the sounds, but that happed too slowly; by the time my sound was faded in, it was already over.  [Update: I'm also told by People At Microsoft that the Communications settings is wrong, wrong, wrong unless you are actually a communications app]

Convergence problems

Except that this is not fully converged.  For the phone you have to add callbacks to Windows.Media.SystemMediaTransportControls (getting the current one with GetForCurrentView()); the two callbacks you need are PropertyChanged and ButtonPressed.  On Desktop, you add callbacks to Windows.Media.MediaControl and you need a callback for about six different things.

App Manifest Woes

This still doesn’t work; you need to update the Package.appmanifest to declare that you do background audio.  Here the blogs are simply wrong, and present XAML that works until you try to compile for RELEASE mode.
The correct XAML is:
<Extensions>
  <Extension Category="windows.backgroundTasks"
               
EntryPoint="DesktopCompanion.App">
    <BackgroundTasks>
      <Task Type="audio" />
    </BackgroundTasks>
  </Extension>
</Extensions>

Note the EntryPoint item; the blog posts about this all mention a StartPage, which is wrong in this context.
But we’re still not done.

Hidden windows, quiet timers

So we have a great solution, and the app will ding when it’s minimized.  We can even prove it; run the app, wait for the ding, run minimized, and wait for the ding again.
That test turns out to be flawed.  IF you start the timer and minimize it before it has a change to ding the first time, it won’t ding in the background.  You have to make a foreground sound first.
Solution: add  a very short quiet ding right when the app starts. 
I also discovered that setting the ding to be looping would solve the problem, but it seemed like the first go-around would not play and then the second and subsequent ones would.

Oh, so you like listening to music?

There’s one problem I haven’t solved.  If you do all this on the phone, the “ding” will automatically stop your music from running.  On full (desktop/laptop/tablet) Windows, the music will simply fade out, let the ding happen, and then come back.  On the phone it stops dead and doesn’t resume.
This might not be bad, but the ding is actually optional; you can run in muted mode.  I normally run muted; otherwise it would distract by work mates.
Solution:
  • Add a DingSilentlyOnce() that can do the silent ding
  • Call it at startup unless the user has the app muted
  • Call it when the user switches out of muted mode (either by pressing the mute button or by selecting a sound to play)
This still doesn’t solve the problem where the ding will stop my background music on the phone.

Conclusion

Making things go ding is only slightly painful until you need it to actually work, at which point four different changes are needed, none of which are properly documented.

Saturday, April 16, 2016

Giant List: The Art of English Murder: Writers on Project Gutenberg

The Art of the English Murder (“As Seen on the BBC as “A Very British Murder”) traces the current love of a good mystery back through time.  In addition to occasionally writing about programming, I also enjoy a good mystery.

Project Gutenberg is an awesome source of public-domain books that volunteers have scanned and proofread.  Naturally, it contains many of the authors listed in the book!  All Gutenberg book are free, but you should consider donating.

In this list, I’ve put all of the authors from the book whose works are available from Project Gutenberg.  The author is listed first with a link to Wikipedia, then the Gutenberg page for the author, and then links to specific mentioned works.

Often an author is mentioned in several chapters; I’ve happily duplicated all entries.  Sometimes an author is presented without any specific (traceable) work.  In these cases, only the page to the authors works are presented.

Not all chapters include references to traceable writers; these are simply skipped.  The later chapter deal with more modern writers whose works aren’t yet out of copyright are are therefore not in Project Gutenberg.

Introduction

George Orwell: no listing

Thomas de Quincy: multiple entries including entries from the Lock and Key Library

Charles Dickens: multiple entries including  Bleak House

Dorothy L Sayers, creator of Lord Peter Whimsey : a single entry only; “Oxford Poetry” of which she’s the editor has has a single poem (and not a mystery)

Agatha Christie: two entries only

Margery Allingham: no entries

Ngaio Marsh: no entries

Graham Green: no entries

Chapter 1: A Connoisseur in Murder

Thomas de Quincy: multiple entries including Confessions of an English Opium Eater

Chapter 4: The Murder Circuit

Mary Shelley: multiple entries including Frankenstein, Frankenstein and  Frankenstein.

Elstree murder:

Thomas de Quincy: multiple entries

Thomas Carlyle:  multiple entries

Charles Dickens: multiple entries

Edward Bulwer-Lytton: multiple entries

Walter de la Mare: multiple entries

Sir Walter Scott: multiple entries

Chapter 6: True Crime

Shakespeare: multiple entries including Hamlet

Thomas de Quincy: multiple entries

Ann Radcliffe: multiple entries including The Mysteries of Udolpho

Jane Austen: multiple entries including Northanger Abbey

George Augustus Sala: entries for volumes 1 2 and 3 of The Strange Adventures of Captain Dangerous

Edward Bulwer-Lytton: multiple entries  including Pelham, or the Adventures of a Gentleman and Eugene Aram

Lytton Strachey: multiple entries including Eminent Victorians

Chapter 7: Charles Dickens

Charles Dickens: multiple entries  including Oliver Twist, exerpts from Household WordsBleak House

Newgate Calendar: entries for volume 1 and 2 of  The Newgate Calendar

Chapter 9: Stage Fright

Victoria and Albert Museum performance

Charles Dickens: multiple entries  including Bleak House

Chapter 11: Middle-Class Murderers and Medical Gentlemen

Thomas de Quincy: multiple entries including entries from the Lock and Key Library

Arthur Conan Doyle: multiple entries include Adventure of the Speckled Band

Chapter 13: Detective Fever

Wilkie Collins: multiple entries including Armadale and Moonstone

Charles Dickens: multiple entries 

Chapter 14: A New Sensation

Mary Elizabeth Braddon: multiple entries

Wilkie Collins: multiple entries including The Woman in White, Moonstone, Armadale

Dorothy L Sayers, creator of Lord Peter Whimsey : a single entry only; “Oxford Poetry” of which she’s the editor has has a single poem (and not a mystery) – and not The Gaudy Night, the book referenced in the chapter.

Sheridan le Fanu: multiple entries .  Sheridan is the research topic for detective Harriet Vane from Dorothy L. Sayer’s Gaudy Night.

Chapter 15: It is worse than a crime, Violet

Mary Elizabeth Braddon: multiple entries including Lady Audley’s Secret

Chapter 16: Monsters and Men

Robert Louis Stevenson: multiple entries including Doctor Jekyll and Mister Hyde 

Oscar Wilde: multiple entries including the Picture of Dorian Gray

Arthur Conan Doyle: multiple entries

Chapter 17: The Adventures of the Forensic Scientist

Arthur Conan Doyle: multiple entries including A Study in Scarlet and The Devil’s Foot

Eugène François Vidocq: multiple entries (all in French)

Completely missing from the book is my own favorite detective author, R. Austin Freemen: multiple entries including John Thorndkye’s cases

Chapter 18: Revelations of a Lady Detective

Andrew Forrester: a single entry which isn’t The Female Detective

Catherine Crowe: a single entry which isn’t The Adventures of Susan Hopley

Ann Radcliffe: multiple entries including The Mysteries of Udolpho 

Hans Christian Andersen: multiple entries none of which are really mysteries.  He’s mentioned as someone known by Catherine Crowe.

Charles Dickens: multiple entries but is just mentioned as a friend of Catherine Crowe

W. S. Hayward isn’t even part of Wikipedia or Project Gutenberg despite write Revelations of a Lady Detective

G. K. Chesterton: multiple entries including the Innocence of Father Brown

Chapter 19: the Women between the Wars

Agatha Christie: two entries only, neither of which is Murder is Easy or the Murder of Roger Ackroyd.

Edgar Wallace: multiple entries

Arthur Conan Doyle: multiple entries including Hound of the Baskervilles

John Buchan: multiple entries  including 39 steps and Greenmantle

E. W. Hornung: multiple entries  including several Raffles books.

Freeman Wills Crofts: one entry (the Pit Prop Syndicate)

G. K. Chesterton: multiple entries

Margery Allingham: no entries

Nicholas Blake: no entries

Chapter 20: The Duchess of Death

Agatha Christie: two entries only

Chapter 22: The Great Game

Dorothy L Sayers, creator of Lord Peter Whimsey : a single entry only; “Oxford Poetry” of which she’s the editor has has a single poem (and not a mystery)

Agatha Christie: two entries only

G. K. Chesterton: multiple entries

 Baroness Orczy: multiple entries

A. A. Milne: multiple entries including the Red House Mystery 

Ronald Knox: no entries

Arthur Conan Doyle: multiple entries

Charles Dickens: multiple entries

Wilkie Collins: multiple entries

Thomas de Quincy: multiple entries

Raymond Chandler: no entries

John Rhode (real name: Cecil Street): no entries

Ngaio Marsh: no entries

Chapter 23: Snobbery with Violence

Dorothy L Sayers, creator of Lord Peter Whimsey : a single entry only; “Oxford Poetry” of which she’s the editor has has a single poem (and not a mystery)

Colin Watson: no entries

Agatha Christie: two entries only

Val Gielgud: no entries

S. S. Van Dine: two entries under his real name as Willard Wright including Modern Painting: It’s Tendencies and Meanings but no mysteries.

Nicholas Blake: no entries

Ngaio Marsh: no entries

Edgar Wallace: multiple entries

Graham Green: no entries

Raymond Chandler: no entries

Chapter 24: The Dangerous Edge of Things

Dashiell Hammett: no entries

Raymond Chandler: no entries

Graham Green: no entries

Alfred Hitchcock: no entries

Postscript: the Decline of Murder

George Orwell: no entries

James Hadley Chase: no entries

Thomas de Quincy: multiple entries

Tuesday, January 26, 2016

XAML Binding a ComboBox to an Enum

Universal Apps: XAML Binding a ComboBox to an Enum

XAML sometimes has good news, and sometimes bad news for how easy we programmers can bind to types of lists.  Some "just work" and some are almost impossible.  The bad news is that most of the stackoverflow WPF solutions to binding a ComboBox to an enum don't work with Universal Apps.  The good news is that it's not actually hard to do.

The fundamentals are that
  1. You need to create a list of the enums.  A simple mechanism is something like Enum.GetValues(typeof(T)).Cast().ToList();
  2. XAML will happily bind a property of that list to a ComboBox ItemsSource
  3. Then bind the ComboBox SelectedItems to the an enum property

You will almost certainly want to display something a little nicer than just the enum values.  You can do this with a little IValueConverter.  It's possible to make a templated converter, so you can just pop in a standard class into your project.  The standard display XAML attribute isn't available for Universal, but it's trivial to make a small custom DisplayAttribute class. 

I've created a simple project with a nice helper classes; an entire sample project is now published on MSDN Samples pages along with complete instructions.






Saturday, October 3, 2015

Debugging your VisualState triggers

Windows 10 includes some the RelativePanel and new VisualState improvements to make it simpler to design “adaptive” displays.  But like all declarative languages, debugging is just simply painful.

To make the VisualState features work, you have to create a VisualStateManager in your grid (or similar); the VisualStateManager in turn as a VisualStateGroup; the VisualStateGroup has a set of VisualState items (you will always have two or more).  The VisualState in turn has a VisualState.StateTrigger (often an AdaptiveTrigger with a MinWindowsWidth) and VisualState.Setters to actually change your display.

Problem #1: if you mistype the name of your control, it’s just silently ignored.  It doesn’t even spit out a warning into the Output window.  If you are an inconsistent caser (like me), you’ll find this a rich productive bug farm.

Problem #2: the rules for the RelativePanel aren’t tricky, but you have to get used to them.  It’s tough to try to learn both the rules for RelativePanel while also learning how to make the AdoptiveTrigger work.

Problem #3: for a short while my C# project was set to “any CPU”.  It would “compile” and run with no warnings, and then run the last actual build.  All my “changes” would be completely ignored!

To fix your problems:

  1. Never set your project to “Any CPU”.  Yes, it used to be the awesome value, but now it’s the horrific value.  I don’t even know why they still include it as an option
  2. Never type your control names in the XAML designer.  Always do a cut-n-paste so that the name is guaranteed correct

Thursday, June 4, 2015

Data Binding -- good idea done badly, or bad idea implemented as well as can be hoped?

 The promise of data binding is that you can write your XAML UI code in one file, and then with a little bit of typing hook up the UI to your underlying data structures.  Which is great, until you have to do anything at all complex (e.g.,: I have a list of data, and I want a UI of all the data except for a subset of data that isn't right.

Worse, you get weird problems with data binding.  When you make a UserControl, you can just set up some public properties; the internals of your control bind to the properties, and everything is great.  Except you can't use a binding expression to set the values, and if you used the convenience this.DataContext = this in your constructor, you can't use binding to set common properties like 'Width' or 'Tags' any more.

Jerry Nixon has the answer in his Blog from 2013.

Short answer: use DependencyProperties and set (this.Content as FrameworkElement).DataContext = this; after you have this.InitializeComponent();'d.

Friday, May 15, 2015

Stupid Idea #692: The installed client has fewer features than the web client

So there I am, using my nice speedy Visual Studio program, happily editing and running code.  I want to use the new team planning features so I can pick my next task more rationally.  And what I discover is that it's horrible: the isn't really a way to "plan"; I can create a work item (but is that what I want to do?), and I can write a custom query to see my work items, but what I can't do is see some boxes on the screen and move them around.

Keep in mind that I use Trello for my hobby projects; it's awesome in its simplicity.  I can make new little card, and move them from column to column, and track what's going on.

So why is the expensive, heavy, full-featured Visual Studio so far behind the curve?  Why doesn't it have a nice graphical interface?  Where is the help for simple planning?

Answer: those are on the web, not in the full client.  In order to use them, I have to leave my nice productive environment, and go to a totally different web page.  And sign in.  with some credentials.  Which have to match the credentials I signed into Visual Studio with.  But there isn't a "go to the web" button.

Never force your customers to leave your product!  As soon as I have to type in a web address to go somewhere else, and sign in again, why wouldn't I just use Trello and skip the Microsoft solution entirely?

Saturday, March 14, 2015

An easy guide to installing using WIX

This tutorial is for everyone who just wants to build a simple installer using the WIX toolkit to generate a standard .MSI file. The sample has a couple of files; they get installed. A shortcut is added to the desktop. That’s it. You can read my sample, and be done in fifteen minutes, or you can wrestle your way through the maze of arcania that is the official documentation.

The first step is to install WIX; luckily it’s not hard. Go to the http://wixtoolset.org site and pick a published stable release. I used v3.9 R2 (stable). The second step is to make a directory, and dump my project files there. I used c:\temp\2015\wix, but you can use anything.

The project files is a dummy EXE, a really dummy DLL (it’s just some text), a dummy license file and a dummy help file.  There is also a .WXS WIX installer file and the BAT file that will generate a .MSI installer file. 

Edit the MyApp.msi file and make the following changes. They are detailed below, but here’s the general rule: everything with ‘myapp’ needs to be changed.

  1. Change all the GUIDs! Search for MYAPP-GUID and replace the guid. Seriously, this is critical. Note that every guid is different. There are three of them.
  2. Once you change the GUIDs, you can try the MakeInstall.bat file to make a .MSI installer file.
  3. Everywhere that there’s a MyApp in CamelCase, the string is visible to the user. This includes:
    • Product Name and manufacturer
    • Package description, comments and manufacturer
    • Property for the disk prompt (I don’t know when this will ever show up)
    • Directory to install to (which is always in the program files directory)
    • Shortcut name (the shortcut is installed on the desktop)
  4. Everywhere there’s a myapp in lowercase, it’s something that isn’t visible to the end-user
    • Media cab file (I don’t know where this is ever used)
    • File name and source for the myapp.exe, myapp.dll and more
    • The icon reference the app name
  5. Everywhere there’s a MYAPP that is all uppercase, it’s an ‘ID’. The WIX idea is that some IDs are actually chosen so that different parts of the system can refer to one another. Other ids are not like that, and have specific requirement (e.g., the icon id MUST end in .exe, which violates every principle of naming things that ever existed.

Run the MakeInstaller.bat file to make a .MSI file. There are two programs that get run, ‘candle’ and ‘light’. The BAT file will also clean up the useless intermediary files.

And like magic, you have a working installer!  Start by just using my files and just update the GUIDs in the MyApp.msi file and generate an MSI.  Then once you have a working installer and a workflow to make it, you can get fancy and install your programs and files into your preferred directories.

All my sample files are in this ZIP file.

Good luck!