исключение prism null в Container.Resolve‹IEventAggregator›()

Строка 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>

person Behzad    schedule 29.07.2018    source источник
comment
Чтобы использовать агрегатор событий, его не нужно регистрировать. Вам нужно будет иметь событие (унаследованное от PubSubEvent), затем вы можете просто передать его в свои модели просмотра/представления и подписаться/опубликовать события!   -  person Axemasta    schedule 29.07.2018
comment
Спасибо, а есть простой пример?   -  person Behzad    schedule 29.07.2018
comment
Я предоставлю полный вариант использования в качестве ответа на этот вопрос   -  person Axemasta    schedule 29.07.2018


Ответы (3)


Вам не нужно регистрировать IEventAggregator при инициализации приложения, как INavigationService или IPageDialog, вы можете использовать его прямо из коробки!

Чтобы использовать EventAggregator, вы должны сделать следующее:

Создать мероприятие

Сначала вам нужно создать событие (используя Prism), которое вы можете передать в файл EventAggregator. Ваше событие должно наследоваться от 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!

person Axemasta    schedule 29.07.2018
comment
Спасибо чувак. Я обновил вопрос. Проблема в том, как подключиться к событию из xaml listiew?! - person Behzad; 30.07.2018
comment
Привет @Behzad, вы можете применить x:Name к своему списку, а затем подписаться на метод в отделенном коде, чтобы прокрутить туда, куда вам нужно перейти, напрямую ссылаясь на список - person Axemasta; 31.07.2018
comment
этот способ не является способом MVVM, не так ли? потому что мы используем codeBehinde - person Behzad; 22.08.2018
comment
@Behzad Использование отделенного кода не обязательно ломает MVVM. Вы можете писать приложения MVVM в чистом отделенном коде (все концепции одинаковы). Если ваша модель просмотра делает вещи, связанные с просмотром, то вы нарушаете MVVM. Все дело в том, что представление знает о модели представления, но модель представления не знает о представлении. Иногда вам нужно использовать программный код, чтобы сделать то, что формы xamarin не позволяют вам делать в обычном режиме! - person Axemasta; 22.08.2018

Просто проверьте, добавляете ли вы приведенный ниже код в проекты IOS, Android и UWP.

IOS-Appdelegate

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

        }
    }

Android — основная активность

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

        }
    }

UWP-- MainPage.cs

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

        }
    }
person Pratius Dubey    schedule 29.07.2018

Мое руководство по этому вопросу изменилось по мере того, как в Prism были добавлены функции, которые еще больше упрощают подобные вещи.

В прошлом причина, по которой вы разрешали и добавляли IEventAggregator в качестве StaticResource, заключалась в том, что не было возможности внедрить это. Теперь у нас есть ContainerProvider, который удивительным образом позволяет добавлять в XAML типы, требующие внедрения зависимостей. Для начала вы можете реорганизовать свой ScrollToBehavior для использования шаблона DI, добавив IEventAggregator в качестве параметра конструктора, удалив свойство Bindable (если вы выберете).

public class ScrollToBehavior : BehaviorBase<ListView>
{
    private IEventAggregator _eventAggregator { get; }

    public ScrollToBehavior(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;
    }
}

Как я уже упоминал, вы можете использовать ContainerProvider в XAML для разрешения и предоставления типа, требующего внедрения зависимостей, следующим образом:

<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>
person Dan Siegel    schedule 01.08.2018
comment
Спасибо. Вы уверены, что эта строка верна? ‹ioc:ContainerProvider x:TypeArguments=behavior:ScrollToBehavior /› - person Behzad; 01.08.2018
comment
Введите ioc:ContainerProvider не найден в xmlns clr-namespace:Prism.ioc;assembly=Prism.Forms - person Behzad; 01.08.2018
comment
Какую версию ты используешь? не имеет значения, какой контейнер вы используете, так как мы абстрагировали контейнер DI в Prism 7. - person Dan Siegel; 01.08.2018
comment
Prism 7, и я пока не могу использовать Prism.Ioc - person Behzad; 22.08.2018
comment
Если вы все еще используете Prism 6, вы не можете использовать эту функцию, поскольку она не была представлена ​​до v7. - person Dan Siegel; 22.08.2018
comment
как я уже сказал, я использую Prism 7.1.0.172-pre. Нужен ли Nuget? - person Behzad; 22.08.2018
comment
Извините, я прочитал ваш комментарий вне контекста. Поставщик контейнеров находится в сборке Prism.Forms и использует абстракцию IoC для разрешения вашего типа. На самом деле не имеет значения, какой контейнер вы используете, потому что в конечном итоге он все равно исходит из этого контейнера. Вы можете использовать его в любом проекте, прямо или косвенно ссылающемся на Prism.Forms. Поэтому, если вы используете новый PackageReference, вам просто нужна ссылка на Prism.{Ваш контейнер}.Forms. - person Dan Siegel; 22.08.2018
comment
Введите ioc:ContainerProvider не найден в xmlns clr-namespace:Prism.Ioc;assembly=Prism.Forms - person Behzad; 22.08.2018
comment
@Behzad, у тебя нет приложения репо ... Я не могу сказать тебе, что ты делаешь неправильно. Что я могу сделать, так это указать вам на XAML View в моках, которые мы используем для модульного тестирования. Я предлагаю вам посмотреть на это для руководства. - person Dan Siegel; 22.08.2018