开发者

IoC container object scoping

I am interested in implementing an IoC container in my project but I haven't seen an example out there that does what I need.

Here is the situation, my application is built in WPF and uses the MVVM pattern to create a player for an infrared video format. In this format, each video is actually made up of multiple "subframes" (think of it as capturing at multiple shutter speeds simultaneously in order to increase the dynamic range of the data) that are each displayed in a TabControl. I would like to use an IoC container to help me create the ViewModels for each of the tabs, but I have two concerns.

  1. I need a way to pass in the object that represents the subframe I'm creating a ViewModel for so at least one of the ViewModel's dependencies can't be created by the IoC container because it already exists.

  2. I have user controls inside the view for a subframe that have their own ViewModels so those ViewModels need to be created by the IoC container as well. The problem with this is that while the controls (and their ViewModels) have separate concerns, they are not completely indpendent so they use some coordination objects. Unfortunately in all the examples I've seen you can either have your IoC container create a new instance of a dependency or have a singleton, but what I need is a single instance during the controlled scope of time when I'm creating the subframe ViewModel.

That's a lot of text so here's some code that shows what I'm doing and what I'd like to do.

What I have now

In the open a movie code:

foreach (var subframe in movieFile)
{
    // Subframes is the ObservableCollection that the TabControl is bound to
    Subframes.Add(new SubframeViewModel(subframe));
}

In the SubframeViewModel:

public SubframeViewModel(ISubframe subframe)
{
    _subframe = subframe;

    // FrameController tracks the current frame number and fires an event 
    // when it changes
    var frameController = new FrameController(subframe); 

    // ImageViewModel represents the actual movie image. Uses FrameController
    // to know when to raise PropertyChanged for the property that represents
    // the image
    ImageViewModel = new Imag开发者_StackOverfloweViewModel(subframe, frameController);

    // FrameControlViewModel represents the playback controls.  Uses
    // FrameController to implement actions
    // Play, Pause, Jump to frame, Jump to time...
    FrameControlViewModel = new FrameControlViewModel(subframe, frameController);
}

What I would like to have without changing the existing sematics

In the open a movie code:

foreach (var subframe in movieFile)
{
    Subframes.Add(container.Resolve<SubframeViewModel>());
}

In the SubframeViewModel:

public SubframeViewModel(ISubframe subframe, ImageViewModel imageModel, 
                            FrameControlViewModel frameModel)
{
    _subframe = subframe;

    ImageViewModel = imageModel;

    FrameControlViewModel = frameModel;
}

In reality, there are more coordination and ViewModel objects involved but the patterns are the same. That said, I think you can see why I'm interested in an IoC container here.

I think my scenario should be rather common but I'm not sure and I don't want to waste my time trying to fit a square peg into a round hole so here are my questions. Can any / all IoC containers do this? If not, can you point me towards a refactoring that would improve my code and make IoC work?


Autofac definitely does what you require - parameters provided explicitly can be combined with those autowired by the container:

vm = container.Resolve<SubFrameViewModel>(new NamedParameter("subframe", subframe));

(Matching by type rather than name is also possible.)

You can even have the container inject a Func or custom delegate into the calling component, so that the container dependency (i.e. the call to Resolve) is unnecessary:

Func<ISubFrame, SubFrameViewModel> _vmFactory; // Injected
vm = _vmFactory(subframe);

See http://code.google.com/p/autofac/wiki/DelegateFactories for info on the latter.

Nick


It looks like you want to handle the extra constructor parameters in your IoC scenario, and I see two options:

1 - Creating a simple constructor which takes in a subframe, and expose the ImageViewModel and FrameControlViewModel as public settable properties like so:

// assumes frameControlVM and imageVM have been constructed and are valid
foreach (var subframe in movieFile)
{
    var subframeVM = container.Resolve<SubframeViewModel>(subframe);
    subframeVM.ImageVM = imageVM;
    subframeVM.FrameControlVM = frameControlVM ;
    Subframes.Add(subframeVM);
}

2 - Pass the arguments you need into the IoC container, which simply passes the parameters into the SubframeVM constructor:

// assumes frameControlVM and imageVM have been constructed and are valid
foreach (var subframe in movieFile)
{
    var subframeVM = container.Resolve<SubframeViewModel>(subframe, imageVM, frameControlVM);
    Subframes.Add(subframeVM);
}

Ultimately which one you choose depends on how tightly coupled you want your SubframeViewModel IoC resolver to be with the rest of your VMs. If your imageVM and frameControlVMs need IoCs of their own, you can simply chain them together:

// assumes frameControlVM and imageVM have been constructed and are valid
foreach (var subframe in movieFile)
{
    var frameControlVM = container.Resolve<FrameControlViewModel >(subframe);
    var imageVM = container.Resolve<ImageViewModel>(subframe, frameControlVM);
    var subframeVM = container.Resolve<SubframeViewModel>(subframe, imageVM, frameControlVM);
    Subframes.Add(subframeVM);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜