Injection without a container

Aug 27, 2008 at 1:21 PM
How could I inject registered and resolved objects from a view that has no container? The structure of my scenario is the following:

Module
    ParentView
        ChildView [XAML]

The module inject the UnityContainer in the constructor. From this container, I can retrieve my IRegionManager, IEventAggregator, etc. The ParentView would also then be resolved to do the same, if necessary, and let say for this use case it is done:

container.Resolve<ParentView>();

public class ParentView(IRegionManager _regionManager, IEventAggregator _eventAggregator)
{
    ...
}

My ParentView definition looks like the following:

<ContentControl
    x:Name="ParentView"
    ...
    xmlns:controls=www.mycontrols.com
    >
    <controls:ChildView SomeProperty="true"/>
</ContentControl>

My ChildView is statically defined, which means the default constructor has been called already. This also implies that I should not have to resolve this ChildView in code because it already has been constructed. This leads me to my original question:

How could I inject registered and resolved objects from a view that has no container?

I could include a DP in my ChildView of type EventAggregator and bind it to the ParentView newly exposed, readonly property of, you guessed it, EventAggregator. but I do not want to.

Suggestions please.
Aug 27, 2008 at 2:41 PM
I just realized that there is a Dependency attribute, so I will be working with this to resolve my issues. Actually, this might be exactly what I was looking for. Thanks in advance if you thought about replying for this issue. Will keep this thread updated.
Aug 27, 2008 at 5:58 PM

Hi

 

Since the ChildView class is not resolved by the container, the Dependency attribute is ignored. If you want properties and other injection performed to an instance when you do not control its construction, you can use the BuildUp method of the Unity container:

 

public ParentView(ParentViewPresenter presenter, IUnityContainer container)

{

    InitializeComponent();

 

    _presenter = presenter;

    _presenter.View = this;

 

    container.BuildUp(myChildView.GetType(), myChildView);

}

 

Please, let me know if it helps.

 

Mariano Converti

http://blogs.southworks.net/mconverti

Aug 27, 2008 at 10:55 PM
Edited Aug 27, 2008 at 11:21 PM
mconverti,

Thanks for the heads up. I actually answered a separate posting regarding the DependencyAttribute before seeing your posting.

http://www.codeplex.com/unity/Thread/View.aspx?ThreadId=27343


I also concluded that rather than using the BuildUp method of the container, I could just register my BusinessObject with container.RegisterType(BusinessObject, BusnessObject). With this implemenation, property injection worked fine.

The BuildUp implementation worked fine, but what I did not like about the BuildUp solution is that it goes through two (2) different constructors, the default for Xaml and the injected one for resolvement. I felt uncomfortable with this.

My main obsatcle right now is trying to organize initialization of BusinessObjects and try not to get Injection-Happy. Injection is fine but can get messy. So far I get the impression that global business objects should only be registered and injected through Dependency attributed properties, menaing littel initialization logic in constructor, while modular business objects, business objects outside of the scope of resolvement, can be resolved. When I say "outside of the scope of resolvement," I am mainly speaking about non-top level, module accessible objects that rely business objects.

I am still putting more necessary thought into all of this. Will keep you posted. Thanks again.

Andres Olivares
Sep 2, 2008 at 1:09 AM

mconverti,

I understand now a little more of how to organize new views with injection. I now layout my view statically and use styles to bind properties for regionalized views within a module. I create a region on a container ContentControl, for example,

in my parent view, I then create a style the type that will be stored in the target placeholder ContentControl.

<!--From:-->
<UserControl
    x:Name="root"
    x:Class="UseCaseModule.ParentView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:self="clr-namespace:UseCaseModule"
    >
    <self:ChildView x:Name="childControl" ChildContext="{Binding DataContext, ElementName=parent}"/>
<UserControl>

<!--To:-->
<UserControl
    x:Name="root"
    x:Class="UseCaseModule.ParentView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cal="http://www.codeplex.com/CompositeWPF"
    xmlns:self="clr-namespace:UseCaseModule"
    >
 <UserControl.Resources>
        <ResourceDictionary>
            <Style x:Target="{x:Type self:ChildView}">
                <Setter Property="ChildContext" Value="{Binding DataContext, ElementName=parent}"/>
            </Style>

        </ResourceDictionary>
    </UserControl.Resources>
        <ContentControl x:Name="childArea" cal:RegionManager.RegionName="{x:Static self:ParentView.ChildArea}"/>
</UserControl>

My module can then resolve and regionalize views in the proper placeholders.

// UseCaseModule
public void Initialize()
{
 IRegionManager regionManager = container.Resolve<IRegionManager>();

 IRegion parentArea = regionManager.Regions[ShellConstants.MainArea];
 if (parentArea != null)
 {
  ParentView parent = container.Resolve<ParentView>();
  parentArea.Add(parent);
  parentArea.Activate(parent);
 }

 IRegion childArea = regionManager.Regions[ParentView.ChildArea];
 if (childArea != null)
 {
  ChildView child = container.Resolve<ChildView>();
  childArea.Add(child);
  childArea.Activate(child);
 }
}

If I want to access my child control from my ParentView, I would just extract and cast the Content from the placeholder.

// ParentView
void buttonHasContext_Click(object sender, RoutedEventArgs e)
{
  ChildView childView = childArea.Content as ChildView;
  MessageBox.Show(string.Format("The child has {0}.",
  childView.ChildContext == null ? "no context" : "context"));
}

If I am mistating anything, please let me know.  Thanks again.

Andres Olivares

Sep 4, 2008 at 4:55 PM
Hi Andrés,
I'm not sure I understand correctly what you mean with the following:

The BuildUp implementation worked fine, but what I did not like about the BuildUp solution is that it goes through two (2) different constructors, the default for Xaml and the injected one for resolvement. I felt uncomfortable with this.

The BuildUp method will not run constructor injection or new up a new instance of the class; it will just perform the other strategies that can be executed after object creation, such as property or method injection.
I know you already followed a different approach for this case, but this may easy some of your concerns about using this approach in the future.

I hope this helps,
Julian Dominguez
http://blogs.southworks.net/jdominguez
Sep 4, 2008 at 4:59 PM
Julian,

After thinking about it some more, I figured that going through the construction sequence of the target object would be unless, and hope that this is not what was being done. I figured Prism would have used a strategy as you described. Your comment does make me feel more comfortable using it where ever necessay, but for now it is a last resort.

Thank you for the clarification,

Andres Olivares