14

I am using PRISM 5 in my WPF application. And the Shell view in my application has two regions, consider it as A and B.The region A contains a POPUP (PRISM 5 interactivity feature is used to show popup).

The application is working when i create an instance of the popup view model inside the constructor of the view .

Working code

public PopupView()
{
    InitializeComponent();
    this.DataContext = new PopupViewModel(); // Working code
}

But when i try to create view model instance using the dependency injection.The application fails on the InitializeComponent(); of the parent view (View A).

DI Not working code

public PopupView(PopupViewModel viewModel)
{
    InitializeComponent(); // Failing in AView initialze
                           // before reaching here

    this.DataContext = viewModel;
}

View model registration in module/bootstrapper

container.RegisterType<AViewModel>();

Error occured

NULLReference Exception occured

Stacktrace(Edited for the question)

at System.DefaultBinder.BindToMethod(BindingFlags bindingAttr, MethodBase[] match, Object[]& args, ParameterModifier[] modifiers, CultureInfo cultureInfo, String[] names, Object& state)
   at MS.Internal.Xaml.Runtime.DynamicMethodRuntime.CreateInstanceWithCtor(Type type, Object[] args)
   at MS.Internal.Xaml.Runtime.ClrObjectRuntime.CreateInstance(XamlType xamlType, Object[] args)
   at MS.Internal.Xaml.Runtime.PartialTrustTolerantRuntime.CreateInstance(XamlType xamlType, Object[] args)
   at System.Xaml.XamlObjectWriter.Logic_CreateAndAssignToParentStart(ObjectWriterContext ctx)
   at System.Xaml.XamlObjectWriter.WriteEndObject()
   at System.Windows.Markup.WpfXamlLoader.TransformNodes(XamlReader xamlReader, XamlObjectWriter xamlWriter, Boolean onlyLoadOneNode, Boolean skipJournaledProperties, Boolean shouldPassLineNumberInfo, IXamlLineInfo xamlLineInfo, IXamlLineInfoConsumer xamlLineInfoConsumer, XamlContextStack`1 stack, IStyleConnector styleConnector)
   at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
   at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
   at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
   at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
   at MyNamespace.AView.InitializeComponent() in e:\xxx\xxxxx\xxx\AView.xaml:line 1
   at MyNamespace.AView..ctor(AViewModel viewModel) in e:\xxx\xxxxx\xxx\AView.xaml.cs:line 18

AViewModel(Edited one to avoid project specific information)

 public class ItemSelectionNotification : Confirmation
 { 
      //This class includes properties related to my project
 }

public class AViewModel
 {
        public InteractionRequest<ItemSelectionNotification> ItemSelectionRequest { get; private set; }

        public AViewModel(EventAggregator eventAggregator,IUnityContainer container)
        {
            this.eventAggregator = eventAggregator;
            this.container = container;
            ItemSelectionRequest = new InteractionRequest<ItemSelectionNotification>();
            SettingsCommand = new DelegateCommand(OnClickSetting);    //Command for settings button click      
        }

        //Button click handling
        public void OnClickSetting()
        {                      
                var notification = new ItemSelectionNotification()
                    {
                        Title = "Items"
                    };
                this.ItemSelectionRequest.Raise(notification,OnSaveCallback);
         }  

        private void OnSaveCallback(PropertySelectionNotification returned)
        {
        }   
 }
Prasanth V J
  • 1,126
  • 14
  • 32
  • 1
    "The application fails" what does that mean? Do you get an exception? – quadroid Dec 15 '14 at 13:49
  • Can you please post the code that invokes the popup to be shown? – quadroid Dec 15 '14 at 14:09
  • Unity is not used anywhere in Stacktrace. It can't create AView with no default constructor. You can't make InitializeComponent to resolve components from Unity container. – norekhov Dec 16 '14 at 06:14
  • FYI-Updated question.There was a mistake in the code – Prasanth V J Dec 16 '14 at 07:19
  • @norekhov How can i pass unity container to the popupview?I am using Complex Custom Popup Windows in PRISM 5.But i can't find any sample to pass container to the popup.http://msdn.microsoft.com/en-us/library/ff921081(v=pandp.40).aspx – Prasanth V J Dec 16 '14 at 07:21
  • See my answer for general hints. – norekhov Dec 16 '14 at 07:53
  • Do you has added the Default-Constructor: **public AViewModel()**? You can create the VM first with DI and then show it with DataTemplate. (with MEF i can do ServiceLocator.Current.GetInstance()) – gReX Jul 22 '15 at 14:31
  • 1
    Am I missing something or you want to inject PopupViewModel but you only registered "AViewModel"? You have to register every viewmodel you want to use. – Andras Sebo Aug 05 '15 at 21:20
  • Did you register PopupView in the container? If you're going to use DI and call PopupView.Show(), you should pull it from the IOC. – Rickey Aug 12 '15 at 19:48
  • Just like Andras pointed out, you need to register PopupViewModel also if you want Unity to inject it for you, you are missing container.RegisterType(); – Noman Khan Aug 19 '15 at 22:51
  • @PrasanthVJ Did you solve this problem? I am using the Autofac DI framework and am getting the exact same problem you were. – mrsargent Oct 28 '15 at 13:00
  • It is bad practices to depend on the IoC container, but if it is needed and you are crazy, the container must be registered to itself. – Michael Jul 15 '16 at 14:01
  • The exception indicates that the problem is not resolving AViewModel. The problem is in loading the xaml. Try put a breakpoint in the constructor of PopupView and see that the ViewModel is proper instantiated. – Michael Jul 15 '16 at 14:04

2 Answers2

1

I will assume that you use InteractionRequestTrigger with PopupWindowAction in your XAML to bind PopupView to corresponding InteractionRequest.

You can't pass PopupViewModel to the constructor of the PopupView because the view is created by the PopupWindowAction directly and not by DI-container. When PopupWindowAction creates PopupView, it will set view's DataContext to the INotification object that you passed to the InteractionRequest.Raise(…). That INotification has a Content property which can be used to pass any data you want to the PopupView. For example, you can pass PopupViewModel here.

EDIT: I've looked up PopupWindowAction sources and it appears that I'm wrong. They use ServiceLocator when they try to instantiate PopupWindowAction.WindowContentType, so technically passing PopupViewModel to PopupView's constructor should not result in an exception, but it is still useless since view's DataContext is further replaced by the INotification object passed to the InteractionRequest.

Example:

// PopupViewModel.cs
internal sealed class PopupViewModel
{
    public PopupViewModel(string message)
    {
        Message = message;
    }

    public string Message { get; }
}    

// PopupView.xaml
<UserControl …>
    <Grid DataContext="{Binding Content, Mode=OneTime}">
        <Label Text="{Binding Message, Mode=OneTime}" />
    </Grid>
</UserControl>

// SomeViewModel.cs
internal sealed class SomeViewModel
{
    // Don't use DI-container references to construct objects, inject factories instead.
    // Also to keep things simple you can just create your PopupViewModel directly if it has no external dependencies.
    private readonly Func<string, PopupViewModel> _popupViewModelFactory;

    public SomeViewModel(Func<string, PopupViewModel> popupViewModelFactory)
    {
        _popupViewModelFactory = popupViewModelFactory;
    }

    public ICommand ShowPopupCommand { get; } = new DelegateCommand(DoShowPopup);

    public InteractionRequest<INotification> PopupRequest { get; } = new InteractionRequest<INotification>();

    private void DoShowPopup()
    {
        PopupRequest.Raise(new Notification
        {
            Content = _popupViewModelFactory("This is a Popup Message!")
        }, _ =>
        {
            // Callback code.
        });
    }
}

// SomeView.xaml
<UserControl …>
    <i:Interaction.Triggers>
        <prism:InteractionRequestTrigger SourceObject="{Binding PopupRequest, Mode=OneTime}">
            <prism:PopupWindowAction WindowContentType="views:PopupView" />
        </prism:InteractionRequestTrigger>
    </i:Interaction.Triggers>

    <Button Command="{Binding ShowPopupCommand, Mode=OneTime}" />
<UserControl>

// SomeModule.cs (or maybe Bootstrapper.cs if you setup your container in Bootstrapper)
public sealed class SomeModule : IModule
{
    private readonly IUnityContainer _container;

    public SomeModule(IUnityContainer container)
    {
        _container = container;
    }

    public override void Initialize()
    {
        _container.RegisterType<Func<string, PopupViewModel>>(
            new InjectionFactory(c =>
                new Func<string, PopupViewModel>(message =>
                    c.Resolve<PopupViewModel>(
                        new ParameterOverride("message", message))));
    }
}
Tony
  • 1,422
  • 1
  • 11
  • 12
0

I think you are registering the AViewModel, but IoC container is not having the right instance or factory for PopupViewModel. From my point of view, your View needs PopupViewModel as a dependency but the container cant resolve it because this type is not registered.

In addition please push here your XAML file because the exception was thrown from InitializeComponent() method, it happens because inconsistent markup. Thus, we need to see the markup to provide you with more feedback.

  • Guessing that Unity is being use. In Unity, types does not need to be registered to be resolved. Only interfaces and if choosing the constructor is not unambiguous or if a different lifetime manager is desired. – Michael Jul 15 '16 at 13:59