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

- ssdl view et TPT par Matthieu MEZIL le 07-05-2008, 02:04

- L'injection SQL n'est PAS un problème QUE pour les développeurs web ! par CoqBlog le 07-05-2008, 01:08

- Un outil pour réaliser des animations WPF basées sur des équations de Bézier par Perspective le 07-04-2008, 21:45

- Sandcastle et CodePlex : le verdict par CoqBlog le 07-04-2008, 20:53

- ssdl view et TPH par Matthieu MEZIL le 07-04-2008, 19:12

- Webcasts sur le Parallel Framework disponibles par Matthieu MEZIL le 07-04-2008, 17:26

- [Silverlight] - Comprendre et Débuter avec Silverlight par Danuz le 07-04-2008, 12:41

- SharePoint : Nouvel article sur l'exportation et Importation de sites SharePoint par Blog Technique de Romelard Fabrice le 07-04-2008, 01:00

- ImagineCup 2008 Final in Paris: Day 1 par Richard Clark le 07-03-2008, 22:48

- PowerShell : Comment utiliser un ENUM .NET dans un script PowerShell par Blog Technique de Romelard Fabrice le 07-03-2008, 18:09