Event Aggregator Null reference error

Sep 27, 2013 at 12:58 PM
I am running into an issue on one of my views when I try to navigate to a child view. The parent view has a Telerik gridview with a command wired in with a command parameter. That part seems to be working correctly because I get to the method specified in the command along with the correct parameter. When I try to make the call EventAggregator.Publish(...) the EventAggregator is null.

The parent view is working and wired to a NavigationViewModel and the List is wired to a MyListViewModel like in your examples in the book, as is the child view. I know that I may have missed a step but I am not sure where. Any ideas would be great. I will post some sample code later today for my project if needed.
Sep 30, 2013 at 8:53 AM
Where are you referencing the EventAggregator? Is it in code behind? It should be available in your ViewModels if they're wired up correctly.
Oct 3, 2013 at 2:42 PM
Edited Oct 3, 2013 at 4:57 PM
I am making the call to EventAggregator.Publish(...) in the view model and I have the viewmodel wire up like the MainViewModel and the NavigationViewModel with the ExportAsViewModel annotation using the Type. The view is annotated with the ExportAsView, also using the Type, and ExportViewToRegion in the code behind for the view. The code behind is also exporting the ViewModelRoute for the ViewModel / View.

There are two main content areas both defined as ContentControls with the ExportAs Region.RegionNames of NavigationRegion and ContentRegion.
MainViewModel.cs  

[ExportAsViewModel(typeof(MainViewModel))]
public class MainViewModel : BaseViewModel
{
    [Import]
    public Global Globals { get; set; }

    [Impot]
    public IMyApplicationContext Appcontext { get; set; }

    protected override void InitializeVm()
    {
        ...
        base.InitializeVm();
        AppContext.Title = "My Application title";
    }

    protected override void ActivateView (string viewName, IDictionary<string, object> viewParameters)
    {
        base.ActivateView(viewName, viewParameters);
    }
}

MainPage.cs

[ExportAsView(typeof(MainPage), IsShell = true)]
public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
    }

    [Export]
    public ViewModelRoute Binding
    {
        get { return ViewModelRoute.Create<MainViewModel, MainPage>()}; }
    }
}

NavigationViewModel.cs

[ExportAsViewModel(typeof(NavigationViewModel))]
public class NavigationViewModel: BaseViewModel
{
    [Import]
    public Global Globals { get; set; }

    public IActionCommand<string> HomeCMD { get; private set; }
    //... for the menu commands

    public NavigationViewModel()
    {
        HomeCMD = new ActionCommand<string>(ShowView);
        //... New the ActionCommands
    }

    public void ShowView(string parameter)
    {
        //switch to select the view and fire 
        EventAggregator.Publish(Globals.HomeView.AsViewNavigationArgs());
        // .. the rest of the menu options
        // These all seem to work
    }
}

NavigationView.cs

[ExportAsView(typeof(NavigationView), IsShell = true)]
[ExportViewToRegion(typeof(NavigationView), Global.Constants.NAVIGATION_REGION)]
public partial class NavigationView: UserControl
{
    public NavigationView()
    {
        InitializeComponent();
    }

    [Export]
    public ViewModelRoute Binding
    {
        get { return ViewModelRoute.Create<NavigationViewModel, NavigationView>()}; }
    }
}

ItemListViewModel.cs

[ExportAsViewModel(typeof(ItemListViewModel))]
public class ItemListViewModel: BaseViewModel, IItemListViewModel, IEventSink<ViewNavigationArgs>, IEventSink<UnhandledExceptionEvent>
{
    [Import]
    public Global Globals { get; set; }

    [Impot]
    public IMyApplicationContext Appcontext { get; set; }

    public IActionCommand<string> ViewListItemCMD { get; private set; }

    ICommand IItemListViewModel.ViewListItemCMD 
    {
        get { return ViewListItemCMD; }
    }

    private ObservableCollection<IItem> _Items = new ObservableCollection<IItem>();
    public ObservableCollection<IItem> Items
    {
        get
        { 
            return _Items;
        }
    }

    public ItemListViewModel()
    {
        ViewListItemCMD = new ActionCommand<string>(ShowView);
    }

    protected override void InitializeVm()
    {
        EventAggregator.Subscribe<ViewNavigationArgs>(this);
        EventAggregator.Subscribe<UnhandledExceptionEvent>(this);
        base.InitializeVm();
        AppContext.Title = "My Application List Page Title";
    }

    protected override void ActivateView (string viewName, IDictionary<string, object> viewParameters)
    {
        LoadItems();
        base.ActivateView(viewName, viewParameters);
    }

    public void ShowView(string parameter)
    {
        if (parameter != null)
            EventAggregator.Publish(Globals.ItemView.AsViewNavigationArgs().AddNamedParameter("ItemID", parameter));
            // Here is where the EventAggregator is null
    }

    public void HandleEvent(ViewNavigationArgs publishedEvent)
    {
        var viewMetadata = Router.GetMetadataForView(publishedEvent.ViewType);

        if (viewMetadata == null || !viewMetadata.Category.Equals("Menu"))
        {
             return; // I have not started using the menu category yet
        }
    }

    public void HandleEvent(UnhandeledExceptionEvent unhandeledEvent)
    {
        ...
    }

    private void LoadItems()
    {
        try
        {
            _Items.Clear();
            _Items = ItemsCollection.Instance().Items;
            RaisePropertyChanged(() => Items);
        } catch (Exception ex) {
            //TODO: Add to logger
        }
    }
}

ItemListView.cs

[ExportAsView(typeof(ItemListView)]
[ExportViewToRegion(typeof(ItemListView), Global.Constants.CONTENT_REGION)]
public partial class ItemListView: UserControl
{
    public ItemListView()
    {
        InitializeComponent();
    }

    [Export]
    public ViewModelRoute Binding
    {
        get { return ViewModelRoute.Create<ItemListViewModel, ItemListView>()}; }
    }
}

ItemViewModel.cs

[ExportAsViewModel(typeof(IItemViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ItemViewModel: BaseEntityViewModel, IItemViewModel
{
    [Import]
    public Global Globals { get; set; }

    [Impot]
    public IMyApplicationContext Appcontext { get; set; }

    public IActionCommand<string> SaveCMD { get; private set; }

    ICommand IItemListViewModel.SaveCMD 
    {
        get { return SaveCMD ; }
    }

    private IItem _Item = new Item();
    public IItem Item
    {
        get 
        {
            return _Item;
        }
        set
        {
            _Item = value;
            RaisePropertyChanged(() => Item);
        }
    }

    private long _ItemId;
    public long ItemId
    {
        get 
        {
            return _ItemId;
        }
        set
        {
            _ItemId = value;
            RaisePropertyChanged(() => ItemId);
        }
    }

    public ItemViewModel()
    {
        SaveCMD = new ActionCommand<string>(SaveItem);
    }

    protected override void InitializeVm()
    {
        base.InitializeVm();
        AppContext.Title = "My Application Item Page Title";
    }

    protected override void ActivateView (string viewName, IDictionary<string, object> viewParameters)
    {
        ItemId = viewParameters.ParameterValue<long>("ItemId")
        LoadItem();
        base.ActivateView(viewName, viewParameters);
    }

    public void SaveItem(string parameter)
    {
        EventAggregator.Publish(Globals.HomeView.AsViewNavigationArgs());
    }

    private void LoadItem()
    {
        Item = ItemCollection.Instance().GetItemByID(ItemId);
    }
}

ItemView.cs

[ExportAsView(typeof(ItemView)]
[ExportViewToRegion(typeof(ItemView), Global.Constants.CONTENT_REGION)]
public partial class ItemView: UserControl
{
    public NavigationView()
    {
        InitializeComponent();
    }

    [Export]
    public ViewModelRoute Binding
    {
        get { return ViewModelRoute.Create<ItemViewModel, ItemView>()}; }
    }
}
Oct 3, 2013 at 3:01 PM
Is the EventAggregator available in your MainViewModel and NavigationViewModel? I think we need to see some sample code, please.
Oct 3, 2013 at 4:03 PM
Well that looks OK to me. Are you sure it's the EventAggregator that's null, not Globals? I can't see where you export that from the code you have posted.
Oct 3, 2013 at 5:11 PM
Edited Oct 3, 2013 at 5:13 PM
I did not include the code for Global but yes the class is exported. I finised posing all of the code a little after you looked at it so the MainPage, Navigation that launches the list as well as the list and the item page.

In Global I only have constants defined for the Content and Navigation Regions and the public readonly strings for the views; here is an example
Global.cs

[Export]
public class Global
{
    public static class Constants
    {
        public const string NAVIGATION_REGION = "NavigationRegion";
        public const string CONTENT_REGION = "ContentRegion";
    }

    public readonly string NavigationView = typeof(NavigationView).FullName;
    public readonly string HomeView = typeof(HomeView).FullName;
    public readonly string ItemListView = typeof(ItemListView).FullName;
    public readonly string ItemView = typeof(ItemView).FullName;

    ICommand ExportCMD
    {
        get { return ExportCommand}
    }

    public IActionCommand<object> ExportCommand { get; set; }
}
The Command in the ItemListView is in the CellTemplate <Button control> on a Telerik Gridview for Silverlight
Oct 3, 2013 at 9:01 PM
I have looked at EventAggregator at the end of ActivateView in debug and it is not null; however when I click on any button (I added some test buttons) the call to LoadItem occurs and EventAggregator is null. This is not the case for the rest of the navigation calls from the menu, so I am thinking that I have somethIng wired up incorrectly.
Oct 4, 2013 at 8:23 AM
Aha! Now we're getting somewhere. Presumably, then, you have more than one instance of the ViewModel. How are you binding the Button control's command property to the IActionCommand in your ViewModel? Can we see the xaml?
Oct 5, 2013 at 9:18 PM
Edited Oct 6, 2013 at 4:34 PM
(+1) That was exactly the issue. I had a static reference to the viewmodel in the xaml that I was using to reference the command. I took that out and wired in the command using a relative source.
<telerik:RadButton Command="{Binding Path=DataContext.ViewListItemCMD, RelativeSource={RelativeSource FindAncestor, AncestorType=telerik:RadGridView}}" CommandParameter="{Binding ID}" />
This is the xaml for the button that sits in the grid column CellTemplate DataTemplate.

The button fires correctly now, but I have a new problem, the ItemView page thinks that it is wired to the MainViewModel and not to the ItemViewModel as defined in the ViewModel Route like is shown above.

Thank again for your help, still getting used to the Jounce framework.
Oct 7, 2013 at 8:08 AM
The DataContext of LayoutRoot (or whatever the top-level layout is (I think!)) on your ItemView will be ItemViewModel.
Oct 7, 2013 at 8:21 AM
Incidentally, will this not work?
<telerik:RadButton Command="{Binding ViewListItemCMD}" CommandParameter="{Binding ID}" />
I'm not familiar with Telerik controls, so it might not, but it does with standard Microsoft buttons.
Oct 7, 2013 at 7:27 PM
Hey John_cat,

Thanks for all of the help. I had views that were nested inside the ItemView so I had to specify a relative DataContext for them. Once I did that everything worked including the command wireup. Thanks again for all of the help.