May 18, 2011

WPF Binding not working? Check the Output Window

Took me a long time and hours of frustration troubleshooting WPF binding failures to finally find a silver bullet. Actually, this stuff is all over the place on the net, but for whatever reason, not mentioned in many WPF books.

If you are expecting to see a binding when you start your WPF application, but the value never changes, or is default, or the bound listview is empty when it should have data, check the output window in Visual Studio while you debug.

Bindings in WPF are best-efforts only by the framework. Not really sure why. I sometimes wish a giant unhandled exception error would show up instead of silent failure. Nevertheless...

Here's a sample error message you might find there.

Let's say you have the following XAML layed out and you're trying to bind a listview to a 'Parameters' ObservableCollection member of the control data context. But when you filled out the XAML, it was misspelled.

<DockPanel>
  <Label DockPanel.Dock="Top" Style="{StaticResource LayoutLabel}">Parameter Selection</Label>
  <Border  Style="{StaticResource LayoutBorder}">
    <ScrollViewer DockPanel.Dock="Bottom">
      <ListView View="{DynamicResource ParameterView}" ItemsSource="{Binding Path=Parametrs}"/>
    </ScrollViewer>
  </Border>
</DockPanel>

Now when you debug, the members of the 'Parameters' ObservableCollection don't appear in the listview. Go and check the output window and you might see this in the output window
System.Windows.Data Error: 39 : BindingExpression path error: 'Parametrs' property not found on 'object' ''OrderedEnumerable`2' (HashCode=57007955)'. BindingExpression:Path=Parametrs; DataItem='OrderedEnumerable`2' (HashCode=57007955); target element is 'ListView' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
Lots of gobbledygook, but clearly in this message WPF is complaining that binding cannot be made with a Parametr property. It shouldn't be too hard to find the trouble with this information.

More often than not, it's not a spelling mistake, but a plain mismatch between the object being searched by WPF and the binding path given.

Example being if the aforementioned control had a datacontext set to 'MyObject' but the class of 'MyObject' doesn't have a 'Parameters' property at all.

May 14, 2011

Cool Places to Build Stuff

A survey of Software developers finds very narrow focus in what motivates. Even the most hardened veteran still gets tingles when building something new and learning.

If you haven't read 'Drive' by Daniel Pink yet, you should get on that. His insights are very true for us software people. Just a fantastic book. If you are feeling unmotivated by your decent paying job, get this book for some possible explanations.

Bottom line, it's very cool to build stuff. Along that vein, I've been visiting this blog a lot in the past few days. It seems to be written directly for me. I'm a shutterbug, a product review addict, and software professional (which they seem to have a requirement for).

I found a job listing on the site and it sounds like a wicked cool place to work. Lots of building stuff, very few meetings.

But the most interesting part isn't the description of themselves in the job listing, but their use of coding challenge to evaluate new candidates. It doesn't appear to be one of those high pressure 'code while we watch' type deals. Rather, you download the challenge data and produce a solution. Email them a link and your resume when you're done.

I might just do that.

Apr 29, 2011

Seth Godin Quote Post

A refreshing outlook on "My boss won't let me". You have to overcome this attitude to do something useful.
When we say, "my boss won't let me," what we're often saying is, "my boss wants great results, but she's not willing to let me take initiative without responsibility."
I'd be shocked if any smart boss took a different approach. Who's going to give you authority without responsibility
Thanks for the daily inspiration Seth.

Apr 22, 2011

Better Than Any Software Developer Compensation Package

I saw this promise in a Software Developer Wanted ad today
We promise you’ll never spend more than an hour a week in meetings.
Heady promise. Still, I know lots of developers who would go for this. At least, they will take a second look at the posting when they read that they aren't really expected to attend too many meetings.


Very clever ad. They definitely know their demographic.

Apr 17, 2011

Promote Your Code: Software Development in Small Environments

Working with a large team of Professional Software Developers is a bit of a dream come true. We take code seriously and we all love to see beautiful structure and design. Code maintainability is utmost on our list of priorities. Well designed and highly maintainable code is the mark of Professional Software Developers.

I used to work in much smaller enterprises where the need for a real Professional Software Developer wasn't recognized. In those places, code was produced by 'affiliated professionals' as I call them. Engineers, Scientists, even Junior Software Developers. In short, people capable of making code, but not trained how to handle software process.

I remember a manager asking us for a code review once. Code reviews should be de rigeur at any company producing code, although in practice is not widely adopted. Anyway, we had no idea what he was talking about. I suspect the manager didn't either. It was probably a due-diligence thing. Papers that needed signing.

We did the best we could. A bunch of us code guys borrowed code guys from other projects to review our code independently. It was a nightmare to gather materials in time for pre-meeting review, prepare a walk-through for the other team, then try to schedule everyone in the meeting.

When we finally got everyone together and started our walkthrough, it was obvious that the other code guys hadn't even cracked open the material we sent. The whole meeting was a bust. We sat for an hour describing basically what our product was supposed to do. Not good use of review time. Although the managers papers got signed!

If we'd had a Professional Software Developer around, I can imagine that the review process would have been a lot more productive. For example, we would've known that reviews that are more frequent and much smaller are far more effective than one huge review of thousands of lines at the end of a development cycle. Who can understand the mess created when code guys are left to their own architectural devices for 6 months? We also would've known how to handle the ego challenges of critical review of a developers artwork.

Still, the Kings Ransom that true professionals are paid is a little off-putting for businesses that don't specialize in software. Maybe there's not really enough there to employ such a professional full-time. It's too bad that a company struggling with software can't bring in Professional Software Developers part time, just to lend their expertise on process and architecture.

Or can they?

Why not drop me a line at the contact page?

Mar 27, 2011

Kerning (Character Spacing) with Microsoft Office Embedded Charts

Note: This probably applies to copy/pasted charts between Excel/Word, I was using VBA, so I had to find the VBA way to fix it.

I like Office VBA automation. Sometimes Microsoft makes it hard for me to remember that fact though.

The usual problem is that the easy stuff is easily automated with VBA. Which is good. But if you want to do something slightly irregular, dare I say even advanced, then you're in for a world of hurt.

When copying and pasting charts between Excel and Word, the traditional wisdom is to copy and paste as a picture because it's the most reliable reproduction of the original chart once pasted.

Fine if all you want is a static chart pasted into a Word document, but if you want to give the Word user the ability to modify the chart or data, then you need to copy and paste a chart object.

Although it's fully supported by the VBA interop runtime, the results are less than fantastic.
Here's some code that pastes an existing Excel Chart Object

Sub PasteChartAsInteractive(chart As Excel.chart1)
    Dim PageWidth As Long
    Dim WidthRatio As Double
    chart.ChartArea.Copy
    Dim myShape As Shape
    
    Selection.Style = ActiveDocument.Styles("Normal")
    Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter

    'Commented out line is pasting as image.
    'Selection.PasteSpecial Placement:=wdInLine, DataType:=wdPasteMetafilePicture

    Selection.PasteAndFormat (wdChart)
    
    Selection.EndOf Unit:=wdParagraph, Extend:=wdMove
    Selection.TypeParagraph
    Selection.ParagraphFormat.Alignment = wdAlignParagraphLeft
    
    Selection.range.ListFormat.ApplyBulletDefault
    Selection.TypeText "..." + vbCr

End Sub

But the problem with the inserted chart is that the kerning is all messed up. Observe the results.

The kerning fault is especially noticeable in the title above. There is virtually no spacing between characters in any letters. Some even appear to overlap.

Google searches mostly turn up the workaround of 'paste as image', which was not an option for me, the chart had to be editable and live.

I had given up and was going to move away from Excel Charts and into using Word Graph Objects This was going to be an ordeal because I had a bunch of existing charts in this macro, pasted as images, and the formatting all needed to be consistent. My impression is that the graph and chart API's are not really that similar.

Then I stumbled on a solution with Clouseau-esque serendipity. Changing the object layout (Format -> Object -> Layout) to use 'Square' rather than 'In-line' made the kerning problem disappear. What's more, I could change the layout back to 'In-line' and kerning was still proper.

There was a minor issue with finding the appropriate commands to do this with VBA. Normally I record a macro of the action I want to reproduce if I'm not totally sure how. With macros, the Layout tab is disabled, so I had to dig around online to find the VBA.

Sub PasteChartAsInteractive(chart As Excel.chart)
    Dim PageWidth As Long
    Dim WidthRatio As Double
    chart.ChartArea.Copy
    Dim myShape As Shape
    
    Selection.Style = ActiveDocument.Styles("Normal")
    Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter
    
    Selection.PasteAndFormat (wdChart)
    Set myShape = Selection.Paragraphs(1).range.InlineShapes(1).ConvertToShape
    myShape.ConvertToInlineShape
    
    Selection.EndOf Unit:=wdParagraph, Extend:=wdMove
    Selection.TypeParagraph
    Selection.ParagraphFormat.Alignment = wdAlignParagraphLeft
    
    Selection.range.ListFormat.ApplyBulletDefault
    Selection.TypeText "..." + vbCr

End Sub
And the result

It's too bad that we have to resort to these cheap tricks when trying to get members of the Office suite to behave together. You would think by now, the integration would be much tighter.

By the way, did you notice that the Y-axis title is truncated in both images? The fix for that is to add superfluous characters to the Y-axis title until all the important characters show.

Mar 23, 2011

Paginated Printing of WPF Visuals - II

Last time I discussed paginated printing of wpf visuals, I mentioned that the pagination didn't support a whole lot of options.

There was no support for margins or headers for example. The print was edge-to-edge which is OK when you're a developer and you're going to throw the paper out right after printing, but not so good if you are the end user and need to put the paper in a binder, or if you've dropped the whole mess on the floor and need to put it back in order.

The easy way to put more visuals with the visuals you have rendered is to use a ContainerVisual object and stack some visuals together. With my previous entry there was a problem because it transformed and rendered the original Visual directly to print. This meant that the Visual could not be part of ContainerVisual as it already had a visual parent.

To solve that problem, I rendered the Visual to bitmap before print. That way I could use ContainerVisual with the bitmap and stack up any number of visuals in the container. Here's the class.

class FrameworkVisualPrint : DocumentPaginator
{
    private readonly FrameworkElement Element;
    private const double XMargin = 1 * 96;
    private const double YMargin = 1 * 96;
    public String Header { set; get; }

    public FrameworkVisualPrint(FrameworkElement element)
    {
        Element = element;
    }

    private const double ScaleFactor = 0.5;

    private DrawingVisual GetHeader(int pageNumber)
    {
        var header = new DrawingVisual();

        using (var dc = header.RenderOpen())
        {
            var text = new FormattedText("Page " + (pageNumber + 1) + Environment.NewLine +
                Header, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, 
                new Typeface("Arial"), 8, Brushes.Black);
            dc.DrawText(text, new Point(XMargin, 0.5 * 96));
        }

        return header;
    }

    public override DocumentPage GetPage(int pageNumber)
    {
        var tgroup = new TransformGroup();
        tgroup.Children.Add(new ScaleTransform(ScaleFactor, ScaleFactor));
        Element.RenderTransform = tgroup;
        tgroup.Children.Add(new TranslateTransform(-PageSize.Width * (pageNumber % Columns) 
            + XMargin, -PageSize.Height * (pageNumber / Columns) + YMargin));
        Element.RenderTransform = tgroup;

        try
        {
            var area = new Rect(
                new Point((PageSize.Width * (pageNumber % Columns)) / ScaleFactor,
                          (PageSize.Height * (pageNumber / Columns)) / ScaleFactor),
                new Size(PageSize.Width / ScaleFactor,
                         pageSize.Height / ScaleFactor));

            Element.Clip = new RectangleGeometry(area);
            var elementSize = new Size(
                Element.ActualWidth,
                Element.ActualHeight);
            Element.Measure(elementSize);
            Element.Arrange(new Rect(new Point(0, 0), elementSize));

            // Make a bitmap from the transformed Element
            var bitmap = PngBitmap(Element, (int)area.Width, (int)area.Height);
            var vis = new DrawingVisual();

            // Draw the bitmap into a DrawingVisual object
            DrawingContext dc = vis.RenderOpen();
            dc.DrawImage(bitmap, new Rect(0, 0, area.Width, area.Height));
            dc.Close();

            // Grab a header to apply (with page numbers)
            var header = GetHeader(pageNumber);
            // Container for all the new stuff.
            var cVisual = new ContainerVisual();

            cVisual.Children.Add(header);
            cVisual.Children.Add(vis);
            return new DocumentPage((cVisual));

        }
        finally
        {
            Element.RenderTransform = null;
            Element.Clip = null;
        }

    }

    private RenderTargetBitmap PngBitmap(Visual visual, int width, int height)
    {
        // Render
        var rtb =
            new RenderTargetBitmap(
                (int)(width / ScaleFactor),
                (int)(height / ScaleFactor),
                96.0 / ScaleFactor,
                96.0 / ScaleFactor,
                PixelFormats.Default);
        rtb.Render(visual);


        return rtb;
    }

    private Size pageSize;
    public override Size PageSize
    {
        set
        {
            pageSize = value;
            pageSize.Width -= XMargin;
            pageSize.Height -= YMargin;
        }
        get { return pageSize; }
    }
}

The class isn't actually complete. See the previous article for the initial version. This is just new and changed methods.

The important bits are commented.
  • Make a bitmap from the Visual
  • Draw the bitmap to a new DrawingVisual Object
  • Stick the DrawingVisual and any other visuals needed in a ContainerVisual
  • Bob's your uncle!