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)
{
}
}
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))));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With