تفاوتهای پیاده سازی مثال پست قبلی با این پست:
- در مثال قبل پروژه به صورت Desktop و با WPF پیاده سازی شده بود ولی در این مثال با Silverlight میباشد؛
- در مثال قبل از UnityBootstrapper استفاده شده بود ولی در این مثال از MefBootstrapper؛
- در مثال قبل هر View در یک ماژول قرار داشت ولی در این مثال هر دو View را در یک ماژول قرار دادم؛
- در مثال قبل از Prism Libary 2.x استفاده شده بود ولی در این مثال از PrismLibrary 4.x؛
- و...
نکته : برای فهم بهتر مفاهیم، آشنایی اولیه با MEF و مفاهیمی نظیر Export و Import و AggregateCatalog و AssemblyCatalog نیاز است. در صورتی که با این مطالب آشنایی ندارید میتوانید از (^) شروع کنید.
برای شروع یک پروژه Silverlight ایجاد کنید. بعد از اضافه شدن دو پروژه Silverlight و Web، یک Silverlight Class Library جدید بسازید.
ابتدا یک Page ایجاد کنید و کدهای زیر را در آن کپی کنید.
<UserControl x:Class="Module1.Module1View1" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" FlowDirection="RightToLeft" FontFamily="Tahoma"> <StackPanel> <sdk:DataGrid Height="100"> <sdk:DataGrid.Columns> <sdk:DataGridTextColumn Header="کد" Width="50" /> <sdk:DataGridTextColumn Header="عنوان" Width="200" /> <sdk:DataGridTextColumn Header="نویسنده" Width="150" /> </sdk:DataGrid.Columns> </sdk:DataGrid> <Button x:Name="NextViewButton" Width="150" Height="25" Foreground="Red" Background="Blue" Content="لیست طبقه بندی ها" /> </StackPanel> </UserControl>
[Export(typeof(Module1View1))] public partial class Module1View1 : UserControl { [Import] public IRegionManager TheRegionManager { private get; set; } public Module1View1() { InitializeComponent(); NextViewButton.Click += NextViewButton_Click; } void NextViewButton_Click(object sender, RoutedEventArgs e) { TheRegionManager.RequestNavigate ( "MyRegion1", new Uri("Module1View2", UriKind.Relative), a => { } ); } }
حال یک Page دیگر برای طبقه بندی کتابها ایجاد کنید و کدهای زیر را در آن کپی کنید.
<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="Module1.Module1View2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" FlowDirection="RightToLeft" FontFamily="Tahoma"> <StackPanel> <sdk:DataGrid Height="100"> <sdk:DataGrid.Columns> <sdk:DataGridTextColumn Header="کد" Width="150"/> <sdk:DataGridTextColumn Header="عنوان" Width="150"/> </sdk:DataGrid.Columns> </sdk:DataGrid> <Button x:Name="NextViewButton" Width="150" Height="25" Foreground="Green" Background="Yellow" Content="لیست کتاب ها" /> </StackPanel> </UserControl>
using Microsoft.Practices.Prism.Regions; using System; using System.ComponentModel.Composition; using System.Windows; using System.Windows.Controls; namespace Module1 { [Export] public partial class Module1View2 : UserControl { IRegion _region1; [ImportingConstructor] public Module1View2( [Import] IRegionManager regionManager ) { InitializeComponent(); ViewModel viewModel = new ViewModel(); DataContext = viewModel; viewModel.ShouldNavigateFromCurrentViewEvent += () => { return true; }; _region1 = regionManager.Regions["MyRegion1"]; NextViewButton.Click += NextViewButton_Click; } void NextViewButton_Click( object sender, RoutedEventArgs e ) { _region1.RequestNavigate ( new Uri( "Module1View1", UriKind.Relative ), a => { } ); } } }
نکته: اگر یک کلاس، سازنده با پارامتر داشته باشد باید با استفاده از ImportingConstructor حتما سازنده مورد نظر را هنگام وهله سازی مشخص کنیم در غیر این صورت با Exception مواجه خواهید شد.
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 System.ComponentModel.Composition; using Microsoft.Practices.Prism.Regions; namespace Module1 { public class ViewModel : IConfirmNavigationRequest { public event Func<bool> ShouldNavigateFromCurrentViewEvent; public bool IsNavigationTarget( NavigationContext navigationContext ) { return true; } public void OnNavigatedTo( NavigationContext navigationContext ) { } public void OnNavigatedFrom( NavigationContext navigationContext ) { } public void ConfirmNavigationRequest( NavigationContext navigationContext, Action<bool> continuationCallback ) { bool shouldNavigateFromCurrentViewFlag = false; if ( ShouldNavigateFromCurrentViewEvent != null ) shouldNavigateFromCurrentViewFlag = ShouldNavigateFromCurrentViewEvent(); continuationCallback( shouldNavigateFromCurrentViewFlag ); } } }
- IsNavigateTarget : برای تعیین اینکه آیا کلاس پیاده سازی کننده اینترفیس، میتواند عملیات راهبری را مدیریت کند یا نه.
- OnNavigateTo : زمانی عملیات راهبری وارد View شود(بهتره بگم View مورد نظر در Region صفحه لود شود) این متد فراخوانی میشود.
- OnNavigateFrom : زمانی که راهبری از این View خارج میشود (View از حالت لود خارج میشود) این متد فراخوانی خواهد شد.
- ConfirmNavigationRequest : برای تایید عملیات راهبری توسط کلاس پیاده سازی کننده اینترفیس استفاده میشود.
using Microsoft.Practices.Prism.MefExtensions.Modularity; using Microsoft.Practices.Prism.Modularity; using Microsoft.Practices.Prism.Regions; using System.ComponentModel.Composition; namespace Module1 { [ModuleExport(typeof(Module1Impl))] public class Module1Impl : IModule { [Import] public IRegionManager TheRegionManager { private get; set; } public void Initialize() { TheRegionManager.RegisterViewWithRegion("MyRegion1", typeof(Module1View1)); TheRegionManager.RegisterViewWithRegion("MyRegion1", typeof(Module1View2)); } } }
در متد Initialize برای RegionManager دو View ساخته شده را رجیستر کردیم. این کار باید به تعداد Viewهای موجود در ماژول انجام شود.
در پروژه اصلی بک Page به نام Shell ایجاد کنید و کدهای زیر را در آن کپی کنید.
<UserControl x:Class="NavigationViaViewModel.Shell" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://www.codeplex.com/prism" FlowDirection="RightToLeft" FontFamily="Tahoma"> <Grid x:Name="LayoutRoot" Background="White"> <TextBlock Text="لیست کتابها به همراه طبقه بندی آن ها" FontSize="19" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Top" /> <ContentControl HorizontalAlignment="Center" VerticalAlignment="Center" prism:RegionManager.RegionName="MyRegion1" /> </Grid> </UserControl>
حال نیاز به یک Bootstrapper داریم. برای این کار یک کلاس به نام TheBootstrapper بسازید:
using Microsoft.Practices.Prism.MefExtensions; using Microsoft.Practices.Prism.Modularity; using System.ComponentModel.Composition.Hosting; using System.Windows; namespace NavigationViaViewModel { public class TheBootstrapper : MefBootstrapper { protected override void InitializeShell() { base.InitializeShell(); Application.Current.RootVisual = (UIElement)Shell; } protected override DependencyObject CreateShell() { return Container.GetExportedValue<Shell>(); } protected override void ConfigureAggregateCatalog() { base.ConfigureAggregateCatalog(); AggregateCatalog.Catalogs.Add(new AssemblyCatalog(this.GetType().Assembly)); } protected override IModuleCatalog CreateModuleCatalog() { ModuleCatalog moduleCatalog = new ModuleCatalog(); moduleCatalog.AddModule ( new ModuleInfo { InitializationMode = InitializationMode.WhenAvailable, Ref = "Module1.xap", ModuleName = "Module1Impl", ModuleType = "Module1.Module1Impl, Module1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" } ); return moduleCatalog; } } }
متد ConfigureAggregateCatalog برای مدیریت کاتالوگها و ماژولها که هر کدام در یک اسمبلی جدا وجود خواهند شد استفاده میشود. در این متد من از AssemblyCatalog استفاده کردم. AssemblyCatalog تمام کلاس هایی که ExportAttribute را به همراه دارند شناسایی میکند و آنها را در Container نگهداری خواهد کرد(^). مانند یک ServiceLocator در Microsoft unity Service Locator(^) .
متد آخر به نام CreateModuleCatalog است و باید در آن تمام ماژولهای برنامه را به کلاس ModuleCatalog اضافه کنیم. در مثال پست قبلی به دلیل استفاده از UnityBootstrapper باید این کار را از طریق BuildEvent ها مدیریت میکردیم ولی در این جا Mef به راحتی این کار را انجام خواهد داد.
تغییرات زیر را در فایل App.Xaml قرار دهید و پروژه را اجرا کنید.
public partial class App : Application { public App() { this.Startup += this.Application_Startup; InitializeComponent(); } private void Application_Startup(object sender, StartupEventArgs e) { var bootstrapper = new TheBootstrapper(); bootstrapper.Run(); } }
دریافت سورس پروژه
ادامه دارد..