Joe White’s Blog

Life, .NET, and Cats


Archive for the ‘Programming’ Category

Refactoring with MVVM is easy!

Friday, July 30th, 2010

I’ve built up a kind of intellectual appreciation for some of the things MVVM gives you, but today I had a real “wow!” moment.

I’ve been working on a WPF UserControl, and it was getting kind of big and cumbersome. I wanted to extract some pieces from it into smaller UserControls to make it more manageable (and to make it easier to make some changes to the high-level layout).

So I created a new UserControl, moved my XAML into it, and referenced it from the original spot.

And that was it. I ran it, and it worked. That simple. No worries about moving dozens of code-behind methods onto the new control. No messing with method and field visibilities, and figuring out which objects the new control needed to have references to so it could do its work. No re-hooking event handlers.

Okay, it wasn’t quite cut-and-paste — there was some fixup to be done. The new UserControl needed some xmlns: attributes added. And I wanted the attached layout properties (Grid.Row, Grid.Column) to stay in the original file, not move into the new one (they’re part of the parent layout, not intrinsic to the child UI). So it took maybe a minute or so.

But it was nothing like the splitting headache that is extracting a UserControl in WinForms.

And then I extracted another UserControl. And I ran. And it just worked.

Wow.

Just, wow.

But the downside is, now I’ve got this overwhelming temptation to rewrite our million-line codebase in WPF…

MVVM and DialogResult with no code-behind

Sunday, July 25th, 2010

I like the Model-View-ViewModel pattern in WPF, and the way it helps get code out of the UI and into a place you can test it. But every now and then you run into a weird limitation — something you can’t do out of the box. One such example is closing a dialog box.

WPF’s Button doesn’t have a DialogResult property like buttons did in Delphi and WinForms. Instead, the codebehind for your OK button has to manually set the Window’s DialogResult property to true. This makes sense in principle — it lets you validate the user input before you close — but it makes it hard to use “pure” MVVM with no code-behind. I don’t actually give a hoot about blendability (I still write all my own XAML), but since I’m still learning WPF and MVVM, I take it as a challenge to find pure-MVVM solutions to problems, just as a learning exercise.

The obvious (wrong) solution

The obvious solution would be to just do this:

<Window ...
        DialogResult="{Binding DialogResult}">

Then make your ViewModel implement INotifyPropertyChanged in the usual way, and DialogResult gets pushed up to the view the same way as everything else. Right?

Unfortunately, DialogResult isn’t a dependency property (good grief, why not?), so the above code gives you a runtime error when you try to create the window:

A ‘Binding’ cannot be set on the ‘DialogResult’ property of type ‘TestWindow’. A ‘Binding’ can only be set on a DependencyProperty of a DependencyObject.

Back to the drawing board.

Others’ solutions

Some Googling found a StackOverflow post, “how should the ViewModel close the form?”, with an accepted answer (with 5 downvotes) of “give up; you can’t use MVVM for dialog boxes”. But I’m not quite ready to throw in the towel, so I keep reading.

Another answer on the same question — which had 0 upvotes at the time I read it, despite perfectly answering the question — pointed to a blog post by Adam Mills: “Window.Close() from XAML”. Adam’s solution uses an attached behavior. I’m learning to appreciate the attached-behavior pattern; you create an attached property, but then give it side-effects. It’s a good way to get code out of the codebehind, and it forces you to make it reusable at the same time.

But I’m not crazy about the details of Adam’s solution, because it requires you to create a style, hook up triggers, …a lot of mess. His post doesn’t actually have a complete code sample, so I’m not even sure how you hook the style into your window, though I’m sure I could puzzle it out eventually. And even his incomplete example is five lines of XAML. It’d probably be up to 7 or 9 by the time you actually got it fully wired up, and that’s 7 or 9 lines that you have to repeat for every dialog box you write.

Shouldn’t it be simpler? Shouldn’t it be almost as simple as the databinding syntax would have been, if the WPF team had gotten it right and made DialogResult a dependency property?

The one-line* attached behavior

* Okay, yes, it’s two lines if you count the XML namespace.

So I rolled my own attached behavior that does make it almost that simple. Here’s how you use it:

<Window ...
        xmlns:xc="clr-namespace:ExCastle.Wpf"
        xc:DialogCloser.DialogResult="{Binding DialogResult}">

Your ViewModel should expose a property of type bool? (Nullable<bool>), and should implement INotifyPropertyChanged so it can tell the view when its value has changed.

Here’s the code for DialogCloser:

using System.Windows;
 
namespace ExCastle.Wpf
{
    public static class DialogCloser
    {
        public static readonly DependencyProperty DialogResultProperty =
            DependencyProperty.RegisterAttached(
                "DialogResult",
                typeof(bool?),
                typeof(DialogCloser),
                new PropertyMetadata(DialogResultChanged));
 
        private static void DialogResultChanged(
            DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var window = d as Window;
            if (window != null)
                window.DialogResult = e.NewValue as bool?;
        }
        public static void SetDialogResult(Window target, bool? value)
        {
            target.SetValue(DialogResultProperty, value);
        }
    }
}

I’ve posted this as an answer on the StackOverflow question, so if you think it’s a good solution, feel free to vote it up so that others can find it more easily.

Using a worker AppDomain to register a COM assembly

Friday, December 4th, 2009

I’ve been coding in .NET since 2002. Today I finally had a reason to use an AppDomain. I had a task that needed to run in a separate AppDomain and then return, so I’m thinking of it as a “worker AppDomain”.

We have a code path that needs to programmatically register one of our assemblies as a COM library (shudder). And yes, there are good reasons why it’s not enough for us to do this at install time. But that’s okay, because the code is pretty simple:

public static class MyRegistrar
{
    public static void Register()
    {
        var assembly = LoadMyComAssembly();
        var registrationServices = new RegistrationServices();
        registrationServices.RegisterAssembly(assembly,
            AssemblyRegistrationFlags.SetCodeBase);
    }
}

(I also could have shelled out to regasm.exe with the /codebase option, and gotten the same result. But that would have required hard-coding the path to the .NET Framework binaries, which is even worse than COM.)

The downside is that, once my process loads the COM assembly, that DLL file is now locked on disk until my process exits. This turned out to be problematic — it’s actually a Windows service that’s running the above code, and I was having trouble building the COM assembly because the service had it locked!

So I had to make sure the assembly got unloaded after we ran the above code. That means either a separate process, or a separate AppDomain. And if I used an AppDomain, I wouldn’t have to add yet another project to our solution. So I dove right in, and after several false starts, got something that worked. Here’s my code to load and regasm an assembly, without keeping the file locked thereafter:

public class MyRegistrar : MarshalByRefObject
{
    public static void Register()
    {
        var domain = AppDomain.CreateDomain("Registrar", null,
            AppDomain.CurrentDomain.BaseDirectory,
            AppDomain.CurrentDomain.BaseDirectory, false);
        try
        {
            var me = typeof(MyRegistrar);
            var assemblyName = me.Assembly.FullName;
            domain.Load(assemblyName);
            var registrar = (MyRegistrar) domain.CreateInstanceAndUnwrap(
                assemblyName, me.FullName);
            registrar.RegisterAssembly();
        }
        finally
        {
            AppDomain.Unload(domain);
        }
    }
    private void RegisterAssembly()
    {
        var assembly = LoadMyComAssembly();
        var registrationServices = new RegistrationServices();
        registrationServices.RegisterAssembly(assembly,
            AssemblyRegistrationFlags.SetCodeBase);
    }
}

To run code inside an AppDomain, I need an object that lives inside the new domain, but that I can call into from outside it (i.e., from the primary AppDomain); hence the change from static class to MarshalByRefObject descendant, and the move of the actual registration code to an instance method. Then I can just create a new AppDomain, create an instance of my class inside that domain, call the object’s instance method (which then executes inside the new domain), and then unload the AppDomain so that it unloads the assembly. Most of the gyrations are there because there isn’t a generic version of AppDomain.CreateInstanceAndUnwrap — if there was, the inside of that try..finally would be all of two lines long, if that.

Actually, better yet would be if RegistrationServices could take the filename of an assembly, rather than only taking a reference to an already-loaded-and-locked Assembly object. Then it would be a drop-in replacement for regasm. Still, the above code isn’t too complicated, and it seems to work nicely.

NUnit and Silverlight

Friday, October 9th, 2009

Unit testing in Silverlight is a persnickety business. The NUnit.Framework binary is built for full .NET, so you can’t easily use it to test Silverlight assemblies. I tried a few different things, but kept running into walls.

Fortunately, smarter people have already figured it all out. Jamie Cansdale made a Silverlight NUnit project template that gets you started right. It’s intended for TestDriven.NET, but it works great with ReSharper’s test runner too. Just download and open his template, and it’ll add itself to Visual Studio. Then the next time you do New Project, there’s an extra “Silverlight NUnit Project” option available under the Visual C# > Silverlight project type. Very cool.

However, the nunit.framework assembly in Jamie’s template is from some unidentified, but old, version of NUnit. There’s no version info in the DLL, but I know it’s gotta be 2.4.x or earlier, because its Is class (from the fluent assertions — Assert.That(2 + 2, Is.EqualTo(4));) is in a different namespace, whereas I know that 2.5 moved it into the main NUnit.Framework namespace.

Since I use the fluent assertions all the time, and since I just don’t want to use an old version, I went hunting again, and found Wes McClure’s NUnit.Framework 2.5.1 for Silverlight 3. It’s only a little old — right now the latest version is 2.5.2 — and his binaries are working out quite nicely so far.

So I use Jamie’s template to create a new project, which includes a lib directory with the old version of nunit.framework.dll; then I grab Wes’s nunit.framework.dll and drop it into the lib directory, replacing the older version. And I’m good to go.

Now, back to those fiddly trig calcs… (See, there was a reason I wanted to add a test project!)

Update, Oct 10 7:30am… Intellisense works great with Wes’s assembly. Building and running are a different story. Much unexplainable behavior from Visual Studio. Short version: I couldn’t get Wes’s assembly to work with the ReSharper test runner. But Jamie’s template is working fine so far.

BarCamp Omaha 2009…

Friday, October 9th, 2009

So I’m finally getting around to writing about last weekend’s BarCamp.

My overall impression was “awesome”. Two things that stand out in my mind are:

  • Going to great presentations by people I know;
  • Being able to flag down the conference planners at lunch and bounce ideas off them.

Neither of those are something I’d get at a Microsoft TechEd — or even so much at a Heartland Developers Conference. Great sessions, yes; but I really value the sense of intimacy, and it’s just not the same at big conferences.

They had three tracks — creative, entrepreneurial, and technical — and I wound up splitting my time pretty evenly between them, which surprised me a bit. Erica gave a great talk about the power of conversation. Someone (I’ve got his name in my notes) gave a talk about the nuts-and-bolts of how the brain works… neurotransmitters and all that. Nate had a round-table-ish discussion of how attention deficit disorder affects us as IT workers. Bunch of other sessions that I don’t recall in detail at the moment, but I took notes. Very cool stuff. I was drained by the end of the day, but it was a good kind of drained.

Totally worth $5 and a day of my time.

The biggest downside was that they got donuts, muffins, and bagels for breakfast. All carbs, no protein… a nap waiting to happen. (Turned out the sponsor who was going to provide breakfast fell through at the last minute, so they had to scramble to find something else — so it’s actually pretty cool that there was breakfast.) But I managed to find some peanut-buttery candy to help tide me over till lunch, so it worked out OK. I’ve volunteered to bring a big jar of peanut butter next year.

I did find that, for me as an introvert, the evening-before party wasn’t very interesting. No offense to the people I talked to there; but it takes energy for me to be around people, and mingling doesn’t do much for me. I’ll probably skip the evening parties at HDC again this year for the same reason.

But the conference itself is totally something I’ll do again.

Session notes will be forthcoming as I get around to it.

Kinda wishing I could keep using Delphi

Thursday, September 24th, 2009

I’ve been reading the recent debate about a “Delphi Community Edition”. Most of it seems pretty abstract: “I think it would help the Delphi community if…”

That’s all well and good, but I thought I’d share something less theoretical: something that directly affects me, a longtime Delphi geek.

I’ve been using Delphi since its first release in 1995. I still have one of the original brochures somewhere, with the quote saying “It’s going to change our lives, you know.” That quote still sticks in my head, all these years later.

Delphi has been a pretty good tool to work with. Sure, the IDE freezes for half a minute at a time when you type an open paren, Ctrl+click doesn’t work half the time, and the IDE still can’t pull off a cross-unit rename refactoring (and, and, and…). But damn it, Delphi lets you write programs that work and work well. Good God, just try to find a decent unbound grid in .NET. Or a WinForms control — any WinForms control — that even begins to approach the quality of Toolbar2000 or VirtualTree.

My company got acquired, and is moving to .NET. On the one hand, I honestly can’t say I mind too much; .NET has some sweet libraries — way fewer cool GUI controls than Delphi, but more cool everything else. I love not having to write one set of code to deal with an array and a different set of code to deal with a list. The unified type system rocks for unit testing (no need to write a CheckEquals overload for every enum we’ve ever defined). And, of course, Delphi doesn’t have ReSharper. ‘Nuff said.

But I cut my Windows-programming teeth on Delphi (after banging my head against VB). Asked my comp sci department for a copy of Delphi instead of a cash scholarship, way back in ‘95. Used it for my senior honors project. Knew it inside and out. Took at least one Delphi aptitude test where I was correcting the questions. Somehow I became one of the first Delphi conference bloggers. And Delphi has gotten me more than one job, and it got me where I am, working with a terrific team.

I’d really like to keep a copy of Delphi around, just to play around with for hobby projects. It’d be great to play with the new stuff in Delphi 2010. And to play with Prism. And, hell, just to show my appreciation for the product, by paying for a license now that my company won’t need to anymore.

But if it’s just for me, I can’t justify the price they want me to pay.

If it was $200, I’d find the money; Delphi is totally worth that. I might even be able to stretch to $300, especially if it included both Win32 and Prism. But $400, for an upgrade that’ll just need upgrading again in another year, and for just one platform? My wife really needs a new computer, and it wouldn’t be fair of me to ask her to wait another half a year for nothing better than that.

At $400, I walk away. With regret.

The last version of Delphi that I own is Delphi 4 — after that, I was always able to convince my employer to buy it for me (or they already had it). So after December, when the “upgrade from any prior version” offer expires and even the painful $400 price-point goes through the roof, I’m probably going to be out of the Delphi business permanently.

And so we come to (presumably) unintended consequences. By setting their prices so high, the Delphi sales team is ensuring that, once I’m no longer paid to use Delphi, I’ll no longer be able to use Delphi. And so I won’t be able to stay current, and a couple years from now, I probably wouldn’t be able to get another Delphi job even if I could find one.

I suppose they need to run their business as they see fit. They have every right to set prices high enough to drive away their longtime customers, if that’s what they feel they need to do.

But I’m becoming painfully aware of what a lot of people have been saying for years: Delphi’s pricing is downright hostile to the hobbyist. They’re aiming strictly at the enterprise, and screw anyone else.

And that’s sad, because it’s the Inprise attitude, and the ALM attitude, all over again. They’ve got this “if we raise the price tag, we’ll get more money, and the money’s all that matters” mentality. It apparently never occurred to them that sometimes, lowering the price tag can multiply your income (and your customer base). Would that hold for Delphi? A lot of community members have been pretty vocal in thinking it will, and I’m becoming a believer.

But the sales department, so far, has stuck its fingers in its ears and pretended not to hear. And the dev team either can’t, or won’t, pressure them to change their minds.

I totally admire what the dev team has been doing lately. They’ve been making Delphi, well, Delphi again. They’ve been doing some serious moving and shaking. D2010 sounds sweet, and I’d love to play around with it.

But unless they fire the Borland/Inprise sales team, and hire some CodeGear folks, my Delphi days are numbered.

I’ve always hated change. Life will go on, of course. But still, I’ll miss Delphi.

Upcoming Omaha developer-ish conferences: BarCamp and HDC

Friday, September 18th, 2009

BarCamp Omaha is October 2-3 (Friday evening to Saturday). I’ve never been to a BarCamp, but it promises to be intriguing — the session schedule is planned on a whiteboard Saturday morning, and anyone who wants to run a session, can. It’s not just a tech conference; they say the major tracks will be Tech, Creative, and Entrepreneurship.

I understand that BarCamps are usually free, but this one costs $5. But (a) that’s cheap (heck, I thought the HDC was cheap at $200 — but then again, I’m not paying for the HDC out of my own pocket) and (b) you get the full conference experience for that $5: free T-shirt (great, another one to go into the drawer), free breakfast, free lunch, and free pop and snacks all day. Free food is the primary reason for going to a conference, so it should feel just like home.

I’m toying with the idea of speaking at BarCamp (haven’t really decided yet). Their FAQ says the time slots are only 30 minutes, and I’m wondering if I should take a stab at a 31 Minutes of ReSharper. It’d take some serious editing, mind you, given that my original material was 31 days.

The Heartland Developers Conference (HDC), a Microsoft-themed conference here in Omaha, is October 15-16. I guess I don’t really need to hype it, since it’s 100% sold out this year (I wonder how long until they need to start spilling over into the first floor of the Qwest Center?). But I’m looking forward to it just like every year, because the second-day breakfast always has all the free bacon you can eat.

Oh, and they always have some pretty awesome sessions, too. A couple years ago they had Scott Guthrie from Microsoft do one of the keynotes, if that gives you any idea (at the time, he was Microsoft’s General Manager in charge of the CLR, ASP.NET, Silverlight, WPF, and IIS, among other things). They get good people and a lot of interesting content. I can pretty much register without even looking at the session list, and know that every timeslot will have a session that’s well worth my while — and even with the economy the way it is, my boss was happy to pay all our conference registrations. There’s benefits to making something cheap. (Delphi sales department, are you listening?)

Micro-rant: Ninject and IKernel

Tuesday, July 7th, 2009

Ninject looks cool. So does Autofac, but Ninject has automatic self-binding.

But I hate how Ninject calls its container “IKernel”.

This is the one part of Ninject that you are guaranteed to use. (Well, I guess you need modules too — not that that name is much better.) IKernel is the single most visible part of the Ninject API. And its name is absolutely wretched.

It’s named for its implementation, with no regard to its usage. In real life, it isn’t a kernel; it belongs to the kernel module in Ninject’s modular implementation. Don’t get me wrong, I appreciate that it’s modular. But don’t make me, as a dev who just wants to use a DI framework, suffer through that implementation detail.

Nobody should have to care what a “kernel” is unless they’re writing their own. “Kernel” means nothing to someone using the container (which is almost everybody). The name is not just distracting, it’s outright misleading — it actively suggests “this is not a container”, when in fact it’s exactly a container, keeper of the Get<T> method.

I really want to give Ninject an honest try, but this seriously bugs me. Why not “IContainer”? Or something that isn’t a lie? (Yeah, I know they’re ninjas and all, but shouldn’t the subterfuge be reserved for the enemy?)

WPF oddity of the day: attached/dependency properties and breakpoints

Sunday, May 24th, 2009

Silverlight doesn’t have any real support for ICommand, so I wrote an attached CommandBinder.Command property. Then it wasn’t working (at least when I compiled for WPF, which is a lot easier to debug), so I tried putting breakpoints in my SetCommand and CommandChanged methods. Neither ever got hit.

It turns out that WPF’s attached-property pattern is weird: you have to declare a getter and setter method, but they don’t get called.

Here’s some sample code for an attached property, just for reference:

public class CommandBinder
{
    public static DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached(
            "Command", typeof(ICommand), typeof(CommandBinder),
            new PropertyMetadata(CommandChanged));
 
    private static void CommandChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        // do something
    }
    public static ICommand GetCommand(DependencyObject d)
    {
        return (ICommand) d.GetValue(CommandProperty);
    }
    public static void SetCommand(DependencyObject d, ICommand value)
    {
        d.SetValue(CommandProperty, value);
    }
}

You have to have a setter method; otherwise you get a compiler error. (Apparently the compiler has some logic to enforce the design pattern.) But as far as the XAML parser is concerned, the setter method is more of an attribute — it says “Yeah, I’m settable.” The XAML loader doesn’t call SetCommand; it calls SetValue directly on the target object.

I did some experimenting, and it looks like this applies to dependency properties as well. You have to declare a corresponding CLR property, or you’ll get a compiler error when you try to set the property in XAML; but the XAML loader never actually uses the property.

In both cases, your setter could actually do nothing at all, and the XAML would still set the property’s value correctly. (But then anyone who tried to set the property programmatically would be in for some head-scratching. So don’t do that.)

I had wondered, in the past, why you would pass a PropertyMetadata with a change-handler delegate, rather than just putting the on-change logic inside the SetXXX or property setter. Now I know.

(Actually, in my experimenting, I was able to get it to call the property setter. All I had to do was misspell the property name that I passed to DependencyProperty.Register. So that’s why I have to tell it the name (something else I had always wondered) — so it can do a dictionary lookup. If the dictionary lookup fails, it falls back on trusty-but-slow Reflection.)

So that explains why my SetCommand wasn’t being called. Why wasn’t CommandChanged firing either? Stupid mistake on my part — I hadn’t set the DataContext, so the binding expression failed.

Geek quote of the day: Git and Home Depot

Thursday, May 21st, 2009

Git is intimidating. It’s a distributed revision-control system, so it’d work online or off, and it’s got tons of cool toys (like git-bisect to automatically figure out which commit introduced a bug). But good luck figuring out which of the umpteen zillion commands you actually need to get something done. (I cheat — I IM my friend Sam and say, “Help?”)

Git has everything from fine-grained commands to handle a tiny part of a single commit, up through high-level commands that mow your lawn and make Julienne fries, and I have no idea how to tell which is which. Like I said, intimidating. Git has been described as not so much a revision-control system, but rather as a toolkit you can use to build your own revision-control system that works exactly the way you want it to. Which is kind of like writing your own lexer, parser, keyhole optimizer, runtime library, memory allocator, JIT compiler, and IDE, and designing custom hardware while you’re at it, and mining the silicon yourself, so you can write a programming language that works exactly the way you want it to.

And it doesn’t help that Git’s Windows support has been very slow in coming, though apparently now it’s mostly as good as on other platforms.

Yesterday I was working on a toy project that might amount to something someday, but that I was more likely to lose interest in after a few days. And I wanted revision control for it (I like diffs). But it didn’t feel worth creating a Subversion repository for something potentially throwaway. Git stores your repository right there in your working copy, which felt like a good fit. So I finally installed msysgit, and promptly found that it’s got some awesome features (I was skeptical of the index when I first heard about it, but it’s actually very cool, especially through the GUI — you can commit just certain lines from a file!… not sure how you run the unit tests on them, though), but that it’s got some stuff that truly sucks (the people who wrote the Git GUI have never heard of window resizing, word-wrapping, or context menus — and the terminology is deliberately confusing. If I can’t figure out how to revert a file, there’s a problem somewhere.)

While reading around, I happened across a mention of Mercurial, another distributed revision-control system, and I started sniffing around for comparisons between Mercurial and Git.

I hardly ever laugh out loud, but Jennie, from another room, called, “What’s so funny?”

From Use Mercurial, you Git!:

I ordered a version control system, not a toolkit for building one! If I’d wanted building blocks for rolling my own, I’d have gone to Home Depot and bought a 1 and a 0.


Joe White's Blog copyright © 2004-2008. Portions of the site layout use Yahoo! YUI Reset, Fonts, and Grids.
Proudly powered by WordPress. Entries (RSS) and Comments (RSS).