English 中文(简体)
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 ImageViewModel(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);
}




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签