Archive for category .NET

ObservableCollection is a Leaky Abstraction

And so is BindingList. Or, rather, exposing them through your controller’s interface is a Leaky Abstraction.

Anyone who’s done any Windows desktop development has eventually come across ObservableCollection and BindingList. How often have you written a controller (ViewModel or Presenter, doesn’t matter what you call it, they’re all some variant of the Controller in MVC) that looks like this.

    public class LeakyWpfController : INotifyPropertyChanged
    {
        public ObservableCollection<Person> People { get; } = new ObservableCollection<Person>();

        public event PropertyChangedEventHandler PropertyChanged;
    }

Or this

    public class LeakyWinformsController
    {
        public BindingList<Person> People { get; } = new BindingList<Person>();
    }

What’s wrong with this code?! We need to expose a collection type that the framework understands for the databinding to work!

No. We don’t. Both Winforms and WPF don’t care what you expose. They only care that the backing field is of the proper type. All you need to expose in your public interface is an ICollection, in both cases. Databinding to these two controllers works perfectly well.

    public class WpfController : INotifyPropertyChanged
    {
        public ICollection<Person> People { get; } = new ObservableCollection<Person>();

        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class WinformsController
    {
        public ICollection<Person> People { get; } = new BindingList<Person>();
    }

Ok, so big deal. It’s not like I’m ever going to use my ViewModel or Presenter for anything but the specific View they were built for…

Are you so absolutely sure of this? If you’re certain that you’ll never want to use the same presentation logic in more than one window or application, then sure. You’re probably right. Leaking this abstraction doesn’t hurt, but what if we wanted to reuse logic from our old Winforms application in our new WPF app? Or what if we wanted to set ourselves up to migrate away from that old Winforms app into a new WPF application? What do we do when WPF and ObservableCollection aren’t the newest, greatest thing anymore and we’d like to migrate to that newest framework? Wouldn’t it be nice to be able to do so with minimal effort?

Our two controllers are at this point so similar, we can combine them into one. (Thanks to the fact that WPF supports BindingList as a backing field.)


    public class Controller : INotifyPropertyChanged, IController
    {
        public ICollection<Person> People { get; } = new BindingList<Person>();
        public ICommand AddItemCommand = new AddItemCommand(this);

        public event PropertyChangedEventHandler PropertyChanged;
    }

I only recommend using BindingList as a backing field if your Controller (view model/presenter) needs to work in a Winforms environment though. There are some performance issues with BindingList. If you only need to target WPF or UWP, then ObservableCollection is the right way to go. Either way, there’s no reason to expose anything more than an ICollection to the outside world.

Advertisements

, , , , , , ,

Leave a comment

Be Careful with ToList()

I recently came across some code during a review that seemed perfectly fine at first glance, but upon further inspection, had potential to perform terribly. Take a look. What’s wrong with this code?

using (var context = new DbContext())
{
context.SomeTable.Where(t => t.Id == someId)
.GroupBy(t => t.Category)
.Select(tg => new { tg.Category, Profit = tg.Sum(p => p.Profit) })
.ToList()
.ForEach(SaveToDb);
}

Do you see it? It’s easy to miss.

Calling ToList() on the Enumerable materializes the query, iterating over the Enumerable in order to generate the List. Then, just a moment later, we iterate over the List. We’ve potentially doubled the run time of this method. In most cases, likely not a big deal, but what if the List contains thousands of items? We’re doing more work than necessary here.

Fixing this is a simple matter of storing the IEnumerable in a variable and using the traditional foreach syntax instead of the ForEach extension method.

using (var context = new DbContext())
{
var query = context.SomeTable.Where(t => t.Id == someId)
.GroupBy(t => t.Category)
.Select(tg => new { tg.Category, Profit = tg.Sum(p => p.Profit) });

foreach(var item in query)
{
SaveToDb(item);
}
}

It just goes to show that you really have to be paying attention when reviewing (or writing!) code. Some issues can be terribly difficult to spot at a glance.

, , , , , ,

Leave a comment

Comments on Doc Comments

I was reviewing some VBA code over at Code Review Stack Exchange the other day and it got me to thinking about comments. The code wasn’t too bad, but there were so many comments in the code that, well…

I just read over this again and I think the fact that I mention the comments so often really highlights the issue. I barely even looked at the code because I was too distracted by all the comments.

Read the rest of this entry »

, , , , , ,

Leave a comment

Mocking the VBA Editor: Moq an IEnumerable that Works with Linq

It’s been a rough morning here. I’ve just spent six hours trying to properly create a mock for the VBProject interface. There’s very little information out there about this, so I thought I’d take a moment to jot this down and save someone else the headache. For all the grief this gave me, the solution is amazing simple.

Read the rest of this entry »

, , , , , , , , , ,

6 Comments

Using Hampers Testing: Enter the Factory

I’ve been writing a lot of C# lately, and paying a lot of attention to my test coverage while I’m at it. Everything was going great until I wanted to use the FolderDialogBrowser to let my users select a directory.

FolderDialogBrowser implements IDisposable, so I naturally reached for a Using block.

using (var folderPicker = new FolderBrowserDialog)
{
    if (folderPicker.ShowDialog() != DialogResult.OK)
    {
        return;
    }

    //...
}

Then I stopped dead. I can’t do that. This will display a GUI and any hope of running automated tests against this method is lost. Read the rest of this entry »

, , , , , , , , , , ,

Leave a comment

JDA Focus 2015

I don’t normally write about my work here, but I just spent the last week in sunny Orlando, FL at JDA Software’s Focus conference. I figured I might as well sum up the experience here before its all over and begins to fade.

For those of you not familiar with JDA, they’re a software company who has a range of products spanning the entire supply chain from manufacturer right down to actually placing the product on the shelf. My work brings me into the macro and micro space planning realms. Or rather, I support the people  in my company who use the Floor Planning and Space Planning software.  This involves automating that software and interacting with JDA’s database product.

Read the rest of this entry »

, ,

Leave a comment

Registering a COM Add-In with InstallSheild LE

I’m taking a quick time out from getting Version 1.2 of Rubberduck ready to talk a little bit about working with COM Add-Ins and Installshield’s installer builder. (Awkward phrase, I know.) First, let me say that I’m not impressed with InstallShield LE, not even a little bit. As awkward as that phrase was, this tool is so much worse. Granted, it could be that it’s a great tool and I’ve just not tried the alternatives yet… but I doubt it. Something out there has to be better. When I find it, I’ll let you know.

I’ve digressed though. I’m here for a reason. I fight with this setting in the installer each and every time I build a new version. Enough is enough. This is my documentation. You see, I spent a few days creating a new installer. The installer would build without error and install without error, only for me to receive a

Could not load the add-in.

message upon opening the VBA IDE. It’s incredibly frustrating, but here’s how to do it right.

When creating an add-in for the VBA Editor, or any MS Office application really, you have to register the assembly for COM Interop. Most of the blogs and tutorials out there show you how to do this with Regasm or Visual Studio. That’s fine for development, but if you want any one else to ever actually use your software, you’ll probably need to create an MSI package and/or a Setup.exe. That program will need to register the assembly on the target machine.

Go to the Project Assistant, and then to the Application Files screen. You’ll need to take a couple of Actions here to properly create the installer. Obviously, you’ll need to add the Primary Output. What’s not so obvious is that you’ll also need to manually link the *.tlb file by selecting installation folder, then the Add File button, and pointing to the file in your \bin\Release directory.

Adding tlb file

The second not so obvious (and most frustrating) thing is you’ll need to set the properties on the assembly correctly. So, right click on the Primary Output, and select Properties. In the dialog, go to the COM & .Net Settings tab. Once you’re there, use the settings below.

  • Extract COM Information
  • Scan at Build == Dependencies and Properties
  • Check the COM Interop box.
  • InstallSheild LE COM Settings 

    You’ll need to do the same for the *.tlb file, only don’t check the COM Interop box this time. 

    Now when you build the Assembly & Installer and then install, your COM Add-in will properly load. There’s a little more to getting your installer perfectly right than that, but I’m short on time and that hidden property is what tripped me up for the last few days. So, hopefully I’ve saved some one some pain. Even if that someone is me a month from now.

    Until next time, Happy Coding.

    , , , ,

    Leave a comment

    A Better Visual Studio for the Little Guy: First Impressions of Visual Studio Community

    I suppose that you’d have to be living under a rock if you haven’t heard by now, but Microsoft just announced some pretty big news. No, I’m not talking about how they just open sourced the .NET framework. I’m talking about the new free Visual Studio offering, Visual Studio Community.

    This isn’t just a rebranded Express. No, this is a full fledged IDE friends. There will be no more needing multiple versions of VS in order to build both web and desktop apps. This one does it all.

    This also isn’t just all of the different Express versions rolled into one either. In Scott Hanselman’s words, “This is practically Pro.” Community lets you start a process when the debugger starts, rather than attach it after the fact. That seems like a little thing, but trust me, it’s not. I’ve been working on a COM add in recently and this has saved me 3 or 4 clicks every time I need to step through some code. Community also gives you a full stack trace and exception information at the tips of your fingers. It helped me track down a bug in minutes that had been driving me mad for a week.

    VS Community is available for free to open source developers, for educational purposes, and companies with 5 or less developers. I really can’t recommend it enough. If you’re using Express, go get yourself a copy of Community. I’m sure I’ve not even really scratched the surface on what Community can do that Express can’t, so leave a comment with the best “new” features you’ve found.

    , , , ,

    Leave a comment