Publié dimanche 3 février 2008 13:28 par Adrien Siffermann

[Silverlight] Créer une application modulaire (Partie 2)

Dans le précédent billet, nous avons vu comment créer un module en Silverlight qui dispense un objet Control, ainsi qu'un WebService qui permet de donner une liste de tous les modules disponibles côté serveur. Nous allons voir aujourd'hui comment, à partir de la liste des modules récupérée depuis le WebService, nous allons pouvoir les télécharger au chargement de la page, puis incorporer les Control que ces derniers dispensent dans le Canvas principal.

J'ai écrit une classe Modman qui s'occupe de la première partie. Il appelle le WebService pour récupérer les URI relatives, télécharge la DLL grâce au Downloader puis créé une instance de la classe qui implémente l'interface IModule avec Activator.CreateInstance. Toutes les instances des modules sont alors stockées dans une liste accessible en lecture.

    public class Modman

    {

        private List<IModule> _modules = new List<IModule>();

        private ModmanWS.Modman _ws = new ModmanWS.Modman();

        private List<ModuleAssembly> _modAssemblyList = new List<ModuleAssembly>();

 

        public event EventHandler OnAllModulesLoaded;

        public event EventHandler OnModuleDownloadFailed;

        public event EventHandler<ModuleErrorEventArgs> OnModuleLoadError;

 

        public List<IModule> ModulesInstances

        {

            get { return _modules; }

        }

 

        public void DownloadAndLoadAllModules()

        {

            string[][] modList = _ws.GetModulesList();

 

            foreach (var mod in modList)

            {

                ModuleAssembly assembly = new ModuleAssembly(mod[0], mod[1], new Uri(mod[2], UriKind.Relative));

                _modAssemblyList.Add(assembly);

 

                Downloader loader = new Downloader();

                loader.Completed += new EventHandler(onDownloadComplete);

                loader.DownloadFailed += new ErrorEventHandler(onDownloadFailed);

 

                loader.Open("GET", assembly.Url);

                loader.Send();

            }

        }

 

        private void onDownloadComplete(object sender, EventArgs e)

        {

            ModuleAssembly assemblyInfo = retrieveAssemblyDownloaded(sender as Downloader);

 

            if (assemblyInfo != null)

            {

                loadModule(assemblyInfo);

                _modAssemblyList.Remove(assemblyInfo);

                if (_modAssemblyList.Count == 0 && this.OnAllModulesLoaded != null)

                    this.OnAllModulesLoaded(this, new EventArgs());

            }

        }

 

        private void onDownloadFailed(object sender, EventArgs e)

        {

            if (this.OnModuleDownloadFailed != null)

                this.OnModuleDownloadFailed(this, new EventArgs());

        }

 

        private ModuleAssembly retrieveAssemblyDownloaded(Downloader loader)

        {

            ModuleAssembly assemblyInfo = null;

            foreach (ModuleAssembly assembly in _modAssemblyList)

            {

                if (assembly.Url == loader.Uri)

                {

                    assemblyInfo = assembly;

                    break;

                }

            }

            return assemblyInfo;

        }

 

        private void loadModule(ModuleAssembly assemblyInfo)

        {

            try

            {

                Assembly assembly = Assembly.Load(assemblyInfo.AssemblyName);

                foreach (Type type in assembly.GetTypes())

                {

                    if (type.GetInterface(typeof(IModule).FullName, false) != null)

                    {

                        IModule instance = (IModule)Activator.CreateInstance(type);

                        _modules.Add(instance);

                    }

                }

            }

            catch (Exception ex)

            {

                if (OnModuleLoadError != null)

                    OnModuleLoadError(this, new ModuleErrorEventArgs(ex));

            }

        }

    }

Notez que j'utilise un objet ModuleAssembly, qui ne me sert en fait qu'à stocker les informations d'un module que retourne le WebService.

On y est presque ! Dans le code de ma page principale Silverlight, je m'abonne aux évènements de Modman, pour pouvoir afficher l'état du chargement des modules dans mon Canvas, et lorsque tous les modules ont été chargés, je récupère la liste des instances de modules, et j'ajoute pour chacun d'entre eux le MainControl au Canvas.

    public partial class Page : Canvas

    {

        public void Page_Loaded(object o, EventArgs e)

        {

            InitializeComponent();

            Modman mm = new Modman();

 

            mm.OnAllModulesLoaded += new EventHandler(ModMan_OnAllModulesLoaded);

            mm.OnModuleDownloadFailed += new EventHandler(ModMan_OnModuleDownloadFailed);

            mm.OnModuleLoadError += new EventHandler<ModuleErrorEventArgs>(ModMan_OnModuleLoadError);

 

            mm.DownloadAndLoadAllModules();

        }

 

        void ModMan_OnModuleLoadError(object sender, ModuleErrorEventArgs e)

        {

            this.statusText.Text += e.Exception.Message;

        }

 

        void ModMan_OnModuleDownloadFailed(object sender, EventArgs e)

        {

            this.statusText.Text += "Cannot download module";

        }

 

        void ModMan_OnAllModulesLoaded(object sender, EventArgs e)

        {

            try

            {

                Modman moduleManager = sender as Modman;

                foreach (IModule module in moduleManager.ModulesInstances)

                {

                    Control ctrl = module.MainControl;

 

                    ctrl.SetValue<double>(Canvas.LeftProperty, 50);

                    ctrl.SetValue<double>(Canvas.TopProperty, 50);

                    ctrl.Visibility = Visibility.Visible;

 

                    this.Children.Add(ctrl);

                }

            }

            catch (Exception ex)

            {

                this.statusText.Text += ex.Message;

            }

        }

    }

Et voilà, nous avons une application Silverlight complètement modulaire ! Les modules sont libres de personnaliser le contrôle qu'ils veulent mettre à disposition, tandis que l'application centrale garde la main sur la disposition de ces derniers dans la Canvas principal. De plus, il suffit de modifier le WebService en filtrant la liste des modules qu'il retourne pour apporter une logique métier aux modules activés (selon l'utilisateur par exemple).

Adrien

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Classé sous

# re: [Silverlight] Créer une application modulaire (Partie 2) @ dimanche 3 février 2008 19:19

Très malin comme technique: bonne idée :)

Thomas LEBRUN

# re: [Silverlight] Créer une application modulaire (Partie 2) @ lundi 4 février 2008 10:17

Vraiment très bien, merci

pc152


Les 10 derniers blogs postés

- [SharePoint] Les sessions TechDays 2012… par Le blog de Patrick [MVP SharePoint] le il y a 6 heures et 27 minutes

- TechDays Paris 2012 : Session pleinière jour 3 par Blog Technique de Romelard Fabrice le 02-09-2012, 11:01

- Mishra Reader : un lecteur RSS très Zune Style en Open Source ! par Cyril Sansus le 02-09-2012, 08:28

- [framework 4] Les Tasks et le Thread UI par Fathi Bellahcene le 02-09-2012, 00:33

- Workflow Foundation 3 a un pied dans la tombe par Blog de Jérémy Jeanson le 02-08-2012, 22:15

- TechDays Paris 2012 : Nouvelles tendances du poste de travail - Bring Your own PC par Blog Technique de Romelard Fabrice le 02-08-2012, 19:42

- TechDays Paris 2012 : System Center Service Manager 2012 Vue d’ensemble par Blog Technique de Romelard Fabrice le 02-08-2012, 17:32

- TechDays Paris 2012 : Pleinière second jour par Blog Technique de Romelard Fabrice le 02-08-2012, 16:23

- TechDays Paris 2012 : Retour d'expérience sur la mise en place d'un Cloud Privé par Blog Technique de Romelard Fabrice le 02-08-2012, 16:04

- TechDays Paris 2012 : Comment SharePoint a sauvé mes TechDays par Blog Technique de Romelard Fabrice le 02-07-2012, 23:59