The ActionBar

In Android applications, the ActionBar is quickly emerging as a UI standard. Although its great, the ActionBar is only supported on Android 3.0 (API level 11, aka Honeycomb) and later. Since (either from prudence or incompetance) carriers seem to push new versions of Android out rather slowly, the majority of phones running Android are on 2x.

ActionBarSherlock and RoboGuice

There's a problem then, the ActionBar is nice, but only a small percentage of phones support it. Luckily, lots of smart folks have created ActionBar libraries for pre-3.0 Android, my favorite is ActionBarSherlock. ActionBarSherlock's API is identical to the native 3.0 ActionBar, and if the native ActionBar is available, ActionBarSherlock politely steps aside and uses it.

Another necessity, at least for me, when developing non-trivial applications is a dependency injection framework. DI frameworks are a big help, allowing me to attack large problems with a set of simple, testable, classes which collaborate but are not coupled. For Android, I'm currently using RoboGuice a popular extension of Google's Guice dependency injection framework. RoboGuice also ships with a nice set of classes easing some of the more annoying parts of developing Android apps. The problem is:

These libraries don't work in the same app

To make ActionBarSherlock work as well as it does, it includes the compatibility library and patches a few of the classes in it. A few of RoboGuice's classes such as RoboListActivity and RoboFragment extend classes from the compatibility library but not the ActionBarSherlock-patched compatibility library. The good news is that these libraries are solving different problems, and we can attack the DI side of the problem using RoboGuice and composition.

Here's a simple solution: extend the ActionBarSherlock-patched compatibility classes and get injection via composition using RoboGuice.getInjector().
// snip
import roboguice.RoboGuice;
import android.os.Bundle;
// this will use the ListFragment from ActionBarSherlock
import android.support.v4.app.ListFragment;
import android.view.View;

public class IocListFragment extends ListFragment {
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  // RoboGuice injection via Composition
  RoboGuice.getInjector(getActivity()).injectMembersWithoutViews(this);
 }
 @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
  super.onViewCreated(view, savedInstanceState);
  RoboGuice.getInjector(getActivity()).injectViewMembers(this);
 }
}
You can now extend from IocListFragment (or any other class you need to create in this way such as IocFragment) and get @Inject along with a nice ActionBar:
// snip
public class GameHistoryFragment extends IocListFragment {
 @InjectView(R.id.noGameHistoryTextView)
 TextView noGameHistoryTextView;
 
 @InjectView(R.id.currentGameButton)
 private Button currentGameButton;
 
 @Inject
 GameHistoryModel gameHistoryModel;
// snip
Fortunately you'll only need to extend a few classes in this way to make both of these libraries work in the same app. This solution feels a bit clunky, so if you know a better solution to this problem, please share it.
2

View comments

  1. I'm surprised to hear that this didn't "just work" with the RoboGuice 2.0 jar and ActionBarSherlock as a library project. ABS was meant to seamlessly replace the official compat library with little-to-no code changes (which only deal with Menu/MenuItem incidentally).

    If you are using maven you can use the <excludes> specification on the RoboGuice dependency to remove its transitive dependency on the official compat lib. Then ActionBarSherlock 3.x should fulfill that requirement since its classes exist in the same package. This was reported to have worked on the Google Group for ABS.

    I haven't yet had time to experiment with implementing both of these libraries in the same project (yet!) but hopefully the coming changes to ADT and library projects will allow the inclusion of both to be much easier.

    After all, it is without a doubt a winning combination.

    ReplyDelete
  2. Hey Jake,
    Thanks for the info, resolving this when building sure beats writing a few awful one-off classes. I'll give that a shot and edit my post with the results.

    ReplyDelete
  1. The ActionBar

    In Android applications, the ActionBar is quickly emerging as a UI standard. Although its great, the ActionBar is only supported on Android 3.0 (API level 11, aka Honeycomb) and later. Since (either from prudence or incompetance) carriers seem to push new versions of Android out rather slowly, the majority of phones running Android are on 2x.

    ActionBarSherlock and RoboGuice

    There's a problem then, the ActionBar is nice, but only a small percentage of phones support it. Luckily, lots of smart folks have created ActionBar libraries for pre-3.0 Android, my favorite is ActionBarSherlock. ActionBarSherlock's API is identical to the native 3.0 ActionBar, and if the native ActionBar is available, ActionBarSherlock politely steps aside and uses it.

    Another necessity, at least for me, when developing non-trivial applications is a dependency injection framework. DI frameworks are a big help, allowing me to attack large problems with a set of simple, testable, classes which collaborate but are not coupled. For Android, I'm currently using RoboGuice a popular extension of Google's Guice dependency injection framework. RoboGuice also ships with a nice set of classes easing some of the more annoying parts of developing Android apps. The problem is:

    These libraries don't work in the same app

    To make ActionBarSherlock work as well as it does, it includes the compatibility library and patches a few of the classes in it. A few of RoboGuice's classes such as RoboListActivity and RoboFragment extend classes from the compatibility library but not the ActionBarSherlock-patched compatibility library. The good news is that these libraries are solving different problems, and we can attack the DI side of the problem using RoboGuice and composition.

    Here's a simple solution: extend the ActionBarSherlock-patched compatibility classes and get injection via composition using RoboGuice.getInjector().
    // snip
    import roboguice.RoboGuice;
    import android.os.Bundle;
    // this will use the ListFragment from ActionBarSherlock
    import android.support.v4.app.ListFragment;
    import android.view.View;
    
    public class IocListFragment extends ListFragment {
     @Override
     public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      // RoboGuice injection via Composition
      RoboGuice.getInjector(getActivity()).injectMembersWithoutViews(this);
     }
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
      super.onViewCreated(view, savedInstanceState);
      RoboGuice.getInjector(getActivity()).injectViewMembers(this);
     }
    }
    You can now extend from IocListFragment (or any other class you need to create in this way such as IocFragment) and get @Inject along with a nice ActionBar:
    // snip
    public class GameHistoryFragment extends IocListFragment {
     @InjectView(R.id.noGameHistoryTextView)
     TextView noGameHistoryTextView;
     
     @InjectView(R.id.currentGameButton)
     private Button currentGameButton;
     
     @Inject
     GameHistoryModel gameHistoryModel;
    // snip
    Fortunately you'll only need to extend a few classes in this way to make both of these libraries work in the same app. This solution feels a bit clunky, so if you know a better solution to this problem, please share it.
    2

    View comments

    1. I'm surprised to hear that this didn't "just work" with the RoboGuice 2.0 jar and ActionBarSherlock as a library project. ABS was meant to seamlessly replace the official compat library with little-to-no code changes (which only deal with Menu/MenuItem incidentally).

      If you are using maven you can use the <excludes> specification on the RoboGuice dependency to remove its transitive dependency on the official compat lib. Then ActionBarSherlock 3.x should fulfill that requirement since its classes exist in the same package. This was reported to have worked on the Google Group for ABS.

      I haven't yet had time to experiment with implementing both of these libraries in the same project (yet!) but hopefully the coming changes to ADT and library projects will allow the inclusion of both to be much easier.

      After all, it is without a doubt a winning combination.

      ReplyDelete
    2. Hey Jake,
      Thanks for the info, resolving this when building sure beats writing a few awful one-off classes. I'll give that a shot and edit my post with the results.

      ReplyDelete
  2. In my last post, we wrote a set of unit tests exercising ConsoleInputService, MessageService, and ConsoleOutputService. We tested these classes thoroughly, and in isolation since their behavior was easier to test in a controlled environment. Its now time to test our main stimulation class Magic8BallSimulator.

    Remember our humble Magic8BallSimulator class? If not, here's a quick refresh:
    // snip
      // our "dependencies" are now interfaces
      private readonly IMessageService _messageService;
      private readonly IInputService _inputService;
      private readonly IOutputService _outputService;
    
      // we're now injecting Interfaces, this loosens our coupling to our "injected" dependencies
      public Magic8BallSimulator(IMessageService messageService, IInputService inputService,
       IOutputService outputService) {
       _messageService = messageService;
       _inputService = inputService;
       _outputService = outputService;
      }
    
      public void Run() {
       _outputService.PrintWelcome();
       string message = string.Empty;
    
       _outputService.PrintInputPrompt();
       _inputService.GetInput();
    
       while (!_inputService.ExitWasRequested()) {
        message = _messageService.GetMessage();
        _outputService.PrintMessage(message);
        _outputService.PrintInputPrompt();
        _inputService.GetInput();
       }
    
       _outputService.PrintExit();
      }
    // snip
    This class depends on IMessageService, IInputService, and IOutputService and those dependencies are injected via Magic8BallSimulator's constructor. Since unit testing requires a controlled environment, we'll need to make sure that the instances of IMessageService, IInputService, and IOutputService that we instantiate and inject behave in predictable ways. Remember, unit tests aim to test a simple unit of code, and for our purposes a "unit" is a method within a class.

    So we have a problem

    We need to make sure that the instances of IMessageService, IInputService, and IOutputService that we instantiate and inject into Magic8BallSimulator behave in predictable ways, but we want those instances to behave in different predictable ways for different tests. Consider this test:

    [Test]: We want to make sure Magic8BallSimulator prints an exit message before it exits.

    To get our injected instances to behave in the way we need them to for this test, we'll have to do the following:
    • Create a InputServiceStub class implementing IInputService. All the method-bodies in in this class will be empty except for ExitWasRequested() which will always return true
    • Create a OutputServiceStub class implementing IOutputService. All the method-bodies in this class will also be empty empty expect for PrintExit() which will set a public PrintExitCalled property to true when called.
    • Create a MessageServiceStub class implementing IMessageService with empty methods.
    • Instantiate the 3 classes above. Instantiate Magic8BallSimulator and inject our 3 test instances
    • call Magic8BallSimulator.Run(), and then make sure that OutputServiceStub.PrintExitCalled is true.
    No Thanks!

    That's too much code for us to write and maintain to test 1 case. We still have to test Magic8BallSimulator, however, after-all they pay us to write software :) The problem is, we don't want to have to write three classes to test 1 case. One way out might be to create 3 abstract classes implementing IMessageService, IInputService, and IOutputService and then extend those class only filling in the method-bodies we need for our test. That still turns out to be a ton of code to maintain, and we'd like our application to be fun to work on, not a pain in the ass. Here's a better way.

    I love Moq. Check this out

    We can leverage the badass, open-source, Moq library to create mock implementations of IMessageService, IInputService, and IOutputService and then use lambda expressions to stand in for the methods we want. We can then inject those mock classes into Magic8BallSimulator. Feel the lightness of the test below :)
    // snip
      [Fact]
      public void PrintExitIsCalledOnExitRequested() {
       // mocked IMessageService
       var messageService = new Mock();
    
       var inputService = new Mock();
       // this is cool, we're getting a free mock of IInputService and we can specify
       // how the ExitWasRequested() method will behave by a lambda expression (as you
       // can see, it always returns true
       inputService.Setup(s => s.ExitWasRequested()).Returns(true);
    
       // outservice mock
       var outputService = new Mock();
    
       // setup and run our simulator
       Magic8BallSimulator magic8BallSimulator = new Magic8BallSimulator(
        messageService.Object,
        inputService.Object,
        outputService.Object
       );
       magic8BallSimulator.Run();
    
       // a simple assertion *verifying* that the PrintExit() method was called
       outputService.Verify(s => s.PrintExit());
      }
    // snip
    Hey, make sure you read the comments above, that's where the good explanations are! Now that we're able to use Moq to mock our dependencies, additional tests are easy! Here are 3 more:
    // snip
      [Fact]
      public void GetMessageIsNotCalledAfterExitRequested() {
       var messageService = new Mock();
    
       var inputService = new Mock();
       inputService.Setup(s => s.ExitWasRequested()).Returns(true);
    
       var outputService = new Mock();
    
       Magic8BallSimulator magic8BallSimulator = new Magic8BallSimulator(
        messageService.Object,
        inputService.Object,
        outputService.Object
       );
       // verify that GetMessage() was *not* called
       messageService.Verify(s => s.GetMessage(), Times.Never());
      }
    
      [Fact]
      public void PrintWelcomeIsCalledOnRun() {
       var messageService = new Mock();
    
       var inputService = new Mock();
       inputService.Setup(s => s.ExitWasRequested()).Returns(true);
    
       var outputService = new Mock();
    
       Magic8BallSimulator magic8BallSimulator = new Magic8BallSimulator(
        messageService.Object,
        inputService.Object,
        outputService.Object
       );
       magic8BallSimulator.Run();
       outputService.Verify(s => s.PrintWelcome());
      }
    
      [Fact]
      public void PrintInputPromptIsCalledOnRun() {
       var messageService = new Mock();
    
       var inputService = new Mock();
       inputService.Setup(s => s.ExitWasRequested()).Returns(true);
    
       var outputService = new Mock();
    
       Magic8BallSimulator magic8BallSimulator = new Magic8BallSimulator(
        messageService.Object,
        inputService.Object,
        outputService.Object
       );
       magic8BallSimulator.Run();
       outputService.Verify(s => s.PrintInputPrompt());
      }
    // snip

    That's it. It's been fun!

    Here's the source code for this post. Thanks so much for reading these posts on Dependency Injection and Unit Testing. I had lots of fun writing these and only hope my silly examples and code-snippets were clear. If you have any questions, go ahead and leave a comment and I'll try to help you out.
    10

    View comments

  3. In the previous post, I showed one way to wire Autofac and WebORB together to achieve AMF-Remoting as well as Dependency Injection. This post builds on the last one by providing an inplementation using Autofac and FlourineFx, the latter is a great open-source .NET AMF Remoting solution.

    Here's the the source code for this post so you won't have to figure out the context of the snippets below.

    Add the following to your WEB-INF\flex\services-config.xml:To tie FlourineFx to Autofac, we'll create and register our own custom Factory (we have to implement the FlourineFx's IFlexFactory interface) and instantiate our objects by resolving them from the DI Container.As in the previous example using WebORB, you now modify your Flex client to use our new destination and exposed interface like this:If there's an easier way to integrate FlourineFx and Autofac, I'd love to hear it, though the above is quite easy :)
    2

    View comments

  4. Imagine that we've built a large middle-tier in C# for a Flex client and have decided to remote objects to and from Flex via AMF. AMF is a great choice for us since it's a lightweight, binary, protocol which is easily de-serialized by the Flash Player (we picked the Flash Player as our client because of its current popularity).

    Since our middle-tier code-base is large and complex, we've attacked that complexity by making lots of simple, loosely coupled, Single Responsibility classes. We've read about Dependency Injection and expect that if we use that general approach, we'll end up with code which is both flexible and easy to test. We'd like to avoid writing the Dependency Injection plumbing ourselves however, so we've decided to leverage Autofac to help. We've also decided to use WebORB to handle the translation of our .NET objects to Flex DTOs/VOs. Using Autofac and WebORB will allow us to focus on our business logic without concerning ourselves with translating to and from AMF and writing the necessary plumbing for Dependency Injection respectively.

    We've decided to create a set of service classes which Flex can access through WebORB. Since these classes are handling client requests directly, they often depend on other injected classes to handle some of the work-load. These dependencies also keep the service classes clean, small and easy to understand. We'd also like to provide these dependent classes to our service classes through Autofac.

    There are problems

    We've chosen two great tools to help, but we've a few problems to work out first:
    1. Out of the box, to use our service classes in WebORB we'll need to create default constructors in them. This is unpleasant since we'd like to inject our dependent classes as constructor arguments.

    2. To expose our Service classes to Flex, we have 2 options:

      1. Expose our service classes directly to Flex, so our client can remote to, say, WebORBAutofacTest.TestService
      2. Create an alias which maps to each of our service classes so our client can remote to, say, AppTestService

      The problem with (1) is that our Flex clients shouldn't know about the specific classes they're using on the middle-tier. This leaves us free to modify, rename, of delete those classes without the fear of breaking our client. Although this makes (2) a better option, (2) is still a bit more work because we'll have to maintain our aliases which reside in a non compiler-checked config file somewhere.

    3. We have no idea how to get new instances of our service classes created and their dependencies injected. In other words, we cannot get WebORB working with Autofac.
    Our goal
    1. We want to inject dependencies into our service classes as constructor arguments (and we'd like for Autofac to instantiate these dependent classes for us).
    2. We'd like to expose only the interfaces implemented by our service classes to our Flex client (that's a more familiar approach on the mid-tier)
    3. and finally, we don't want to constantly update configuration files for AMF remoting
    A solution

    First go ahead and get the source code for this post so you won't have to cut and paste annoying code snippets.

    Next we'll follow the ASP.NET Integration instructions in the all-around great Autofac wiki. After you've read the wiki entry, have a look at this simple ContainerSetup class below. This class is called by our Global.asax class to register our dependencies and help Global.asax implement IContainerProviderAccessor:
    Here's the relevant section of my Global application class:The snippet above informs the classes in our application that the main application class Global is an IContainerProviderAccessor providing access to a ContainerProvider allowing callers to access the DI Container and resolve dependencies. We'll make good use of this property.

    To tie WebORB to Autofac, we'll create and register our own custom Activator (we have to implement the IActivator interface, see the WebORB docs if you want to know more about Custom Activators) and instantiate our objects by resolving them from the DI Container.Configuration files

    We now have to register our new DependencyActivator class in weborb.config luckily we'll only have to modify these configuration files once:Now we have to update 2 XML files which our Flex client will compile against. These files define how and where Flex will send data when remoting. First we'll create a new channel-definition in WEB-INF\flex\services-config.xml:Then we'll add a destination in WEB-INF\flex\remoting-config.xml:We now have Dependency Injection in our service classes via Autofac
    Now we can finally modify our Flex client to use the new DependencyGenericDestination in its RemoteObjects. Notice that we're exposing WebORBAutofacTest.ITestService hey that's an interface!Solution benefits and drawbacks

    Benefits to this approach:
    1. You get a Type passed into DependencyActivator, which works nicely with Autofac's Resolve method.
    2. You do not have to make any modifications to your service classes for this to work (in fact your service classes do not need to depend on WebORB or Autofac at all).
    3. You can expose your Service classes as Interfaces.
    Drawbacks to this approach:
    1. Instantiation of classes that don't use Autofac will be slowed down by DependencyActivator going to Autofac first. To avoid this slow-down you'll have to pick a different destination in the relevant RemoteObjects in your Flex client
    If any of you folks see a better way of accomplishing the goals I set out to tackle using WebORB and Autofac, by all means post a comment.
    1

    View comments

  5. In my last post, we identified that the SimulationRunner class violated the Single Responsibility Principle by concerning itself with:
    • Setting up our application, (in fact SimulationRunner created an instance of every class in the application)
    • Running our application (via simulator.Run())
    (In case you've forgotten, the Single Responsibility Principle is the assertion that there should never be more than one reason for a class to change). We addressed the disparate responsibilities in SimulationRunner by creating the ContainerSetup class and leveraging Autofac (a badass Dependency Injection framework) to create and wire-in instances of our dependencies for us (i.e. setup our application).

    We've arrived at code which is easy to change. That's valuable for our requirements will certainly change. There's only one rather large lingering concern:

    I'm not sure it works

    As our code stands now, I've no justification for believing that our application will work correctly in every circumstance. If you're sure, then you're new to this and new developers seem to know everything :) For us to be sure our code is solid, we need evidence, but why gather evidence if you're certain this application won't break? See the problem? We'll gather our evidence via a suite of simple Unit Tests.

    Unit Tests

    A Unit Test is a simple test of a small unit of code, for our purposes, units will be single methods. Remember our ConsoleInputService class?
    // snip
     public class ConsoleInputService : IInputService {
      private string input = "input-initializer";
    
      public string GetInput() {
       input = Console.ReadLine();
       return input;
      }
    
      public bool ExitWasRequested() {
       return String.IsNullOrEmpty(input);
      }
     }
    // snip
    Here's a simple set of unit tests for ConsoleInputService. We're testing the following cases below:
    • The ConsoleInputService.GetInput() accurately returns console input
    • The ConsoleInputService.ExitWasRequested() returns true when it reads a new-line from console input
    • The ConsoleInputService.ExitWasRequested() returns true when it reads empty input from the console
    • The ConsoleInputService.ExitWasRequested() returns true when it reads a new-line from console input
    • The ConsoleInputService.ExitWasRequested() returns true when it reads a string containing only spaces from console input
    // snip
     public class ConsoleInputServiceTests {
      private ConsoleInputMock consoleMock;
    
      public ConsoleInputServiceTests() {
       consoleMock = new ConsoleInputMock();
      }
    
      [Fact]
      public void ConsoleInputIsReturnedByGetInput() {
       string testInput = "This is test input.";
       consoleMock.GivenConsoleInputOf(testInput);
    
       ConsoleInputService service = new ConsoleInputService();
       string input = service.GetInput();
       consoleMock.CloseConsoleInput();
    
       Assert.Equal(testInput, input);
      }
    
      [Fact]
      public void ExitIsRequestedOnNewlineInput() {
       consoleMock.GivenConsoleInputOf(Environment.NewLine);
    
       ConsoleInputService service = new ConsoleInputService();
       service.GetInput();
       consoleMock.CloseConsoleInput();
    
       bool exitWasRequested = service.ExitWasRequested();
       Assert.True(exitWasRequested);
      }
    
      [Fact]
      public void ExitIsRequestedOnEmptyInput() {
       consoleMock.GivenConsoleInputOf(String.Empty);
    
       ConsoleInputService service = new ConsoleInputService();
       service.GetInput();
       consoleMock.CloseConsoleInput();
    
       bool exitWasRequested = service.ExitWasRequested();
       Assert.True(exitWasRequested);
      }
    
      [Fact]
      public void ExitIsRequestedOnWhitespaceInput() {
       consoleMock.GivenConsoleInputOf(" ");
    
       ConsoleInputService service = new ConsoleInputService();
       service.GetInput();
       consoleMock.CloseConsoleInput();
    
       bool exitWasRequested = service.ExitWasRequested();
       Assert.True(exitWasRequested);
      }
     }
    // snip
    The ConsoleInputMock class below is a simple test helper which simulates a given string coming from the console as input. Often to isolate a single class to test its methods, you have to do sneaky things like this.
    // snip
     public class ConsoleInputMock {
      private StringReader consoleInputReader;
    
      // sets up the Console with a given input string
      public void GivenConsoleInputOf(string consoleInput) {
       if (consoleInputReader != null)
        CloseConsoleInput();
    
       consoleInputReader = new StringReader(consoleInput);
       Console.SetIn(consoleInputReader);
      }
    
      public void CloseConsoleInput() {
       consoleInputReader.Close();
       consoleInputReader.Dispose();
       consoleInputReader = null;
      }
     }
    // snip
    As a general guideline, unit tests should be self-contained, clearly named, and as simple as possible. They should also only test one thing. This is important for when a test fails, its helpful to know exactly what broke. Have another look at the methods in ConsoleInputServiceTests above, you should be able to see what they're testing based on their names (e.g. ExitIsRequestedOnEmptyInput). Speaking of testing, here's a screen-shot of the output of the tests in ConsoleInputServiceTests, see the failure?
    ExitIsRequestedOnWhitespaceInput failed. When ConsoleInputService.ExitWasRequested() encountered input that was just spaces, we expected it to return true, signalling that the user wished to exit. It evidently sees that as valid input. Let's fix ConsoleInputService.GetInput() to trim all input and re-run ConsoleInputServiceTests.
    // snip
      public string GetInput() {
       input = Console.ReadLine();
       if (!String.IsNullOrEmpty(input))
        input = input.Trim();
    
       return input;
      }
    // snip
    We can now re-run our ConsoleInputServiceTests and we pass.
    A few tests of the MessageService and ConsoleOutputService classes are included in the source code for this post as well, to run it, make sure you grab a copy of xunit, unpack it somewhere meaningful like C:\Program Files\xunit-1.6.1 then goto the Properties of the Pass4Tests project and in the Debug section set Start external program: to point to one of the xunit.console executables. Your setup should look similar to this:

    Up Next

    In the next post we'll tackle unit testing the Magic8BallSimulator class which is more interesting since it contains 3 dependencies.

    Happy testing.
    0

    Add a comment

  6. In my last post, we implemented a set of interfaces in our service-classes and injected those interfaces into the Magic8BallSimulator class. This de-coupling of Magic8BallSimulator and its dependencies, allowed us to radically change how we output text in our application without breaking it. Here's the Magic8BallSimulator constructor we ended up with last time, it's nice and de-coupled:
      // snip
      // we're now injecting Interfaces, this loosens our coupling to our "injected" dependencies
      public Magic8BallSimulator(IMessageService messageService, IInputService inputService,
       IOutputService outputService) {
       _messageService = messageService;
       _inputService = inputService;
       _outputService = outputService;
      }
      // snip
    Here's our previous implementation of the the SimulationRunner program (I dropped our crazy MultipleOutputService class in favor of ConsoleOutputService for the moment):
    // snip
     public class SimulationRunner {
      static void Main(string[] args) {
       Magic8BallSimulator simulator = new Magic8BallSimulator(
        new MessageService(),
        new ConsoleInputService(),
        new ConsoleOutputService()
       );
       simulator.Run();
      }
     }
    // snip

    Wait a moment

    Have a look at the SimulationRunner class above one more time. SimulationRunner is closely coupled to several specific classes, namely Magic8BallSimulator, MessageService, ConsoleInputService, and ConsoleOutputService. There's also a more subtle problem with SimulationRunner, it has more than 1 responsibility. SimulationRunner is currently:
    • Setting up our application, in fact it creates a new instance of every class in the application
    • Running our application (via simulator.Run())
    Certainly SimulationRunner ought to have the responsibility of running our application, but how can solve our two remaining problems of:
    1. Removing our application's setup responsibility from SimulationRunner, and
    2. de-coupling SimulationRunner from specific instances of our service classes?
    Our attack will involve using a Dependency Injection framework and a new class whose sole responsibility is setting up our application.

    Autofac (https://github.com/autofac/Autofac/) - a badass Dependency Injection framework for .NET.

    Here's an absurdly brief overview of what Autofac can do for us (if you want more information, check-out the above link to Autofac's google-code site or this article on CodeProject). Autofac allows us to register classes like MessageService as implementations of specific interfaces (like IMessageService). Here's the best part, if we register all our dependencies for Magic8BallSimulator as well as Magic8BallSimulator itself with Autofac, Autofac will also examine Magic8BallSimulator's constructor parameters and inject the registered dependent classes for us. That kicks ass!

    Here's our new ContainerSetup class, it registers our application classes with Autofac and does our application setup work.
    //snip
     public class ContainerSetup {
      private ContainerBuilder builder;
    
      public IContainer BuildContainer() {
       builder = new ContainerBuilder();
    
       // in English this reads, setup ConsoleInputService as the implementation of
       // IInputService
       builder.RegisterType().As();
       // Magic8BallSimulator doesn't implement an interface, its registered as-is
       builder.RegisterType();
       builder.RegisterType().As();
       builder.RegisterType().As();
    
       return builder.Build();
      }
    }
    //snip
    
    Inside BuildContainer() we're registering the classes that Autofac will provide when their relevant interfaces are requested. For example, on line 10, we're registering ConsoleInputService as the class to use when one of our classes has a dependency on the IInputService interface (hey, Magic8BallSimulator depends on that interface!). Notice that we didn't map Magic8BallSimulator to anything, it doesn't implement an interface.

    Problem Solved!

    Here's our new SimulationRunner class. It's de-coupled from the specific classes in our application and is free of all setup responsibilities. It's asking Autofac for the class to run (that's the call to Resolve() on line 6):
    //snip
     public class SimulationRunner {
      static void Main(string[] args) {
       ContainerSetup containerSetup = new ContainerSetup();
       IContainer container = containerSetup.BuildContainer();
       container.Resolve().Run();
      }
     }
    //snip
    
    As I mentioned before, since we've registered our Magic8BallSimulator class with Autofac as well as its dependencies (MessageService, ConsoleInputService, and ConsoleOutputService), Autofac will create and inject instances of those dependent classes into Magic8BallSimulator for us. Scroll up and look at the old Magic8BallSimulator constructor, it hasn't changed at all :)

    For the curious

    To keep this post relatively simple, I dropped our crazy MultipleOutputService class in favor of ConsoleOutputService. Remember MultipleOutputService? We used that class to show how de-coupling with interfaces allowed us to radically change a whole section of our application (and even its behavior) without breaking anything. It's also worth noting that MultipleOutputService's constructor takes a file-path string as it's argument.

    If we wanted to use MultipleOutputService as our implementation of IOutputService we'd make the following change to our ContainerSetup class:
    //snip
       //builder.RegisterType().As();
       string outputFilePath = Path.Combine(Path.GetTempPath(), "magic8BallOutput.txt");
       builder.Register(c => new MultipleOutputService(outputFilePath)).As();
    //snip
    In the code above, we're still specifying MultipleOutputService as our implementation of IOutputService, but we're also providing Autofac with a simple lambda expression to use when creating MultipleOutputService. The good news is, if we keep the code above, nothing else has to change (we'll still get radically different output behavior).

    Source code for this post.

    but wait, there's more

    Steve asked a great question: But what if I want to use both MultipleOutputService and ConsoleOutputService? Say there is a user option to select which method to output with, can a DI framework handle this for me?

    Since it's trivial to register more than one implementation of IOutputService with the dependency injection framework, the framework can still help us here. We'll have to write the user-activated output switch option though :) Here's the approach I see:
    1. Remove MultipleOutputService and add PopupOutputService and FileOutputService to express our new modes of output. We'll also keep ConsoleOutputService around since one of our options is to print to the console.

    2. Since this silly example currently runs in the console, I'm going to let users pass a few command-line parameters specifying how they'd like their output delivered. Legal parameter values will be: "popup","file","console", and "all". If we get odd combinations like "console all" we'll assume "all".

    3. We'll also need a class to hold our configuration. That class we'll be constructed by parsing our command-line arguments and will be passed into our ContainerSetup.BuildContainer method so we'll know which classes to regsiter as implementations of IOutputService.
    Here's our configuration class, aptly named Config:
    //snip
     // an enumeration expressing our different output modes
     public enum OutputModes { console, popup, file, all };
    
     // holds our configuration, this class will be easy to expand later on
     // if we need to
     public class Config {
      public List OutputModes { get; private set; }
    
      public Config(List outputPreferences) {
       OutputModes = outputPreferences;
      }
     }
    //snip
    Here's ArgumentsParser its whole point in life is to sanity-check and parse our command-line arguments:
    //snip
     public class ArgumentsParser {
      private string[] arguments;
      private string requestedOutputMode = string.Empty;
    
      // default output mode when no args specified
      private List outputModes = new List(){ OutputModes.console };
    
      public ArgumentsParser(string[] args) {
       arguments = args;
      }
    
      public Config GetConfig() {
       SanityCheckArgs();
    
       return new Config(outputModes);
      }
    
      private void SanityCheckArgs() {
       // no-args to check
       if (arguments.Length == 0)
        return;
    
       // too many args
       if (arguments.Length > 3)
        throw new ArgumentException(
         "Too many arguments were specified, expected 'console','popup','file', or 'all'");
    
       SetupOutputModes();
      }
    
      private void SetupOutputModes() {
       outputModes = new List();
    
       // see if each requested output-mode exists in our struct
       foreach (string outputModeRequested in arguments) {
        try {
         outputModes.Add(
          (OutputModes)Enum.Parse(typeof(OutputModes), outputModeRequested, true)
         );
        } catch {
         throw new ArgumentException(String.Format(
          "Illegal output mode '{0}' requested, expected 'console','popup','file', or 'all'",
          outputModeRequested));
        }
       }
       // handles odd input like "console all"
       if( outputModes.Contains(OutputModes.all) )
        outputModes = new List() { OutputModes.all };
      }
    
     }
    //snip
    Here are our change to ContainerSetup.BuildContainer, notice the new config parameter:
    //snip
      public IContainer BuildContainer(Config config) {
       _config = config;
       // snip - previous code is still valid
    
       // we're now registering our IOutputService based on our pass config configuration class
       if (_config.OutputModes.Contains(OutputModes.console) || _config.OutputModes.Contains(OutputModes.all))
        builder.RegisterType().As();
    
       if (_config.OutputModes.Contains(OutputModes.popup) || _config.OutputModes.Contains(OutputModes.all))
        builder.RegisterType().As();
    
       if (_config.OutputModes.Contains(OutputModes.file) || _config.OutputModes.Contains(OutputModes.all)) {
        string outputFilePath = Path.Combine(Path.GetTempPath(), "magic8BallOutput.txt");
        builder.Register(c => new FileOutputService(outputFilePath)).As();
       }
    
       return builder.Build();
      }
    //snip
    We're now expecting a collection of IOutputService's in Magic8BallSimulator, so we'll modify that class as follows (notice the new IEnumerable constructor parameter and the _outputServices property:
    //snip
      private IEnumerable _outputServices;
    
      // we're now injecting Interfaces, this loosens our coupling to our "injected" dependencies
      public Magic8BallSimulator(IMessageService messageService, IInputService inputService,
       IEnumerable outputServices) {
       _messageService = messageService;
       _inputService = inputService;
       _outputServices = outputServices;
      }
    
      public void Run() {
       PrintWelcome();
       string message = string.Empty;
       PrintInputPrompt();
       _inputService.GetInput();
    
       while (!_inputService.ExitWasRequested()) {
        message = _messageService.GetMessage();
    
        PrintMessage(message);
        PrintInputPrompt();
        _inputService.GetInput();
       }
    
       PrintExit();
      }
    
      private void PrintWelcome() {
       foreach (IOutputService outputService in _outputServices)
        outputService.PrintWelcome();
      }
      private void PrintInputPrompt() {
       foreach (IOutputService outputService in _outputServices)
        outputService.PrintInputPrompt();
      }
      private void PrintMessage(string message) {
       foreach (IOutputService outputService in _outputServices)
        outputService.PrintMessage(message);
      }
      private void PrintExit() {
       foreach (IOutputService outputService in _outputServices)
        outputService.PrintExit();
      }
    //snip
    And finally, here's our new SimulationRunner tying it all together:
    //snip
      static void Main(string[] args) {
       ContainerSetup containerSetup = new ContainerSetup();
       IContainer container = containerSetup.BuildContainer();
       container.Resolve().Run();
      }
    //snip
    ThePopupOutputService and FileOutputService classes were trivial, I've added those to the new source-code for this section of the post as well.

    Unit Tests up next

    Although our new code is de-coupled, to ensure that its solid, we'll need to test it a bit. We'll start by testing each class separately. >> Next Post
    4

    View comments

  7. In my last post, we finally injected dependencies into our Magic8BallSimulator class, but soon realized that by injecting specific classes with specific behaviors we were coupling Magic8BallSimulator to its dependencies. We discussed how this kind of coupling would make our application brittle for the following reasons:
    1. If we want to change, say, ConsoleOutputService we risk breaking Magic8BallSimulator too, since it depends directly on ConsoleOutputService (and changing the output on the console really shouldn't break our entire application).

    2. If we get a requirements change to alter how we output messages, say, to send them as Instant Messages or via Email, we'll have to rip out ConsoleOutputService and change Magic8BallSimulator as well. This makes our application less maintainable because changes to one section break and cascade to other parts of our application making the whole thing a pain in the ass to work on.
    Here's the Magic8BallSimulator constructor we ended up with last time:
    //snip
      public Magic8BallSimulator(MessageService messageService, ConsoleInputService ConsoleInputService,
       ConsoleOutputService ConsoleOutputService) {
       _messageService = messageService;
       _ConsoleInputService = ConsoleInputService;
       _ConsoleOutputService = ConsoleOutputService;
      }
    //snip
    We decided that we needed to alter Magic8BallSimulator to depend upon abstractions instead of concrete implementations, making Magic8BallSimulator loosely coupled to the classes it depends on.

    Consider our ConsoleOutputService class. It's a concrete class which has a specific behavior. It prints output to the console, and it's "to the console" behavior is rather specific don't you think? This means that when we inject ConsoleOutputService into Magic8BallSimulator, Magic8BallSimulator knows not only that ConsoleOutputService outputs things, but how it outputs them as well. Now how ConsoleOutputService outputs things is its own concern, and we'd like to keep our application flexible enough so we can change how we output things without without breaking Magic8BallSimulator. The solution is simple, we need to tell Magic8BallSimulator that we have a class capable of handling output, but not how that class does its job. Here's the solution to our output problem:

    Interfaces!

    IOutputService - a contract to provide output functionality
    //snip
     public interface IOutputService {
      void PrintExit();
      void PrintInputPrompt();
      void PrintMessage(string message);
      void PrintWelcome();
     }
    //snip
    This bit is important:

    IOutputService is a simple contract which says "I agree to provide the following behavior (PrintExit, PrintInputPrompt etc), but how I work inside is no one else's concern. Now we only need a simple modification to ConsoleOutputService to complete our de-coupling.

    ConsoleOutputService - implements IOutputService and prints to the console
    //snip
     class ConsoleOutputService : IOutputService {
      //snip - this is the only change to ConsoleOutputService , really, that's it.
     }
    //snip
    Let's modify Magic8BallSimulator's constructor to take its new de-coupled dependency (notice we're now passing in an IOutputService interface instead of an instance of the specific ConsoleOutputService class):
    //snip
      private IOutputService _outputService;
    
      // we're now injecting an Interface, this loosens our coupling to our "injected"
      // ConsoleOutputService dependency
      public Magic8BallSimulator(MessageService messageService, ConsoleInputService inputService,
       IOutputService outputService) {
       _messageService = messageService;
       _inputService = inputService;
       _outputService = outputService;
      }
    //snip
    2 more Interfaces

    Let's de-couple Magic8BallSimulator from, the rest of its dependencies. Here are our remaining interfaces:
    //snip
     public interface IInputService {
      bool ExitWasRequested();
      string GetInput();
     }
    
     public interface IMessageService {
      string GetMessage();
     }
    //snip
    I won't bore you with pasting copies of ConsoleInputService implementing IInputService or of MessageService implementing IMessageService (see the zip file for that code). Stay with me, things are about to get interesting.

    Success!

    here's our new Magic8BallSimulator class:
    // snip
      // our "dependencies" are now interfaces
      private IMessageService _messageService;
      private IInputService _inputService;
      private IOutputService _outputService;
    
      // we're now injecting Interfaces, this loosens our coupling to our "injected" dependencies
      public Magic8BallSimulator(IMessageService messageService, IInputService inputService,
       IOutputService outputService) {
       _messageService = messageService;
       _inputService = inputService;
       _outputService = outputService;
      }
    //snip
    Magic8BallSimulator still has its dependencies injected, and behaves the way it did in the last post (in other words, we didn't break anything). Magic8BallSimulator still relies on the services provided by its dependent classes, but now it's de-coupled from the concrete details of how those classes do their work. Don't believe me?

    Check this out

    A really different implementation of IOutputService:
    Yeah, that's certainly *different* :)
    Here's the new implementation of IOutputService, check out PrintMessage(), it prints messages to the screen, a file, and within a Windows-forms MessageBox:
    //snip
     public class MultipleOutputService : IOutputService {
      private string _outputFilePath = String.Empty;
    
      public MultipleOutputService(string outputFilePath) {
       _outputFilePath = outputFilePath;
      }
    
      private string _message = string.Empty;
    
      public void PrintMessage(string message) {
       _message = message;
       WriteMessageToConsole();
       WriteMessageToFile();
       ShowMessagePopup();
      }
    
      private void WriteMessageToConsole() {
       Console.WriteLine(_message);
      }
    
      private void WriteMessageToFile() {
       File.AppendAllText(_outputFilePath, _message);
      }
    
      // because they're not enough popups in our lives :)
      private void ShowMessagePopup() {
       MessageBox.Show(_message, "The 8-Ball says");
      }
    //snip
    What did we just do?

    Well aside from writing a crazy output class, we've radically changed the output behavior of our application without breaking it! How? Simple. All Magic8BallSimulator knows is that it gets passed (or injected) an instance of a class which implements IOutputService, and our new (slightly odd) MultipleOutputService class does that.

    Here's our new SimulationRunner class, it injects dependent classes into Magic8BallSimulator (remember, Magic8BallSimulator still sees these classes as Interfaces).
    //snip
      static void Main(string[] args) {
       // output file for new output-service
       string outputFilePath = Path.Combine(Path.GetTempPath(), "magic8BallOutput.txt");
    
       Magic8BallSimulator simulator = new Magic8BallSimulator(
        new MessageService(),
        new ConsoleInputService(),
        new MultipleOutputService(outputFilePath) // new odd output class
       );
       simulator.Run();
      }
    //snip
    Source code for this post (that really is an odd output class).

    In the next post

    We'll have a look at a Dependency Injection framework for .NET (there are quite a few to chose from) and how it can make our lives easier. We'll also discuss the differences between running our application and starting it up to run. We'll also check out a better (and more interesting) way of wiring in our dependencies to Magic8BallSimulator. >> Next Post
    3

    View comments

  8. In my last post (read it, its short, honestly), I created an awful Magic8BallSimulator class which violated the Single Responsibility Principle by concerning itself with:
    • Message retrieval
    • Reading user input
    • Printing message and program output
    • Handling user-interactions via a lame read-eval-print (aka REPL) loop
    In this post, I'm going to:
    1. Create a class per responsibility
    2. Make the Magic8BallSimulator class depend on those classes
    3. Inject those dependent classes into Magic8BallSimulator (you'll laugh when you see how simple this turns out to be).
    4. and finally, make you sad by exposing a new problem with the code
    The new classes broken out are:

    MessageService - gets messages
    
     public class MessageService {
    
      public MessageService() {
       SetupMessages();
      }
    
      private List messages = new List();
    
      private void SetupMessages() {
       messages = new List() { 
        "Signs point to yes.", 
        "Yes."
        //snip
       };
      }
    
      public string GetMessage() {
       Random random = new Random();
       int index = random.Next(0, messages.Count - 1);
    
       return messages[index];
      }
     }
    //snip
    ConsoleInputService - reads user input from the console.
    
     public class ConsoleInputService {
      private string input = "input-initializer";
    
      public string GetInput() {
       input = Console.ReadLine();
       return input;
      }
    
      public bool ExitWasRequested() {
       return String.IsNullOrEmpty(input);
      }
    }
    //snip
    ConsoleOutputService - prints output to the console.
    
     public class ConsoleOutputService {
      public void PrintMessage(string message) {
       Console.WriteLine(message);
       Console.WriteLine();
      }
    
      public void PrintWelcome() {
       Console.WriteLine("Welcome to the Magic 8 Ball simulator");
      }
    
      public void PrintInputPrompt() {
       Console.Write("Ask a Question, or press [Enter] to exit >> ");
      }
    
      public void PrintExit() {
       Console.WriteLine("Goodbye");
      }
     }
    //snip
    Magic8BallSimulator - Simulates a Magic 8 Ball via a lame read-eval-print (aka REPL) loop.

    Oh there's a bit of Dependency Injection - MessageService, ConsoleInputService, and ConsoleOutputService are dependencies of Magic8BallSimulator, which is to say that Magic8BallSimulator cannot do its job of simulating a Magic 8 Ball without them. These dependencies are given to this class (or injected) as simple constructor parameters.
    
     public class Magic8BallSimulator {
    
      // these 3 classes are "dependencies" of this class, in that this class cannot
      // do its job without their services.
      private MessageService _messageService;
      private ConsoleInputService _inputService;
      private ConsoleOutputService _outputService;
    
      // here our dependencies are "injected" into this class, that's depedency injection, 
      // really that's it!
      public Magic8BallSimulator(MessageService messageService, ConsoleInputService inputService, 
       ConsoleOutputService outputService) {
       _messageService = messageService;
       _inputService = inputService;
       _outputService = outputService;
      }
    
      public void Run() {
       _outputService.PrintWelcome();
       string message = string.Empty;
    
       _outputService.PrintInputPrompt();
       _inputService.GetInput();
    
       while (!_inputService.ExitWasRequested()) {
        message = _messageService.GetMessage();
        _outputService.PrintMessage(message);
        _outputService.PrintInputPrompt();
        _inputService.GetInput();
       }
    
       _outputService.PrintExit();
      }
     }
    //snip
    SimulationRunner - Runs the simulator class, and injects new instances of the dependent classes into Magic8BallSimulator.
    
     public class SimulationRunner {
      static void Main(string[] args) {
       // watch me now, I'm injecting dependent classes
       Magic8BallSimulator simulator = new Magic8BallSimulator(
        new MessageService(),
        new ConsoleInputService(),
        new ConsoleOutputService()
       );
       simulator.Run();
      }
     }
    //snip
    Hmm, there's still a problem with this code

    Let's have one more look at the Magic8BallSimulator constructor.
      // snip
      public Magic8BallSimulator(MessageService messageService, ConsoleInputService ConsoleInputService, 
       ConsoleOutputService ConsoleOutputService) {
       _messageService = messageService;
       _ConsoleInputService = ConsoleInputService;
       _ConsoleOutputService = ConsoleOutputService;
      }
      // snip
    Notice how we're injecting instances of MessageService, ConsoleInputService, and ConsoleOutputService? What this does is, for example, couple Magic8BallSimulator to ConsoleOutputService which is a specific class printing output in a specific way (to the console). This coupling exposes us to 2 threats:
    1. If we want to change, say, ConsoleOutputService we risk breaking Magic8BallSimulator too, since it depends directly on ConsoleOutputService (and changing the output on the console really shouldn't break our entire application).

    2. If we get a requirements change to alter how we output messages, say, to send them as Instant Messages or via Email, we'll have to rip out ConsoleOutputService and change Magic8BallSimulator as well. This makes our application less maintainable because changes to one section break and cascade to other parts of our application making the whole thing a pain in the ass to work on.
    You might be tempted to try something like the code below, don't do it.
      // snip
      public Magic8BallSimulatorEvenWorse() {
       _messageService = new MessageService();
       _inputService = new ConsoleInputService();
       _outputService = new ConsoleOutputService();
      }
      // snip
    This is actually worse because it adds another responsibility to Magic8BallSimulator namely that of creating its own dependencies. This actually couples us even tighter to these dependent classes since now we're not only using their specific service-implementations, but instantiating them as well.

    Luckily there's a simple way out.

    We need to alter Magic8BallSimulator to depend upon abstractions instead of concrete implementations, making Magic8BallSimulator loosely coupled to the classes it depends on.

    (Awfully coupled) source code for this post, witness the bad design first hand!

    We'll explore this way out in the next post
    1

    View comments

  9. Consider this simple Magic 8-Ball Simulator class, here's the UI:



    and here is the code, reading it should take perhaps a minute.  Heck just read the Run() method.
    
     public class Magic8BallSimulator {
    
      public Magic8BallSimulator() {
       SetupMessages();
      }
    
      public void Run() {
       PrintWelcome();
    
       PrintInputPrompt();
       GetInput();
    
       while (!ExitWasRequested()) {
        GetMessage();
        PrintMessage();
        PrintInputPrompt();
        GetInput();
       }
    
       PrintExit();
      }
    
      private List messages = new List();
    
      private void SetupMessages() {
       messages = new List() { 
        "Signs point to yes.", 
        "Yes."
        //snip
       };
      }
    
      private string message = String.Empty;
    
      private void GetMessage() {
       Random random = new Random();
       int index = random.Next(0, messages.Count - 1);
    
       message = messages[index];
      }
    
      private void PrintMessage() {
       Console.WriteLine(message);
       Console.WriteLine();
      }
    
      private void PrintInputPrompt() {
       Console.Write("Ask a Question, or press [Enter] to exit >> ");
      }
    
      private string input = "place-holder input";
    
      private void GetInput() {
       input = Console.ReadLine();
      }
    
      private void PrintWelcome() {
       Console.WriteLine("Welcome to the Magic 8 Ball simulator");
      }
    
      private void PrintExit() {
       Console.WriteLine("Goodbye");
      }
    
      private bool ExitWasRequested() {
       return String.IsNullOrEmpty(input);
      }
     }
    
    
    Why does this class suck?

    Simple, it is doing way too much work.  As our requirements change and we work on this class, we'll start to introduce bugs in unexpected places.

    [Requirements Change]: We'd like to store the 8-ball messages in a flat-file database.

    Can you honestly do that without the risk of breaking unrelated code like message output?  Imagine the following scenario:

    You: "Yeah, so I was making changes to how the messages are stored and fetched and I broke the way they print to the screen."
    Your teammates: "Hmm, OK". sheesh this guy cannot work on one feature without breaking something completely unrelated

    Hey those two responsibilities are not related! So put them in different classes. In fact the code above has lots of responsibilities:
    • Message retrieval
    • Reading user input
    • Printing message and program output
    • Handling user-interactions via a lame read-eval-print (aka REPL) loop
    Separate responsibilities, separate classes, separate reasons for changing code. This is the Single-Responsibility Principle, a grand and simple assertion that: There should never be more than one reason for a class to change.  In my experience, most programmers dismiss this principle as obvious, and yet cannot seem to follow it when programming.  In fact this kind of code is present in project's which I've otherwise been damn proud to work on.

    Source code for this post, please only download it to shun it, and never speak of it again.

    Let's fix this code

    In the next post we'll see what breaking this class up entails.
    0

    Add a comment

  10. ItemRenderers ought to be considered private children of their parent control and get their data from their parent only.  Of course sometimes itemRenderers need data beyond what's supplied to them via IDataRenderer.  Imagine that we've a List-based control and want our itemRenderer children to know when some bit of data has changed perhaps isTheWorldEnding:Boolean.  The itemRenderers can then prepare from the upcoming conflagration by changing their states accordingly.  I've seen lots of bad solutions to this problem, two common ones are:
    • Injecting a Presentation-Model into the itemRenderers (bad)
    • referencing an awful Singleton with the desired data (real bad)
    Here's a better way. Sub-class the List control (make a MyList control) and add a publicly accessible property of isTheWorldEnding.  In MyList when isTheWorldEnding is set to a new value, call invalidateList() to refresh the renderers. Meanwhile, implement IDropInListItemRenderer in the renderers and get isTheWorldEnding by casting _listData.owner as MyList.  Here's the code to be put in MyList:


    and the code to be placed in our renderer:
    Edit: Joel pointed out that it would be nice to have a convenient method to cast the list, here it is:
    4

    View comments

Blog Archive
About Me
About Me
Loading
Dynamic Views theme. Powered by Blogger.