0

Users are pointing me to Unity Dependency Injection from usercontrol viewmodel to customUsercontrol Viewmodel

The top answer says Don't use DI/IoC container to inject controls

If what im doing should NOT be done, at least advise on what i SHOULD do.

I need my 2 ViewModel to know when my grid objects are checked/unchecked, and which object it was.

How can this be done without IEventAggregator?


I have a usercontrol that i am using as a GridViewRow template. This usercontrol is not loaded until users search for something and my grid displays objects.

On the template, there are checkboxes that when checked, I need to communicate to my viewmodel.

Currently when I build, my application works as expected.

When i modify my constructor from public MainGridTemplate() to public MainGridTemplate(IEventAggregator ea) and run the app without any other code changes (not even saving to a local variable), I get the error

System.NullReferenceException: 'Object reference not set to an instance of an object.'

My callstack only shows 1 entry, [External Code] and my breakpoint on the constructor is never hit. This leads me to believe the IEventAggregator that gets inject is null, or something is null along the path of injecting.

In my view model, im injecting IEventAggregator as well as a IRepository service and those work without issues, so why would i get this error when using DI in a usercontrol

enter image description here

    public MainGridTemplate()
    {
        InitializeComponent();

        PromoFromDateTextBox.DropDownOpened += HandleClicks;
        PromoToDateTextBox.DropDownOpened += HandleClicks;

        PromoNumberTextBox.GotFocus += HandleClicks;
        PromoPriceTextBox.GotFocus += HandleClicks;

        AdsCheck.Click += HandleClicks;
        DistroCheck.Click += HandleClicks;
        ShowCheck.Click += HandleClicks;
        KeepCheck.Click += HandleClicks;
    }

My template is applied with the following in xaml

        <ControlTemplate x:Key="PMSMainRowTemplate"
                         TargetType="telerik:GridViewRow">
            <template:MainGridTemplate DataContext="{Binding}" />
        </ControlTemplate>
        <Style TargetType="telerik:GridViewRow"
               BasedOn="{StaticResource GridViewRowStyle}">
            <Setter Property="Template"
                    Value="{StaticResource PMSMainRowTemplate}" />
        </Style>

My Current Workaround:

In my bootstrapper class, ive added a property StaticContainer

public static IUnityContainer StaticContainer {get; set; }

and in my usercontrol

var container = Bootstrapper.StaticContainer;
_ea = container.Resolve<IEventAggregator>();

yay statics (not really...)

highboi
  • 673
  • 7
  • 28
  • 1
    DI doesn't. Whichever DI container you use, if it can't find a dependency it will *throw* instead of passing a null parameter. Post your code and the full exception including the call stack. You can get it easily using `Exception.ToString()` – Panagiotis Kanavos Jul 10 '18 at 15:44
  • The call stack included in the exception string will show *where* the exception occured. – Panagiotis Kanavos Jul 10 '18 at 15:46
  • see my edit, like i said, my call stack only shows 1 entry. How can i view the exception callstack? – highboi Jul 10 '18 at 15:50
  • `Exception.ToString()` – Panagiotis Kanavos Jul 10 '18 at 15:50
  • let me rephrase, WHERE do i view the exception callstack. I dont see an exception object to inspect the way i would for `DbEntityValidationException` here: https://stackoverflow.com/a/24542325/5434784 – highboi Jul 10 '18 at 15:55
  • @PanagiotisKanavos `Whichever DI container you use, if it can't find a dependency it will throw instead of passing a null parameter.` If you cant answer the previous question, can you atleast offer insight as to why IEventAggregator can be found in my view model, but not my user control which gets loaded AFTER my view model? – highboi Jul 10 '18 at 16:14
  • 1
    See this answer => https://stackoverflow.com/questions/37206055/unity-dependency-injection-from-usercontrol-viewmodel-to-customusercontrol-viewm – Paul Swetz Jul 10 '18 at 17:31
  • Possible duplicate of [Unity Dependency Injection from usercontrol viewmodel to customUsercontrol Viewmodel](https://stackoverflow.com/questions/37206055/unity-dependency-injection-from-usercontrol-viewmodel-to-customusercontrol-viewm) – Paul Swetz Jul 10 '18 at 17:31
  • @lizzy91 I can't guess what your code looks like, how you configured your DI container, what the exception looks like. *You* have to provide that so people can reproduce the problem at least. Right now we have nothing. Just an image that won't compile without any code. Your workaround btw is equivalent to not using DI. Don't you think that people would have noticed if eg Unity was broken? – Panagiotis Kanavos Jul 11 '18 at 07:31
  • As for `but not my user control which gets loaded AFTER my view model?` Because *User Controls* are *controls* - they have parameterless constructors otherwise it would be impossible to place them in forms or use them at design time. *Your* code needs to provide any required properties, services possibly using DependencyProperty props. The exception string would show that in the call stack - it would show that the error occured in `InitializeComponent()` or a Load event, or some constructor call. You still haven't provided that though, or any usable information about the exception. – Panagiotis Kanavos Jul 11 '18 at 07:36
  • BTW you can catch and log even unhandled exceptions that would otherwise crash your application by handling the ` Application.DispatcherUnhandledException` event. Even if the application crashes, .NET will write an Error event in the Event log – Panagiotis Kanavos Jul 11 '18 at 07:38
  • And finally, WPF uses composition. Business logic is never placed in the View, it's placed in viewmodels, models, services tc. User Controls usually contain only XAML tags - they should contain no business or application logic and even UI events can and *should* be handled using data binding, transitions etc. You don't need clicks, you want the SelectedItem or to invoke a Command. Hence they don't need IEventAggregator. Handling business logic, raising business/application events is the job of the ViewModel. That's what allows you to develop views and viewmodels separately – Panagiotis Kanavos Jul 11 '18 at 07:56
  • Composition means you can bind a complex VM property to a View implemented as any other control. You can specify the view used to display a property at runtime by using a ContentControl, specifying templates for different VMs and just *chaning the property value* to change the view as shown in [Binding ContentControl Content for dynamic content](https://stackoverflow.com/questions/15936428/binding-contentcontrol-content-for-dynamic-content). The view could use another view or `ContentControl` to bind to another nested property. DI is meant to be used by ViewModels. Views shouldn't *need* DI – Panagiotis Kanavos Jul 11 '18 at 08:01
  • Where do you expect your UserControl to be injected with the dependency? WPF won't automagically do this for you. – mm8 Jul 11 '18 at 12:20
  • @mm8 im injecting `IEventAggregator ` into a view. not a `control`. – highboi Jul 11 '18 at 13:52
  • @lizzy91: A control is a view...and how does that answer my question? – mm8 Jul 11 '18 at 13:56
  • @PanagiotisKanavos i honestly dont know what code i should share. do you need my control, my bootstrapper class, the entire project? i was able to reproduce the crash simply by adding a parameter in my control. and fix it by removing it. Im not saying unity is broken, and my solution is equivalent to not using DI because that's what i read in the question that was linked as possible duplicate. I would much rather use DI the right way, but apparently i cant get it to work in this 1 user control, but it works fine in my other controls. Ill upload a project if you're willing to look at that – highboi Jul 11 '18 at 13:59
  • @mm8 `IEventAggregator -> View (Code behind)` is what im injecting, Not `Control/View -> ?!?` i dont need to inject a view. does that help? – highboi Jul 11 '18 at 14:14
  • @lizzy91: Where and how are you creating an instance of your control with the constructor that accepts a dependency? – mm8 Jul 11 '18 at 14:18
  • im not manually creating any instances, Im using the control as a template for a gridview. Its done using a `ControlTemplate` and a `Style` See edit for the actual xaml – highboi Jul 11 '18 at 14:20

0 Answers0