在弹出窗口中获取IOC容器

14

我在我的WPF应用程序中使用PRISM 5。我的应用程序的Shell视图有两个区域,称之为A和B。区域A包含一个弹出窗口(使用PRISM 5互动特性显示弹出窗口)。

当我在视图构造函数中创建弹出窗口视图模型的实例时,应用程序正常工作。

正常工作代码

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

但是当我尝试使用依赖注入创建视图模型实例时,应用程序会在父视图(View A)的InitializeComponent();处崩溃。

依赖注入未起作用的代码

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

    this.DataContext = viewModel;
}

在模块/引导程序中注册视图模型

container.RegisterType<AViewModel>();

错误发生了

发生了空引用异常

堆栈跟踪(已编辑,仅供本问题使用)

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
应用程序失败是什么意思?您是否收到异常? - quadroid
你是否已经添加了默认构造函数:**public AViewModel()**?你可以通过 DI 先创建 VM,然后使用 DataTemplate 显示它。(使用 MEF 可以这样做:ServiceLocator.Current.GetInstance<AViewModel>()) - gReX
1
我是否漏掉了什么,或者你想注入PopupViewModel但你只注册了“AViewModel”?你必须注册每个你想使用的viewmodel。 - Andras Sebo
你是否在容器中注册了PopupView?如果你要使用依赖注入并调用PopupView.Show(),你应该从IOC中获取它。 - Rickey
就像Andras指出的那样,如果你想让Unity为你注入PopupViewModel,你需要注册PopupViewModel,你漏掉了container.RegisterType <PopupViewModel>(); - Noman Khan
显示剩余8条评论
2个回答

1
我假设您在XAML中使用了InteractionRequestTriggerPopupWindowAction来将PopupView绑定到相应的InteractionRequest。 无法将PopupViewModel传递给PopupView的构造函数,因为视图是由PopupWindowAction直接创建的,而不是由DI容器创建的。当PopupWindowAction创建PopupView时,它会将视图的DataContext设置为您传递给InteractionRequest.Raise(…)INotification对象。该INotification具有一个Content属性,可用于传递任何您想要传递给PopupView的数据。例如,您可以在此处传递PopupViewModel

编辑:我查看了sources中的PopupWindowAction,发现我的想法是错误的。当他们尝试实例化PopupWindowAction.WindowContentType时,他们使用ServiceLocator,因此从技术上讲,将PopupViewModel传递给PopupView的构造函数不应该导致异常,但它仍然是无用的,因为视图的DataContext被进一步替换为传递给InteractionRequestINotification对象。

示例:

// 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))));
    }
}

0

我认为您正在注册 AViewModel,但是 IoC 容器没有正确的实例或工厂来处理 PopupViewModel。 从我的角度来看,您的 View 需要将 PopupViewModel 作为依赖项,但该容器无法解析它,因为此类型未注册。

另外,请在此处上传您的 XAML 文件,因为异常是从 InitializeComponent() 方法中抛出的,这是由于不一致的标记语言造成的。 因此,我们需要查看标记语言以向您提供更多反馈。


猜测正在使用Unity。在Unity中,类型不需要注册即可解决。只有接口需要注册,如果选择构造函数不明确或需要不同的生命周期管理器。 - Michael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接