【问题标题】:prism null exception on Container.Resolve<IEventAggregator>()Container.Resolve<IEventAggregator>() 上的棱镜空异常
【发布时间】:2018-07-29 06:24:46
【问题描述】:

Resources.Add("eventAggregator", Container.Resolve());引发 Null 异常。

更新 我添加了所有类来解释更多。正如@Axemasta 所说,无需注册 IEventAggregator 并且我删除了注册。现在我不知道如何将 Listview EventAggregator 行为连接到 EventAggregator。

这是整个 App.xaml 代码文件。

public partial class App : PrismApplication
{
    /* 
     * The Xamarin Forms XAML Previewer in Visual Studio uses System.Activator.CreateInstance.
     * This imposes a limitation in which the App class must have a default constructor. 
     * App(IPlatformInitializer initializer = null) cannot be handled by the Activator.
     */
    public App() : this(null) { }


    public App(IPlatformInitializer initializer) : base(initializer) { }

    protected override async void OnInitialized()
    {
        InitializeComponent();

        Resources.Add("eventAggregator", Container.Resolve<IEventAggregator>());// Removed on update

        FlowListView.Init();

        await NavigationService.NavigateAsync("NavigationPage/MainPage");

    }

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {            
        containerRegistry.RegisterForNavigation<NavigationPage>();
        containerRegistry.RegisterForNavigation<MainPage>();           
    }
}

}

行为类:

public class ScrollToMyModelBehavior : BehaviorBase<ListView>
{
    private IEventAggregator _eventAggregator;
    public IEventAggregator EventAggregator
    {
        get => _eventAggregator;
        set
        {
            if (!EqualityComparer<IEventAggregator>.Default.Equals(_eventAggregator, value))
            {
                _eventAggregator = value;
                _eventAggregator.GetEvent<ScrollToMyModelEvent>().Subscribe(OnScrollToEventPublished);
            }
        }
    }

    private void OnScrollToEventPublished(ListItem model)
    {
        AssociatedObject.ScrollTo(model, ScrollToPosition.Start, true);
    }

    protected override void OnDetachingFrom(ListView bindable)
    {
        base.OnDetachingFrom(bindable);
        // The Event Aggregator uses weak references so forgetting to do this
        // shouldn't create a problem, but it is a better practice.
        EventAggregator.GetEvent<ScrollToMyModelEvent>().Unsubscribe(OnScrollToEventPublished);
    }
}

事件类:

public class ScrollToMyModelEvent : PubSubEvent<ListItem>
{
}

页面视图模型:

        public MainPageViewModel(INavigationService navigationService, IEventAggregator eventAggregator) 
        : base (navigationService)
    {
        Title = "صفحه اصلی";
        ListHeight = 100;
        ListWidth = 250;

        _eventAggregator = eventAggregator;

        Items items = new Items();
        ListViewItemSouce = items.GetItems();

        MyModels = items.GetItems();
        SelectedModel = ListViewItemSouce[3];
        _eventAggregator.GetEvent<ScrollToMyModelEvent>().Publish(SelectedModel);
    }

页面浏览量:

<StackLayout HorizontalOptions="Center" VerticalOptions="Center" WidthRequest="{Binding ListWidth}" HeightRequest="{Binding ListHeight}"
                         Grid.Row="1" Grid.Column="1">
                <local:NativeListView x:Name="lst3" ItemsSource="{Binding ListViewItemSouce}" Margin="1" BackgroundColor="Transparent" RowHeight="47" HasUnevenRows="false">
                    <ListView.Behaviors>
                        <local:ScrollToMyModelBehavior EventAggregator="{StaticResource eventAggregator}" /> // Error raised that there is not such a static property
                    </ListView.Behaviors>
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <TextCell Text="{Binding Word}"  TextColor="Black"/>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </local:NativeListView>
            </StackLayout>

【问题讨论】:

  • 要使用事件聚合器,您不需要注册它。您需要有一个事件(继承自 PubSubEvent),然后您可以将它传递到您的视图模型/视图并订阅/发布事件!
  • 谢谢,有什么简单的例子吗?
  • 我将提供一个完整的用例来回答这个问题

标签: xamarin.forms eventaggregator


【解决方案1】:

应用初始化时无需注册IEventAggregator,就像INavigationServiceIPageDialog一样,开箱即可使用!

要使用EventAggregator,您应该执行以下操作:

创建活动

您首先需要创建一个可以传递给EventAggregator 的事件(使用Prism)。你的事件应该继承自PubSubEvent,你可以传递一个对象(可选)。所以你的活动应该是这样的:

using System;
using Prism.Events;

namespace Company.App.Namespace.Events
{
    public class SampleEvent : PubSubEvent
    {
    }
}

查看最近的一个应用程序,我最常在自定义弹出视图(如参数字典)之间传递数据时使用它。

订阅活动

IEventAggregator 触发时,任何订阅了该事件的东西都会执行任何指定的代码。在您想收到活动的班级中,您必须执行以下操作:

  • 通过构造函数传递 IEventAggregator 类(prism 毕竟是 DI)
  • 初始化一个本地 IEventAggregator 以在此类中使用
  • 订阅IEventAggregator 处理程序方法。

代码如下所示:

public class TheClassListeningForAnEvent
{
    private readonly IEventAggregator _eventAggregator;

    public TheClassListeningForAnEvent(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;
        _eventAggregator.GetEvent<SampleEvent>().Subscribe(OnEventRecieved);
    }

    void OnEventRecieved()
    {
        //Do something here
    }
}

触发事件

现在您已经注册了该事件,您可以触发该事件。将IEventAggregator 传递到您要从中触发事件的任何类中并使用Publish Method

public class TheClassPublishingAnEvent
{
    private readonly IEventAggregator _eventAggregator;

    public TheClassListeningForAnEvent(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;

        _eventAggregator.GetEvent<SampleEvent>().Publish();
    }
}

这就是它的长处和短处。你可以将任何东西传递给IEventAggregator,你只需要在你订阅的方法中处理这个。

希望这足以让您使用IEventAggregator

【讨论】:

  • 谢谢伙计。我已经更新了这个问题。问题是如何从 xaml listiew 连接到事件?!
  • 嗨@Behzad,您可以将x:Name 应用到您的列表视图,然后在代码隐藏中订阅一个方法,通过直接引用列表视图滚动到您需要去的地方
  • 这种方式不是 MVVM 方式,不是吗?因为我们使用的是codeBehinde
  • @Behzad 使用代码隐藏不一定会破坏 MVVM。您可以在纯代码隐藏中编写 MVVM 应用程序(所有概念都相同)。如果您的视图模型正在执行与视图相关的事情,那么您正在破坏 MVVM。整个事情是视图知道视图模型,但视图模型不知道视图。有时您需要使用代码隐藏来执行 xamarin 表单无法正常执行的操作!
【解决方案2】:

只需验证您是否在 IOS、Android 和 UWP 项目中添加以下代码。

IOS-Appdelegate

public class AppdelegateInitializer : IPlatformInitializer
    {
        public void RegisterTypes(IUnityContainer container)
        {

        }
    }

Android - MainActivity

public class MainActivityInitializer : IPlatformInitializer
    {
        public void RegisterTypes(IUnityContainer container)
        {

        }
    }

UWP--MainPage.cs

public class UwpInitializer : IPlatformInitializer
    {
        public void RegisterTypes(IUnityContainer container)
        {

        }
    }

【讨论】:

    【解决方案3】:

    随着 Prism 中添加的功能使此类事情变得更加容易,我对此的指导已经发展。

    过去,您将 IEventAggregator 解析并添加为 StaticResource 的原因是无法注入它。我们现在有了 ContainerProvider,它惊人地允许您在 XAML 中添加需要依赖注入的类型。首先,您可以重构 ScrollToBehavior 以使用 DI 模式,方法是添加 IEventAggregator 作为构造函数参数,删除 Bindable 属性(如果您选择)。

    public class ScrollToBehavior : BehaviorBase<ListView>
    {
        private IEventAggregator _eventAggregator { get; }
    
        public ScrollToBehavior(IEventAggregator eventAggregator)
        {
            _eventAggregator = eventAggregator;
        }
    }
    

    正如我提到的,您可以使用 XAML 中的ContainerProvider 来解析并提供需要 DI 的类型,如下所示:

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:ioc="clr-namespace:Prism.Ioc;assembly=Prism.Forms"
                 xmlns:behavior="using:AwesomeProject.Behaviors
                 x:Class="AwesomeProject.Views.ViewA">
      <ListView>
        <ListView.Behaviors>
          <ioc:ContainerProvider x:TypeArguments="behavior:ScrollToBehavior" />
        </ListView.Behaviors>
      </ListView>
    </ContentPage>
    

    【讨论】:

    • 谢谢。确定这条线是正确的吗?
    • Type ioc:ContainerProvider not found in xmlns clr-namespace:Prism.ioc;assembly=Prism.Forms
    • 您使用的是什么版本?使用什么容器并不重要,因为我们在 Prism 7 中抽象了 DI 容器
    • Prism 是 7,我还不能使用 Prism.Ioc
    • 如果您仍在使用 Prism 6,则无法使用此功能,因为它直到 v7 才引入
    猜你喜欢
    • 1970-01-01
    • 2020-01-05
    • 2019-09-22
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 2016-11-15
    • 2020-08-08
    相关资源
    最近更新 更多