Получить контейнер IOC во всплывающем окне
Я использую PRISM 5 в своем приложении WPF. И представление Shell в моем приложении имеет две области, рассматривайте их как A и B. Область A содержит POPUP (функция интерактивности PRISM 5 используется для отображения всплывающего окна).
Приложение работает, когда я создаю экземпляр модели всплывающего окна внутри конструктора представления.
Рабочий код
public PopupView()
{
InitializeComponent();
this.DataContext = new PopupViewModel(); // Working code
}
Но когда я пытаюсь создать экземпляр модели представления, используя инъекцию зависимости. Приложение не работает в InitializeComponent();
родительского представления (вид A).
DI Не работает код
public PopupView(PopupViewModel viewModel)
{
InitializeComponent(); // Failing in AView initialze
// before reaching here
this.DataContext = viewModel;
}
Просмотр регистрации модели в модуле/загрузчике
container.RegisterType<AViewModel>();
Произошла ошибка
Выполнено исключение NULLReference
Stacktrace (Отредактировано для вопроса)
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 (Отредактировано, чтобы избежать информации о конкретном проекте)
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)
{
}
}
Ответы
Ответ 1
Я предполагаю, что вы используете InteractionRequestTrigger
с PopupWindowAction
в своем XAML для привязки PopupView
к соответствующему InteractionRequest
.
Вы не можете передать PopupViewModel
в конструктор PopupView
, потому что представление создается с помощью PopupWindowAction
напрямую, а не с помощью DI-контейнера. Когда PopupWindowAction
создает PopupView
, он будет устанавливать вид DataContext
на объект INotification
, который вы передали в InteractionRequest.Raise(…)
. Этот INotification
имеет свойство Content
, которое может использоваться для передачи любых данных, которые вы хотите использовать PopupView
. Например, вы можете передать PopupViewModel
здесь.
EDIT: Я искал PopupWindowAction
источники, и кажется, что я ошибаюсь. Они используют ServiceLocator
, когда они пытаются создать экземпляр PopupWindowAction.WindowContentType
, поэтому технически передающий конструктор PopupViewModel
to PopupView
не должен приводить к исключению, но он по-прежнему бесполезен, поскольку вид DataContext
заменяется на INotification
объект передан в InteractionRequest
.
Пример:
// 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))));
}
}
Ответ 2
Я думаю, что вы регистрируете AViewModel, но в контейнере IoC отсутствует правильный экземпляр или factory для PopupViewModel. С моей точки зрения, вашему представлению требуется PopupViewModel в качестве зависимости, но контейнер не может разрешить его, потому что этот тип не зарегистрирован.
Кроме того, пожалуйста, нажмите здесь ваш файл XAML, потому что исключение было выбрано из метода InitializeComponent(), это происходит из-за несогласованной разметки. Таким образом, нам нужно увидеть разметку, чтобы предоставить вам больше отзывов.