Showing posts with label UI. Show all posts
Showing posts with label UI. Show all posts

Thursday, December 6, 2012

Apparent binding problems with NotSupportedException in PresentationFramework

I ran into this problem twice over the last couple weeks. Perhaps if I write an article, it'll help my future self (and just perhaps someone else) not spend so much time on it...

I put together a simple WPF form with a ListView. The ListLiew's View contained a GridView with columns bound to a POCO's properties. This was all done in XAML. In the constructor, I created an ObservableCollection to contain the objects and set it to the ListView's ItemsSource property. An event fired when interesting things happened. The event handler created the POCO object, set its properties and added it to the collection.

Everything should have worked.

However, when items were added to the collection, the debug window reported:
A first chance exception of type 'System.NotSupportedException' occurred in PresentationFramework.dll
Over the years, I've found data binding to be a challenge to get working. Part of the problem is it's mostly silent when it fails. So, data simply doesn't show up where it's expected with no indication as to why. Because of this, I assumed this is where the problem lay and spent significant time trying to figure out what was happening.

After quite a while I realized the event handler was called from a non-UI thread. I changed the line that added objects to the collection from:
ListViewDetails.Add(detailData);
to:
Dispatcher.Invoke((Action)(() =>
    ListViewDetails.Add(detailData)));
and everything worked properly. A simple solution once I realized what was wrong.

It'd be really nice if the debug window would output the exception message and not just the type. This would have told me immediately what was wrong and I wouldn't have spent so much time going down a dead-end road.

Monday, February 21, 2011

Arduino notebook: 16x2 LCD display (Part 1)

As I experiment with my Arduino kit, I find I want an easy, self-contained way to display information. The system provides one easy method in the Serial object with its print functions to send things to the computer through the USB port. This works well in development phase when the computer is attached to the board. However, I want to be able to run the kit detached from the computer and still get feedback. When there's limited data, I can use LEDs. They can be on or off to provide one bit of information. Additionally, they can be blinked in various patterns to communicate more than one bit of data. However, this is more abstract than I want. It doesn't strike me as easy, either to program or to use. I just want to read something directly without resorting to Morse Code to get the information.

I also don't want to spend much money.

So, with these three requirements in mind, I searched around. It seemed an LCD display was the way to go, as I found a couple different options. The first is to connect the LCD directly to the Arduino kit. At about $10, it is an inexpensive choice. It requires a number of wires and a moderate amount of programming to drive the display. Yes, this meets the cost and self-contained requirements, but isn't as easy as I would like. The second option is a kit with one of these LCDs and support circuitry to allow me to simply hook power, ground and a single data line to my Arduino. It uses the same Serial object to display information as the computer uses to receive data via USB. So, it satisfies the easy requirement much better, is more self-contained than the bare LCD, and at $25, still doesn't break the bank.

Upon further investigation, the support circuitry turns out to be an Arduino. I'm pretty sure this controller is sitting idle, spinning around doing nothing, most of the time. In addition to getting an LCD display, I believe this option in essence gives me a second Arduino that I might be able to reprogram to have additional features.

With all this going for it, I purchased this kit from SparkFun.com.

How to build a Sparkfun Serial Enabled LCD kit (LCD-10097)

Some assembly required

SparkFun Serial LCD kit - Step 1
(Click any of the pictures for a larger view.)

This is definitely a kit. It comes as seen above: a printed circuit board (PCB), some capacitors, a resistor, a crystal, a transistor, a potentiometer, a 28-pin chip, the LCD screen assembled on its own board and miscellaneous hardware. All this comes in a plastic bag in a box.

There were no instructions with the kit, nor could I find any online. To make up for this, the circuit board was well marked with silk screened values for the components and orientation marks for items that have to go in one way. Since I have put together many electronics kits over the years, I wasn't intimidated by this at all. If you are new to building kits, not having instructions might put you off a bit. However, don't let it. It's really pretty simple if you know how to solder. I'll outline what I did below to help you along.

As an overview, I basically installed the smallest components first and worked my way up to the larger ones.

SparkFun Serial LCD kit - Step 2
First, I installed the small, ceramic capacitors and the one resistor. There are two values for the capacitors. The capacitors labeled "220" go in the locations marked "22pF" on the PCB and "104" capacitors go in the locations marked "0.1uF". The resistor goes in the place marked for it. How these components are oriented on the board does not matter. Either lead can go in either hole.

SparkFun Serial LCD kit - Step 3
Next I added the transistor, crystal and electrolytic capacitor. The crystal can go in either way. The transistor and capacitor however need to be oriented correctly. For the transistor, make sure the flat side of the component matches the outline on the PCB. The capacitor has a light band with a minus sign in it running down one side. Make sure the lead next to this marking goes in the hole with the minus sign silk screened next to it on the PCB.

SparkFun Serial LCD kit - Step 4
Following this, I added the power/data connector and the potentiometer. These pretty much can only go in one way. Just match the components to the silk screen outlines on the PCB.

SparkFun Serial LCD kit - Step 5
After installing all the discrete components, I went to my local electronics store and picked up some DIP sockets. Generally, I don't like soldering IC chips onto boards directly. If I damage them with too much heat while soldering, or do something else stupid to cause them not to work, I don't want to go through the hassle of unsoldering all those connections to replace it. I've had to do that before and it's no fun.

The store didn't have any 28-pin DIP sockets in the narrow variety, but two 14-pin ones will sit nicely next to each other without any problems. On the PCB, note the silk screened outline. One end has a flat edge and the other end has a divot taken out. By convention, the edge with the divot marks the end where pin one goes. The sockets should also have one end that's flat with the other end notched. It's best to put them in with the same orientation as the silk screen. This makes things much less confusing. After the sockets are soldered in place, the chip can be inserted into it. The chip also has a notch in one end. Just line up all the notches and everything should be good.

SparkFun Serial LCD kit - Step 6
Finally, I did a good visual inspection of all my solder joints with a magnifying glass. The next step involves soldering the two boards together. Once this is done, it will be very hard to take them apart, so I wanted to be sure everything looked good.

There are three primary things to look for:
  1. Solder bridges. This is when solder spans two pads when it shouldn't. This is particularly easy to do on the pins for the IC sockets, but they can happen anywhere.
  2. Cold or missing solder joints. When working down a row of IC pins, it's easy to accidentally miss one. A cold joint is when one part of the joint, either the PCB pad or the component leg isn't hot enough to melt the solder but the other one is. Solder will flow onto one but not the other. Both cold joints and missing joints can cause intermittent or unreliable operation.
  3. Solder splatters. Sometimes solder will splatter or drop onto the board where it shouldn't be. Make sure there isn't any messy blobs anywhere. If you do find one, typically they'll just scratch off pretty easily.

After the visual inspection, I soldered the header to the LCD's PCB. Then I placed a small piece of cardboard between the two PCBs to function as a spacer. I placed the controller's PCB on the other side of the header's pins and made sure the two boards were parallel. I wrapped a bit of scrap wire around the assembly to hold them together while I soldered the two end pins. Once they were soldered, I took the wire off and finished soldering the rest of the pins to the controller board. When all the pins were done, I removed the cardboard and declared myself finished with the construction phase.

Batteries not included

Now that I had the physical assembly done, the next step was to hook it up to the Arduino. I went to the oracle of all things technical, Google. Unfortunately, with a moderate amount of searching, I didn't find any definitive instructions regarding what to do next. I found some forum postings that alluded to using the Serial object and some others that said to just hook it up, but didn't give any details.

I figured I probably couldn't hurt anything too badly with a bit of guess work. The connector for the LCD was clearly marked with 5V, Gnd and Rx, so I connected the red wire to the 5V pin, black wire to the Gnd pin and the Rx wire to the Tx pin on the Arduino. Typically in serial communication, transmit on one device goes to receive on the other. With the normal trepidation that I always have turning on a kit for the first time, I plugged in the USB cable.

The backlight came on and no smoke escaped. Well, that's a good first step. The SparkFun site points to some documentation on github, but it only talks about command sequences to control the LCD, it doesn't talk about how to talk to the LCD. It presupposes you know how to do that. I found a library that seemed to imply it worked with this kit, but didn't outright say it did. When I tried using some of the code from it, I got nothing. At this point I didn't know if it was a software problem or a hardware problem. I turned everything off, unconnected the LCD and took a magnifying glass to the kit. I looked at all the solder joints I could. Unfortunately, most were in the middle where I couldn't see. I examined all the legs on the chip going into the socket to make sure none of them got folded up underneath the package instead of going into the socket. They all looked good. I hooked everything back up and tried again. Nothing. I tried more searching online to see if I could find more information. Nothing. Arg. Frustrated, I set it aside for a week.

When I came back to it, I rechecked all the hardware I could with the magnifying glass. I plugged it in and tried writing to it. Same result as before. The backlight came on but I couldn't get it to display anything. Looking at the library code, it seemed a bit suspect, but even if it was wrong, I thought I should still see something. I searched more online but found no new information. One last time I decided to take a look at the kit before contacting customer support. And then it hit me. Pin one was in the wrong position. I couldn't believe it, I'd stupidly put the chip in backwards. I pulled the chip out and put it in the correct way. This time when I applied power, it showed a splash screen. Oh, much, much better.

I uploaded a program that I expected to put some data on the screen and it worked. Well, sort of. That code that looked suspect in the library I used didn't work properly. I suspect it was for some other serial controller with a different command set. I threw together some code based on the manufacturer's documentation on github and suddenly it worked properly. Woo, hoo!

Lessons learned

  1. If you build this kit, expect to see a splash screen on power up. This will tell you if the board works or not, independent of serial communication.
  2. Make sure to get some sockets for the chip. I'm sure glad I did. It would have been a nightmare if I'd accidentally soldered the chip in backwards and then had to desolder first the header and then the chip itself to correct the mistake.
  3. If I ever build another one, I will get a plug for the header. This would allow the two boards to plug together rather than be soldered together. A ribbon cable could also be placed between them for more flexibility with mounting.

That's about it for this write up. Next for this project is to figure out the best way to communicate with it. I need to look at the library to see if I was using it wrong or if it really is designed for a different unit. After that, I plan to investigate reprogramming the LCD's controller to investigate using it for additional processing tasks.

Monday, January 31, 2011

Arduino notebook: an RGB LED and the color wheel (Part 3)

In my last article, I demonstrated use of a potentiometer to control the hue of an RGB LED. In the HSV color space, the hue is one of three parameters controling the color. The other two are saturation and value. With a single control, there isn't a way to vary the other two parameters to give us a greater color range. In this article, I show one technique to control any of the three color variables.

Designing the input

But first, a short design discussion. In order to change what the potentiometer does, we need some method to change its mode of operation. I toyed with several ideas. My preferred method was three buttons: one button puts it in hue change mode, the second button puts it in saturation change mode and finally, the third button puts it in value change mode. The user would press a button and twist the potentiometer, setting that button's associated value. I like this because there is a one-to-one mapping between the buttons and the mode. It makes it easy for the user to understand and use. The problem: I only have two buttons.

My next idea was no button pressed changes hue, one button pressed changes saturation and the other button pressed changes the value. However, as I thought this through, I realized this would not give the user a nice flow between modes since every time one of the buttons was released, the hue mode would be entered, setting it to whatever value the potentiometer was in for the end of the last mode. This would cause the colors to jump around as modes changed and the un-pressed mode, hue, would have to be changed last. This clearly would not work very well.

After further thought, I hit upon the idea of using one button to cycle through the three modes with each button press and using the other button to enter that mode (or in other words, activate the potentiometer). Sort of like one button controls a menu and the other selects and deselects that menu option. To implement this, two additional LEDs are needed to indicate the mode and a third LED to indicate whether the potentiometer is enabled or not. This allows switching between modes without changing the output of the LED until the mode is selected. When the mode is exited, the LED would not change color as it would have in the previous scenario.

I implemented this design. However, after building it, I didn't like it since a binary readout is used to indicate the mode. I considered this sub-optimal from a usability standpoint. How many people can read binary numbers? In addition to the usability issue, it required three LEDs in addition to the switches, increasing the parts count and clutter on the breadboard. It worked but just seemed pretty clunky.

As I thought about it some more, I realized I could use the buttons directly in a binary pattern to select the mode and simply use a short delay before entering the mode. In other words, press and hold one button to change hue. Press and hold the other button to change saturation. Press and hold both buttons to change the value. I like this. It will reduce the parts count and eliminate a level of abstraction in the user interface; the buttons will directly control the mode. This is what I'll present below.

Hardware changes

Starting with the last circuit with in the previous article, I added two switches, two resistors and some jumpers. If you look at the schematic, pins 12 and 13 are connected to ground through a resistor when the switch is open. This means these two pins are normally in the LOW state when digitalRead is called with their pin numbers. When the button is closed, they are connected to the 5V side and become HIGH. The resistor puts a load on the circuit when the button is closed. If the resistor is removed, a direct short between ground and power exists when the button closes; not a good thing to do.

That's it. Pretty simple circuit changes.RGB LED color wheel with HSV controls
Click the image for a larger view or here for a schematic.

Software changes

The software changes are a bit more involved. First, the simple part, I added two declarations for the pins. The next change is a semi-advanced technique, but first a bit of analysis.

There are two buttons. For each button, the software needs to time how long the user has pressed it and, when they have held it down long enough, switch into active mode. To do this, each button requires a timer and a memory of the last button state. The code is the same for both, but the memory to track their status needs to be separate.

To facilitate this type of design, where there are two sections of memory with the same functions working on it, I used something called a class. Put simply, a class associates data with code. To create a class, start with the class keyword followed by the name of the class. This is the name you as a programmer decide to call it. Since this class contains the state information for a mode switch, I called the class ModeSwitchState.

Next, I defined the state information tracked for each switch. This includes the pin the switch is connected to, a timer to track when the last change was made to the switch's state and the switch's last value (i.e. was it pressed or not). These three things are what are called private variables, as indicated by the private keyword. This means nothing outside of functions defined in the class can access their values. The big, technical term for this is data encapsulation. All that means is it's harder to accidentally change the wrong thing because the only things that can get to the memory is this one class.

After I defined the private memory, I created two functions that any code can use. The first is what's called the constructor. This simply means it's the function that is called when a new variable of this type is created. In this case, the constructor takes a parameter to indicate the Arduino pin the rest of the functions will use. Since the pin variable is private, this is the only way to set its value. The idea is you create a variable of this class type for each button to be controlled. The constructor also sets initial values for the other variables and calls pinMode for the pin it reads.

Finally, I wrote a function to read the current value of the pin and, if it's different from the last value, reset the timer and the last value read variables. It then returns true if the button is pressed and the difference between the timer and the current time is greater than 500 ms. Otherwise it will return false.

That's it for the definition of this class. Next, I created two variables of this class type, called modeSwitch1 and modeSwitch2. The constructor is called with the values of the pin assignment previously defined.

And that's it for the advanced stuff. All the other changes are in the loop function.

First the loop gets the current mode state of each switch. Remember, since this is calling the function on the class, all the timer code is neatly tucked away out of sight from the main processing loop. All we have to do now is worry about getting the current value as defined by the readModeSwitch function. That's done by the first two lines.

Next I check to see if either of the switches are currently active. If so, then the potentiometer is read. Following this, either hue, saturation or value is changed to the pot's value based on which combination of switches are pressed. The case where both switches are pressed needs to be checked first, followed by the test for a single switch. If neither of these conditions are met, then the other switch must be pressed and its associated value changed.

Finally, after all this, the RGB color is computed and the LED is set to that color.

If neither switch is pressed, then nothing happens, the loop exits and immediately begins again.

Here's the final code.
int ledPins[] = { 11, 9, 10 };
int analogPin = 0;
int modeBit0pin = 12;
int modeBit1pin = 13;

int hueValue = 0;
double satValue = 1.0;
double lumValue = 1.0;

class ModeSwitchState
{
  private:
    int pin;
    long timer;
    boolean lastValue;

  public:
    ModeSwitchState(int switchPin)
      : pin(switchPin), timer(0), lastValue(false)
    {
      pinMode(pin, OUTPUT);
    }
    
    boolean readModeSwitch()
    {
      boolean curValue = digitalRead(pin) == HIGH;
      if (curValue != lastValue)
      {
        lastValue = curValue;
        timer = millis();
      }
      return curValue && ((millis() - timer) > 500);
    }
};

ModeSwitchState modeSwitch1(modeBit0pin), modeSwitch2(modeBit1pin);

void setup()
{
  pinMode(analogPin, INPUT);
  
  for(int i = 0; i < 3; i++)
    pinMode(ledPins[i], OUTPUT);
}

void loop()
{
  boolean mode1enabled = modeSwitch1.readModeSwitch();
  boolean mode2enabled = modeSwitch2.readModeSwitch();
  
  if (mode1enabled || mode2enabled)
  {
    int analogValue = analogRead(analogPin);

    if (mode1enabled && mode2enabled)
        hueValue = map(analogValue, 0, 1024, 0, 360);
    else if (mode1enabled)
        satValue = analogValue / 1024.0;
    else
        lumValue = analogValue / 1024.0;
  
    byte* colors = hsvToRgb(hueValue, satValue, lumValue);
    setColor(ledPins, colors);
  }
}

void setColor(int* led, const byte* color)
{
  for(int i = 0; i < 3; i++)
    analogWrite(led[i], 255-color[i]);
}

byte rgb[3];
byte* hsvToRgb(int h, double s, double v)
{
        // Make sure our arguments stay in-range
        h = max(0, min(360, h));
        s = max(0, min(1.0, s));
        v = max(0, min(1.0, v));
        if(s == 0)
        {
                // Achromatic (grey)
                rgb[0] = rgb[1] = rgb[2] = round(v * 255);
                return rgb;
        }
        double hs = h / 60.0; // sector 0 to 5
        int i = floor(hs);
        double f = hs - i; // factorial part of h
        double p = v * (1 - s);
        double q = v * (1 - s * f);
        double t = v * (1 - s * (1 - f));
        double r, g, b;
        switch(i)
        {
                case 0:
                        r = v;
                        g = t;
                        b = p;
                        break;
                case 1:
                        r = q;
                        g = v;
                        b = p;
                        break;
                case 2:
                        r = p;
                        g = v;
                        b = t;
                        break;
                case 3:
                        r = p;
                        g = q;
                        b = v;
                        break;
                case 4:
                        r = t;
                        g = p;
                        b = v;
                        break;
                default: // case 5:
                        r = v;
                        g = p;
                        b = q;
        }
        rgb[0] = round(r * 255.0);
        rgb[1] = round(g * 255.0);
        rgb[2] = round(b * 255.0);
        
        return rgb;
}

Conclusion and downloads

That's about all I'm going to do with the RGB LED for now. The source code for this and the past two articles can be downloaded here:
In the next article I will talk about the joys and sorrows of building a simple LCD kit to use with the Arduino.

Friday, October 23, 2009

Canceling application shutdown in WPF

I hate "Are you sure" type dialog boxes. Gratuitous use of them in software makes me want to do violence to whoever thought it was a good idea to put it in. That said, there are a few times where they make sense. For example, the application I'm working on now controls an instrument that may have some expensive, hard to replace, chemistry in it. Stopping the application while the instrument is in use may result in moderate financial loss, so in this case, it does make sense to alert the user to a possible undesired outcome and make sure they really want to proceed with the action.

The WPF Window class has a Closing event that fires when the window is closed. This event has an argument containing a Cancel property with a false default value. Setting this property to true inhibits the closing of the window. When this happens on the application’s MainWindow, this closing cancellation behavior applies to the application as a whole.

Some time ago, our application had code put in to pop up an “Are you sure?” style dialog and set the event's property as appropriate. The problem was it worked for some pathways through the code but not others. The lot fell to me to investigate. There are four ways to close the application: the Alt-F4 key, the task bar's Close option, the Close button in the window's title bar and an Exit menu option. All the methods worked except the Exit menu.

Digging into the code, the Exit method menu called the Shutdown method on the Application.Current object. This seemed like a reasonable thing to do and I went looking elsewhere for the problem. After spending time verifying there wasn't anything else odd in our code I came back to this method. On a hunch, I changed this to calling the Close method on Application.Current.MainWindow. This fixed the problem. I'm not sure why, but apparently the Shutdown method does something to inhibit the normal message processing of open windows.

I know this is typical behavior and it fixes my application for now, but from a design standpoint, I'm not too sure I like this. It seems like application level shutdown code in the Window is at the wrong layer. The Application class has an Exit event that's analogous to the Window's Close event however, this does not allow canceling the operation. In my opinion, the Application class should have an Exiting event with a Cancel property on the argument, similar to the Window class' Closing event.

In any case, if your application does not call the Closing event as you expect, first check to see how it's shutdown.

(25-June-2012: Minor edit for clarity.)

Friday, June 26, 2009

How to display tool tips in WPF DataGrid text column

Like many people before me, while using the DataGrid from the WPFtoolkit, I recently had a requirement to display text nicer than the default. First, the default is simply to truncate the text like so:

I needed the truncated text to have ellipses after it and have a ToolTip showing the entire text. Something like this:

I did a lot of searching the web and didn't find anything straight-forward and elegant. I found things that intimated using styles in XAML might work, although nothing directly addressing what I wanted to do. Furthermore, I found others saying XAML styles won't work at all for cell level changes along with some ugly hacks where, inside the LoadingRow method, they walked back up the VisualTree to change the cell style in code. My search was confounded by the fact that there are a number of different DataGrid components, three by Microsoft (WinForms, WPF and Silverlight) and several by other 3rd party vendors. All have issues doing this very basic thing and all with different workarounds.

After spending the better part of a day researching and testing various possible solutions, I found a comment on a Silverlight forum with the idea of using a DataGridTemplateColumn descendant to handle the new needs. I started to adapt the example code from Silverlight to WPF and thought, "There must be an easier way." Since the existing DataGridTextColumn already did much of what was in this example, I went off to look at its source code. While browsing through it, I found a protected virtual method called GenerateElement that apparently is a factory for the cells' display. On a hunch, I created a descendant of this column type and overrode this one method, changing the properties of the returned value as needed.

Amazingly, it worked the first time. So, to add my own workaround to the mix that's found on the web, here is the class I created:
public class DataGridToolTipTextColumn : DataGridTextColumn
{
    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        var result = (TextBlock)base.GenerateElement(cell, dataItem);
        result.TextTrimming = TextTrimming.CharacterEllipsis;
        ApplyBinding(result, FrameworkElement.ToolTipProperty);
        return result;
    }

    // Copied from DataGridTextColumn because it's not protected there either. Seems like it should be.
    internal void ApplyBinding(DependencyObject target, DependencyProperty property)
    {
        var binding = Binding;
        if (binding == null)
            BindingOperations.ClearBinding(target, property);
        else
            BindingOperations.SetBinding(target, property, binding);
    }
}
The GenerateElement method simply calls the base class and typecasts the return value to a TextBlock. For the moment this is safe since the base class has the type hard coded. The TextTrimming property is then set for CharacterEllipsis and the ToolTip property is bound to the same value as the Text property. This class is twice as long as it needs to be because the ApplyBinding method that exists in the base class is marked internal rather than protected, so I simply made a copy of it for use here.

In my usage, this DataGrid is only to display information; editing is turned off. I haven't checked to see if this would cause any issues in edit mode.

Related material

In all this searching, I did find a couple good resources:
  • Samuel Moura has a 4 part series doing some pretty intensive DataGrid styling and templating: Introduction, Custom Styling, Playing with Columns and Cells and TemplateColumns and Row Grouping.
  • The Tranxition Developer Blog has a good article on adding dependency properties to the TextBlock type. Unfortunately, this doesn't seem to work for TextBlocks that are in another control's VisualTree.
  • This Silverlight thread is what gave me the idea for creating a descendant class.
  • I ran across this great little utility called Snoop to inspect the VisualTree of a running WPF application. I think I'd heard of it before in passing but had never looked into it. I don't know how many times I've written throw-away VisualTree walkers to dump information to the console. Now I'll never have to do that again.

Saturday, February 7, 2009

Microsoft's OfficeUI Ribbon: Adding non-button controls

There are quite a few controls included with the new Microsoft OfficeUI Ribbon library. I recently wanted to incorporate this into a prototype application I was working on. All the examples I found showed how to use it with a button but I wanted a richer UI than just buttons on the ribbon. I did some web searching and found precious little information on using other controls and I did not find any documentation. Using the little information I did find, a lot of reverse engineering and some trial and error, I finally came up with something that works. Therefore, in an effort to help someone else, here are some things I discovered.

First, I wanted a simple mini-form for doing text searches. All it needed was an edit box, a go button and a couple check boxes in a ribbon group. Here is a screen shot of what I wanted:
Ribbon panel specification

In my first attempt, I knew I needed a group to put the controls in, so I naively added one to my ribbon and added the desired controls. The designer immediately became unstable. I was able to compile after stopping and restarting the IDE. However, when running the application, I got a null reference exception loading the form.

Through some routine diagnostic sleuthing, I determined the cause: having multiple groups without assigning GroupSizeDefinitions. If there is only one group, it will work properly without defining a GroupSizeDefinition. However, with more than one group, each group must have a GroupSizeDefinition assigned. I hope that Microsoft will fix this bug before the final release.

In spite of fixing the null reference problem, the layout did not work as desired. Things did not size appropriately. Controls did not position the way I wanted. It was a UI mess.

I had gone to a session at PDC2008 where they demonstrated the control so I went to find that presentation. A bit of information was gleaned from slide 36 [pptx] of session PC45 where the ItemsPanel property was discussed. Unfortunately it was entirely too brief and ended up somewhat misleading. It did give me a clue to start looking for other things though.

After a bit of searching, reading blog articles and forum posts, I found the key to figuring this out in a short post by Mike Cook. I found it best to add an ItemsPanel to the RibbonGroup containing a UniformGrid. The controls then went in this container.

In order to get the controls formatted the way I wanted, I needed to put each row in a DockPanel. However, the only things that can go in a RibbonGroup are things that implement IRibbonControl. To handle this, I created two of my own controls that extend DockPanel and implement IRibbonControl. This ended up working well because I needed to add additional code to each one to work the way I wanted and this helped encapsulate this code.

In formatting the top line, the first thing I found was the RibbonButton, used for the Go function, always assumes there is an image associated with it. For the purposes of this form, I wanted the image to the left of the label, associated with the entire line, not over on the right associated with the button. In order to turn this off, I had to find the image in the button's template and set its Visibility to Collapsed.

After getting the button's image removed, the next thing I found was the RibbonTextBox sizes the text box to its content. This seemed ugly to me and I did not find any way of altering this behavior with simple property settings so I started investigating the VisualTree for the control. After some trial and error, I found I could set the Width of a Border inside the RibbonTextBox and the internal TextBox would remain that size. This strikes me as a pretty ugly and fragile hack, but it works. I hope that this will improve before the final release.

The second row is more straightforward with just two RibbonCheckBoxes on it. It does have a slight oddity though. The Executed property must have a method assigned to it for the check box to be active. The issue is, in this particular use case, I did not need to have anything happen when the user checks the box so there is a required method that has nothing in it. This seems silly to me.

At the end of the day, I was able to get what I wanted out of the library. I think it looks nice for the user and functions well. But, it is not terribly pretty for the programmer and there was quite a bit of frustration getting it to work as I intended, mostly due to poor and lacking documentation. I hope someone else finds this useful. If there are any errors or omissions, please leave a comment to let me know and I will do my best to correct it.

Source code

The ribbon control is publicly available on the OfficeUI web site after agreeing to a long, overwhelming license. (Here are the how-to-get instructions.) As I understand it, this is going to be bundled into the base System.Windows name space with CLR 4.0, so I'm not quite sure why there's such an onerous license on it at this point.

Here is complete source code [zip] for this article. Note that it does contain a reference to RibbonControlsLibrary, the package containing the Ribbon controls, which is not included due to licensing restrictions. In order for this to compile, you need to get this library from Microsoft (see links above) and then update this project to point to your copy of it.

Monday, November 24, 2008

Microsoft's OfficeUI Ribbon: Application template

I've been working with the recently released Ribbon control from Microsoft's Office UI group. There are several cookie-cutter setup steps to get an application ribbon aware. In order to facilitate setting up a new application, I made a Visual Studio 2008 template that creates a blank application containing a ribbon bar with some empty controls.

Here is the template file. Copy this zip file to My Documents\Visual Studio 2008\Templates\ProjectTemplates\Visual C#. When Visual Studio is started, the New project dialog displayed when File | New | Project... will have a new Ribbon Application option under My Templates. Select this to create a skeleton ribbon application.

When the application is created, an error will be displayed indicating the ribbon control library cannot be found. This is because this library needs to be acquired directly from Microsoft. To get it you need to go to the OfficeUI web site. (Here are the how-to-get instructions.)

Once the library is downloaded and installed on your computer, go to the new ribbon application's References, remove RibbonControlsLibrary and then add it in again, pointing to the location on your computer.

The skeleton application contains a Close option on the application menu to stop the application. There is a single tab with a single group containing a single button. Finally, there is a single button on the quick access toolbar. These all can be used as templates to easily add more.

More information on creating Visual Studio templates can be found on the MSDN site. (Thanks to paranoid ferret for the pointers on to how to create templates.)