Sharepoint 2010 Client Context, Silverlight Web Part

Topics: Prism v4 - Silverlight 4
May 22, 2012 at 6:03 PM

Hello,

I am very new to Sharepoint 2010 and am getting familiar with the Prism architecture. Here is my situation.

My boss would like me to write a silverlight web application that can be hosted in Sharepoint 2010 through a Silverlight Web Part. I would like to use the Prism (MVVM) architecture to develop this application. I have some test applications that seem to be working fine.

My boss wants me to collect the Client Model Object from Sharepoint to get the Current User so that I can pass that into services to retrieve the correct information. Each ViewModel will need to be passed this or collect it.

That is my issue. I am able to get the Current User from Sharepoint in the 'Shell.xaml'. But I would like to gather that information inside the App.xaml.cs to pass to the Bootstrapper class or within the Bootstrapper class. Either way so I can pass it into each of my views. If that cannot be done, I would like to get the information in each of the View's ViewModel class. When I try the latter I get errors referencing my Bootstrapper and not being intialized.

Any suggestions?

Developer
May 22, 2012 at 8:04 PM

Hi,

If I understood currently, you are able to obtain the Current User in your Shell and you want to share that information to the rest of the views / view models in your application. If so, I believe a possible approach could be to define a shared service that would be known by all the views / view models and where the Shell can load the information of the Current User.

For example, you could define a CurrentUserService in your Shell project that could expose a CurrentUser property and a CurrentUserChanged event. If a view / view model needs to know the Current User, it could retrieve the service though dependency injection and obtain the Current User from its CurrentUser property. If the Current User is not loaded in the CurrentUserService yet, the views / view models could subscribe to the CurrentUserChanged event to be notified when the Current User is available in the service (this may not be required, but might be useful to avoid possible timing issues). Then, in the Shell you could also retrieve the service through dependency injection and load the Current User in its CurrentUser property so that it could be available for the rest of the views.

You can find more information about shared services in the following chapter of the Prism documentation:

I hope you find this useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

May 23, 2012 at 6:07 PM

Damian,

First, thank you for pointing me in that direction. I believe it is the way to go, unfortunately it is not working correctly. I have added code from about 4 files that would link an Event together. The project compiles fine and runs. The Shell xaml has a button on it and a region. The Region is made up of another SilverList class library that has a user control in it called InitalView.xaml. If I click the button on the Shell xaml file, I want the program to publish to the CurrentUserEvent with the string "hello". At that point the InitialViewModel.cs that subscribes to the CurrentUserEvent would fire and the UpdateUserName function inside the InitialViewModel.cs would run and I would see the word "hello" display in that region.

As the program loads, I see the Subscribe line fire off. When I press the button I see the Publish line fire off. It does not fire off the UpdateUserName function in the InitialViewModel.cs that the Subscribe was attached to, so there is no "hello" shown in the region. Please let me know if you see anything wrong I am doing.

Here is the code for my event. It is in a Silverlight Class library project I have declared the Event for the system to Subscribe and Publish to.

using Microsoft.Practices.Prism.Events;

namespace MediaReach.Infrastructure.Silverlight
{
    public class CurrentUserEvent : CompositePresentationEvent
    {

    }
}

Here is the code in my Bootstrapper.cs that is called from my App.xaml.cs and uses my Shell.xaml and associates the region to my InitialModule:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Practices.Prism.UnityExtensions;
using Microsoft.Practices.Prism.Modularity;

namespace MediaReach
{
    public class Bootstrapper : UnityBootstrapper 
    {
        protected override DependencyObject CreateShell()
        {
            Shell rootShell = new Shell();
            Application.Current.RootVisual = rootShell;
            return rootShell;
        }

        protected override IModuleCatalog CreateModuleCatalog()
        {
            ModuleCatalog modules = new ModuleCatalog();
            modules.AddModule(typeof(MediaReach.UI.InitialModule));
            //modules.AddModule(typeof(ModuleWorld.WorldModule));
            return modules;
        }
    }
}

Here is the Shell.xaml.cs that is referenced in the CreateShell function from the Bootstrapper. The function getUserInformation runs when I click on a button in the Shell.xaml page:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.SharePoint.Client;
using System.Threading;
using Microsoft.Practices.Prism.Events;
using MediaReach.Infrastructure.Silverlight;

namespace MediaReach
{
    public partial class Shell : UserControl
    {
        private IEventAggregator eventAggregator { get; set; }

        public Shell()
        {
            InitializeComponent();
            this.eventAggregator = new EventAggregator(); 
        }

        private void getUserInformation(object sender, RoutedEventArgs e)
        {
            this.eventAggregator.GetEvent<CurrentUserEvent>().Publish("hello");
        }

    }
}

Here is the code for MediaReach.UI.InitialModule that is referenced in the Bootstrapper CreateModuleCatalog. It is in the InitialViewModel.cs file that is a View Model that supports the InitialView.xaml page. When the application runs, the system does run the Subscribe code in the InitialViewModel constructor:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using MediaReach.UI.View;
using MediaReach.Infrastructure.Silverlight;
using Microsoft.Practices.Prism.Events;

namespace MediaReach.UI.ViewModel
{
    public class InitialViewModel : IInitialViewModel 
    {

        private readonly IEventAggregator eventAggregator;

        public IInitialView View { get; set; }

        public InitialViewModel(IInitialView view, IEventAggregator eventAggregator)
        {
            View = view;
            View.Model = this;
            this.eventAggregator = eventAggregator;

            this.eventAggregator.GetEvent<CurrentUserEvent>().Subscribe(this.UpdateUserName);
        }

        public string UserName { get; set; }

        public void UpdateUserName(string name)
        {
            this.UserName = name;
        }
    }
}

 

Developer
May 23, 2012 at 8:28 PM
Edited May 23, 2012 at 8:29 PM

Hi,

I have been analyzing the code snippets you provided, and found the following suggestions:

First, I found that your type payload is missing when you define your event, for example it could look like this, if your event payload is of type string:

public class CurrentUserEvent : CompositePresentationEvent<string>{}

Although, I believe the main cause why your subscriber does not fire when you publish the event, might be related to the fact that in your Shell's code behind a new instance of the EventAggretor is created to publish the event. Instead you should use the container to retrieve the EventAggregator class instance through its IEventAggregator interface.

For example you could easily retrieve the instance of the EventAggretor by using the ServiceLocator in your Shell like this:

ServiceLocator.Current.GetInstance<IEventAggregator>().GetEvent<CurrentUserEvent>().Publish("hello");

The other option you have to retrieve this instance from the container could be by using constructor injection like you did in your InitialViewModel constructor, but to achieve this approach you will have to change your bootstrapper CreateShell method to resolve the Shell instance from the container instead of creating a new one.

Finally, take into account that when changing the UserName property in your view model, you may have to notify the UI about this change. For example your view model could inherit from the NotificationObject class provided with Prism which implements the INotifyPropertyChanged interface to achieve this. And for example you could notify the UI when the property changes, using the RaisePropertyChanged method.

Additionally you could find the following resources interesting, regarding the use of the EventAggregator:

I hope you find this helpful,

Agustin Adami
http://blogs.southworks.net/aadami

May 25, 2012 at 6:38 PM

Aadami,

I tried to put in the line

ServiceLocator.Current.GetInstance<IEventAggregator>().GetEvent<CurrentUserEvent>().Publish("hello");

but am getting an error stating The name 'ServiceLocator' does not exist in the current context.

Am I missing a reference or do I have to create a ServiceLocator.

 

Thanks again.

Developer
May 28, 2012 at 2:51 PM

Hi Kuch,

In order to use the ServiceLocator you will have to add a reference to the Microsoft.Practices.ServiceLocation.dll in your project, this assembly is provided with the Prism source code.

Also if you are interested you could find more information about the use of the ServiceLocator in the following link:

Regards,

Agustin Adami
http://blogs.southworks.net/aadami

Jun 6, 2012 at 4:20 PM

Aadami,

Sorry for not replying yet, but I believe that works. Thanks for the help.

Kuch