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!

Sunday, July 6, 2014

Linear motion with XAML and Storyboard animations!

One of the remarkably cool things with XAML is how easy it is to set up animations.  Most of the time I just need to animate some opacity.  A quick web search, and boom!  I’m in business.

But for some reason, animating motion (like: move my text box off screen) is a pain.  Here are the important steps.

  1. Give your object an x:Name (“obj”).  Let’s also assume that the object is a custom object of type local:JokeControl.  The word local refers to a XML namespace definition.
  2. Add a RenderTransform with a TranslateTransform child to your object
  3. Add in a storyboard and give it an x:Naem
  4. Set the storyboard’s TargetName to the object name
  5. Set the storyboard’s TargetProperty using the weird ‘path’ syntax: (local:JokeControl.RenderTransform).(TranslateTransform.X)

And then in code, just call “.Begin()” on the animation!

Here are the actual bits of code:

From the XAML file:

Notes Code
Set up the ‘local’ namespace so that my user control (which is in C# namespace ‘Jokes’) can be used. xmlns:local="using:Jokes"
Create the animation in the resource section.  The storyboard (animation) is named uiAnimateJokeOut, and actually has more bits than this.

    <Storyboard x:Name="uiAnimateJokeOut" >
            From="0.0" To="400.0" Duration="0:0:0.5"

The object I want to animate needs a RenderTransform; the particular render transform I need is a Translate transform.  I don’t have to name it because I’ll find it by type.

<local:JokeControl x:Name="uiJokeControl" Grid.Column="1" >
        <TranslateTransform X="0" >

C# code to start the animation uiAnimateJokeOut.Begin();

While I’m at it – I wanted the joke control to move right to go off screen, and then come back.  And I wanted to change the joke when it’s off the screen.  I did this by making two animations (one for joke OUT and one for joke IN).  I then added a .Completed on the OUT to swap jokes and to bring the joke back in.

The code looks like this:

uiAnimateJokeOut.Completed += (s, args) => { DoRandom(); uiAnimateJokeIn.Begin(); };

Thursday, June 23, 2011

Multicast -- it's not really hard at all

So, I've been trying to learn some multicast programming. What I really want, of course, is to run a program on one computer in my local network (otherwise known as "home"), and then discover it on another computer.

So I figure multicast is the answer. And, in truth, it is! It's great! It's even simple! But every single silly blog post about it -- especially from the vendors -- makes it sound hard.

Here's the real deal on Multicast. It's just UDP. You send it to an IP address like The exact values are pretty unimportant. And the port is just a port, like 9883. The server (listener) is just a hair more complex: bind to the same port, and set the "multicast join" socket option to the IP address.

Tada! Packets sent by the sender go to the listener. And you can reply from the server back to the sender by looking at the remote IP address.