۱۳۹۱ بهمن ۷, شنبه

آشنایی با Prism - Bootstrapper

در پست قبل اندکی با Bootstrapper، آشنا شدیم. اما این کلاس حرف های بسیاری برای گفتن دارد. در ادامه با برخی جزئیات این سلسله تنظیمات بیشتر آشنا می شویم.


شکل بالا گام های لازم برای مقدار دهی اولیه ی یک برنامه Prism را مشخص می کند. 

ایجاد یک ILoggerFacade: با override کردن تابع CreateLogger در Bootstrapper، شما این اختیار را دارید تا یک logger برای خود تهیه کنید. این logger در طول کل برنامه در دسترس شما خواهد بود. همچنین خود کتابخانه Prism، گزارش های خود را به این logger می فرستد تا شما در جریان روند امور باشید. برای طراحی یک logger کافیست یک کلاس تعریف کرده و واسط ILoggerFacade را در آن پیاده سازی کنید. ما برای سادگی کار گزارش ها را بر روی فایل ذخیره می کنیم. شما می توانید هر نوع پیاده سازی (ذخیره در بانک اطلاعاتی، ارسال ایمیل و ...) دلخواه خود را انجام دهید.
using System;
using System.IO;
using System.Text;
using Microsoft.Practices.Prism.Logging;

namespace PrismApp.Shell
{
    public class TextFileLogger : ILoggerFacade
    {
        private readonly string _fileName = Path.Combine(Environment.CurrentDirectory, "PrismApp.log");
        private readonly object _syncLock = new object();

        public TextFileLogger()
        {
        }

        public void Log(string message, Category category, Priority priority)
        {
            WriteToFile(category.ToString(), message);
        }


        private void WriteToFile(string type, string message)
        {
            lock (_syncLock)
            {
                using (var writer = new StreamWriter(_fileName, true, Encoding.UTF8))
                {
                    writer.WriteLine(string.Format("{0:G}\t{1}:{2}", DateTime.Now, type, message));
                }
            }
        }
    }
}

واسط ILoggerFacade فقط یک تابع Log دارد که در آن پیام، وضعیت و اولویت آن مشخص شده است. شما می توانید مطابق میل خود، اطلاعات لازم را دریافت و ذخیره کنید. در این مثال، فقط وضعیت و متن را ذخیره می شود. اکنون برای مقدار دهی اولیه logger در کلاس Bootstrapper به این شکل عمل می کنیم:

        protected override Microsoft.Practices.Prism.Logging.ILoggerFacade CreateLogger()
        {
            return new TextFileLogger();
        }
با ایجاد یک نمونه از کلاس ساخته شده و بازگرداندن آن، Prism، از این نمونه برای عملیات گزارش استفاده می کند.

ایجاد Module Catalog: در صورتی که برنامه ی شما ماژولار است، با پیاده سازی تابع CreateModuleCatalog می توانید نحوه بارگذاری ماژول های برنامه را مشخص کنید. برای مثال اگر می خواهید ماژول ها را از مسیر خاصی بارگذاری کنید می توانید یک نمونه از DirectoryModuleCatalog استفاده کنید.

        protected override IModuleCatalog CreateModuleCatalog()
        {
            return new DirectoryModuleCatalog()
            {
                ModulePath = Environment.CurrentDirectory;
            };
        }

بدین وسیله، هنگام اجرای برنامه، Prism در مسیر مشخص شده (در این مثال، مسیر اجرای برنامه) به دنبال ماژول ها می گردد و در صورت پیدا کردن، آن ها را بارگذاری می کند. در پست های آینده با نحوه ایجاد ماژول بیشتر آشنا خواهیم شد.

پیکربندی Container: تزریق وابستگی نقش کلیدی را در برنامه های مبتنی بر Prism ایفا می کند. در این مرحله، سرویس های اصلی (Core Services)، بطور پیشفرض توسط Prism در Container ثبت می شوند. اما می توان این کار را بطور دستی نیز انجام داد. اضافه بر این، سرویس های برنامه کاربردی نیز باید توسط برنامه نویس در Container ثبت شوند. از انجایی که فعلا فقط قصد تکمیل اسکلت کامل یک برنامه ماژولار Prism را داریم، سرویس خاصی در Container ثبت نمی کنیم. Prism بطور پیش فرض، بسیاری از سرویس های مورد نیاز را ثبت می کند. در پست های بعدی به این قسمت برمیگردیم. فعلا تابع ConfigureContainer ما در حد ثبت MainWindow باقی می ماند.

        protected override void ConfigureContainer()
        {
            // Register default core services
            base.ConfigureContainer();
            // Register Shell (main window)
            Container.RegisterType<MainWindow>();
        }
پیکربندی RegionAdapterMapping و RegionBehavior پیش فرض: در برنامه های مبتنی بر Prism، مدیریت View ها اندکی متفاوت از برنامه های WPF عادی است. در یک برنامه ماژولار ممکن است View خاصی در یک ماژول تعریف شده باشد و با اجرای فرمانی نیاز باشد آن View به کاربر نمایش داده شود.  بدین منظور از قبل باید در View اصلی برنامه (همان Shell که در اینجا منظور MainWindow است) قسمت هایی تعریف شوند که قادر به نمایش View ها باشند. به این قسمت ها Region گفته می شود. بدین صورت شما می توانید در Shell برنامه، یک یا چند Region با نام های منحصر به فرد طراحی کنید تا ماژول ها بتوانند در آن View های خود را نمایش دهند. در پست های بعدی بیشتر به این قسمت خواهیم پرداخت و فعلا توابع مربوط به آن را override نمی کنیم.

ثبت FrameworkExceptions: شما می توانید استثنا (Exception) های خاصی را در Prism ثبت کنید تا هنگام رخ دادن، استثنای اصلی توسط تابع GetRootException پیدا شده و نمایش داده شود. استثناهای ثبت شده، به سادگی در یک لیست Static ذخیره می شوند. در صورتی که یک Exception، در این لیست ثبت نشده باشد، پس از رخ دادن بدون جستجو برای InnerException اصلی، دوباره throw می شود. از این امکان بسیار به ندرت استفاده می شود.

CreateShell: همانطور که در پست قبل خواندید، از این تابع برای ایجاد View اصلی برنامه (که Shell نامیده می شود) استفاده می شود. در ادامه تابع دیگری به نام InitializeShell وجود دارد که پس از این تابع فراخوانی می شود و پیاده سازی آن نیز اختیاری است. در صورتی که برنامه شما WPF باشد می توانید در این تابع، کد مربوط به مقدار دهی اولیه و نمایش پنجره اصلی را بنویسید. بدین جهت، تغییرات زیر در کلاس Bootstrapper انجام می شود:

        protected override System.Windows.DependencyObject CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }

        protected override void InitializeShell()
        {
            Application.Current.MainWindow = (Window)this.Shell;
            Application.Current.MainWindow.Show();
        }
بدین صورت، ما با override کردن تابع CreateShell، فقط یک نمونه سازی از کلاس MainWindow انجام می دهیم و سپس در تابع InitializeShell، پنجره اصلی برنامه WPF را مشخص کرده و آن را به کاربر نمایش می دهیم.

InitializeModules: همان طور که قبلا ذکر شد، در تابع ConfigureContainer، برخی سرویس های اصلی Prism با کلاس های پیش فرض ثبت می شوند. یکی از آن سرویس ها، IModuleManager است. این سرویس (واسط) وظیفه بارگذاری ماژول های برنامه را بر عهده دارد. در این سرویس، رویداد هایی به نام ModuleDownloadProgressChanged و LoadModuleCompleted وجود دارد که با subscribe شدن، می توان پیشرفت بارگذاری ماژول ها و زمان اتمام بارگذاری آن ها را مشاهده کرد. کتابخانه Prism یک پیاده سازی پیشفرض (کلاس) از این سرویس به عنوان ModuleManager دارد که در تابع ConfigureContainer، آن را ثبت کرده است. در صورتی که پس از override کردن این تابع، تابع base آن فراخوانی شده باشد، این سرویس بطور پیش فرض در Container ثبت شده است و نیازی نیست چیزی را تغییر بدهید.

خب، تا به این جا به اندازه کافی با Bootstrapper آشنا شده ایم. در پست بعدی به سراغ ماژول نویسی رفته و بخشی از مفاهیم Region ها را در کنار آن می آموزیم.

دریافت سورس کد کامل با تگ Step 2