گواهینامه SSL دارای انواع مختلفی است، که هر نوع آن تامین کننده نیاز خاصی میباشد و از اعتبار و قیمت متفاوتی برخوردار است و علاوه بر تامین امنیت میتواند اعتبار یک سازمان را نمایش دهد. به منظور انتخاب بهترین نوع گواهینامه SSL و صرف مناسبترین هزینه به منظور برآورده نمودن نیاز و کارایی مطلوب، لازم است ابتدا تعریفی از آنها داشته باشیم ...
بخش اول - آشنایی و شروع کار با Svelte
- Rabbitmq: یکی از محبوبترین و بالغترین و قابل اعتمادترین Message broker هاست، مستندات و آموزشاش از بقیه بیشتره، سرور اون به راحتی نصب میشه،با استفاده از Rabbitmq مباحث پیشرفته ای مثل Routing و Load Balancer به راحتی قابل پیاده سازین،روی یک سرور شما میتونید حدود 20هزار پیامو در ثانیه ارسال کنید که باتوجه به اینکه شما میتونید سرورهای اون رو بصورت Cluster پیاده سازی کنید میتونین کارایی اونو بصورت قابل توجهی بالا ببرین،همچنین نکته بسیار مهمی که در Rabbitmq وجود داره اینه که در اکثر platfotmها قابل استفادس .اما کاراییش قابل مقایسه با Kafka نیست.(البته باید بگم کارایی که داره جوابگوی اکثر مواردی که حداقل خودم نیاز داشتم بوده) .
- Kafka : مهمترین خصوصیتش کارایی بسیار بالاشه ، در مواردی که کارایی براتون بسیار حیاتیه بهترین انتخابه، با استفاده از Kafka شما میتونین حدود 100هزار پیامو در ثانیه ارسال کنین که با استفاده از مفاهیمی مثل Cluster میتونین کارایشو بسیار بالاتر هم ببرین.این Message broker بیشتر تمرکزشو روی کارایی گذاشته.
- Activemq :می تونم بگم حالت متوسطی از خصوصیات دو گزینه بالاست.
<cdk-virtual-scroll-viewport></cdk-virtual-scroll-viewport>
npm install -g @angular/cli
ng new angular7-virtualScrolling
npm install @angular/cdk@latest
title = 'Angular 7 – Virtual Scrolling feature'; scrollItems: number[] = []; constructor() { for (let index = 0; index < 10000; index++) { this.scrollItems.push(index); } }
<div> <h4> {{this.title}} </h4> <cdk-virtual-scroll-viewport itemSize="100"> <div *cdkVirtualFor="let n of scrollItems">Item {{n}}</div> </cdk-virtual-scroll-viewport> </div>
تمام ! اکنون پروژه را اجرا کنید.
در اولین بار اجرا :
آیا به یادگیری یا ادامهی استفاده از AngularJS خواهید پرداخت؟
در نگاه اول شاید برای توسعه دهندگان مبتدی یک سری مباحث گیج کننده باشن و خیلی از قابلیتها هم جادویی و جذاب. اما حقیقت امر این است که code base این فریم ورک مشکلات شگفت آوری داره. چند ساعت وقت گذاشتن روی اینترنت کافی هست تا از تمام جنبهها فریم ورکهای مطرح رو بررسی کرد و متوجه شد که Angular چقدر مشکلات اساسی داره. بصورت تیتر وار چند مورد رو لیست میکنم:
- Dynamic Scoping, and scope inheritance
- Two-way data binding with $watchers
- The $digest cycle
- No DOM manipulation capabilities
- Finite Routing, unless you use a 3rd party like ui-router
- app logic and structure expressed in HTML
- No server-side rendering (mostly for speed boost and SEO)
- string-based Dependency Injection
- Ill-Conceived architecture (obsolete constructor functions etc)
- Debugging issues
- Re-defining well established terminology
- Syntactic Sugar
- Execution Contexts
- Unnecessary Complications
- Incompatible with 3rd party libraries, like jQuery etc.
- Sparse documentation with literally no real-world examples
و مواردی از این دست. شاید برای پروژههای کوچک این فریم ورک مناسب باشه اما قطعا برای پروژههای بزرگی که قرار است برای مدتی طولانی توسعه داده بشن و نگهداری بشن اصلا انتخاب درستی نیست. حتی اگر پروژههای بزرگی هم با موفقیت توسط این فریم اجرا شده باشه باز هم ماهیت مساله تغییر نمیکنه.
در حال حاظر بین فریم ورکهای دیگه بهترین انتخاب Ember هست که بسیاری از مشکلات ذکر شده رو نداره و ساختار و معماری قوی و خوبی هم داره. Backbone و Durandal هم فریم ورکهای قوی ای هستند ولی تفاوتهای نسبتا زیادی با Ember دارن.
حائز اهمیت این که، اپلیکیشنهای SPA جوان هستند و فعلا همه جای دنیا در حال آزمایش و بررسی این هستند که چطور میشه چنین پروژه هایی رو اجرا کرد و کدام راه بهترین راه هست، بنابراین تا به استانداردهای ثابتی برسیم راه طولانی ای در پیش داریم. از طرفی بزودی استاندارد جدید جاوا اسکریپت (ECMA6) منتشر میشه، که با انتشارش فریم ورک هایی مثل Ember و Angular رو کاملا به هم خواهد ریخت. مثلا در نسخه جدید آبجکتهای Observable خواهیم داشت. بنابراین متدهای Angular و Ember برای تشخیص تغییرات به کلی بلا استفاده خواهند بود و بازنویسیهای اساسی لازم میشود.
> npm install @angular/animations@latest --save
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @NgModule({ imports: [ //… BrowserAnimationsModule ], })
در اینجا مثال سادهای را مشاهده خواهید کرد که انتقال (transition) المنت li را از حالت active به inactive، با یک انمیشن ساده همراه خواهد کرد. محل تعریف انیمیشنها در Angular، داخل متادیتای component@ و توسط خصوصیت animations میباشد. در ابتدای کار باید توابع مختص انیمیشن را در فایل component مورد نظر خود توسط دستور import به شکل زیر وارد کنیم:
import { trigger, state, style, transition, animate } from '@angular/animations';
import { Component } from '@angular/core'; import { trigger,state,style,transition,animate } from '@angular/animations'; @Component({ selector: 'app-root', template: ` <div style='width:50%; margin:auto'> <ul> <li [@myState]="currentState" style='width:100px; padding:10px; list-style-type: none' (click)="toggleState()"> {{currentState}} </li> </ul> </div> `, styleUrls: ['./app.component.css'], animations: [ trigger('myState', [ state('inactive', style({ backgroundColor: '#eee', transform: 'scale(1)' })), state('active', style({ backgroundColor: '#cfd8dc', transform: 'scale(1.1)' })), transition('inactive => active', animate('100ms ease-in')), transition('active => inactive', animate('100ms ease-out')) ]) ] }) export class AppComponent { currentState: string = 'inactive'; toggleState():void{ this.currentState = this.currentState === 'inactive' ? 'active' : 'inactive'; } }
توضیحات تکمیلی
trigger: جهت تعریف یک انیمیشن، از تابع trigger استفاده میکنیم. این تابع استفاده شدهی در خصوصیت animations، در پارامتر اول خود، یک نام یکتا را دریافت خواهد کرد و در پارامتر بعدی، لیستی از توابع وارد شده مختص انیمیشن را دریافت میکند.
نکته: خصوصیت animations، قابلیت دریافت چندین تابع trigger را برای داشتن چندین انیمیشن مجزا، دارا است.
state: با استفاده از این تابع قادر به تعریف وضعیتهای مختلف خواهیم بود. انیمشن در Angular بر دو منطق وضعیت (state) و گذار (transition) پیاده سازی میشود. به عبارت دیگر انیمیشن در Angular بر روی گذار (transition) بین وضعیتها (states) قابل تعریف هستند. این تابع در پارامتر اول خود یک نام و در پارامتر دوم خود تابع style را دریافت میکند.
style: با استفاده از این تابع قادر به تعریف استایلی برای وضعیت تعریف شده خواهیم بود.
transition: برای ساخت انیمیشن واقعی مورد استفاده قرار میگیرد. این تابع در پارامتر اول خود، مسیر حرکت بین دو حالت (state) را به صورت یک رشته دریافت کرده و در پارامتر دوم خود، تابع animate را دریافت میکند. در این مثال مسیر حرکت به صورت 'inactive => active' تعریف شده است. یعنی هنگام گذار از وضعیت inactive به وضعیت active، تابع animate در پارامتر دوم اجرا خواهد شد.
animate: این تابع دو پارامتر timing و styles را دریافت میکند. timing مقداری از جنس رشته (string) است که میتواند ترکیبی از مدت زمان (duration) با مقدار اختیاری تاخیر(delay) و مقدار easing باشد. به عنوان مثال مقدار کامل زیر را درنظر بگیرید:
'1s 100ms ease-out'
در این اینجا مدت زمان، برابر ۱ ثانیه، تاخیر، ۱۰۰ میلی ثانیه و easing، مقدار ease-out خواهد بود و به معنی اجرای انیمیشن با افکت ease-out و در مدت زمان ۱ ثانیه و با تاخیر در شروع به مدت ۱۰۰ میلی ثانیه میباشد. در صورتیکه به این پارامتر مقداری عددی را ارسال کنیم، عدد به عنوان مدت زمان (duration) و بر مبنای واحد میلی ثانیه در نظر گرفته خواهد شد. تمامی مقادیر زیر برای ارسال به این پارامتر معتبر میباشند:
500 // duration=500ms "1s" // duration=1s "100ms 0.5s" // duration=100ms, delay=0.5s "5s ease" // duration=5s, easing=ease "5s 10ms cubic-bezier(.17,.67,.88,.1)" // duration=5s, delay=10ms, easing=cubic-bezier(.17,067,.88,.1)
پارامتر styles در تابع animate یکی از توابع style یا keyframes میباشد. البته این پارامتر اختیاری است و در قسمت نکات تکمیلی توضیح داده خواهد شد. در مثال بالا از این پارامتر صرف نظر شده است.
برای متصل کردن انیمیشن تعریف شده به المنتهای موجود در صفحه، از خصوصیت [triggerName@] استفاده کنید. trigger تعریف شده در قطعه کد بالا myState نام دارد. بنابراین برای اینکه المنت li در گذار بین حالتها، این انیمیشن را داشته باشد، باید [myState@] را به المنت خود اضافه کنید. همچنین مقدار حالت جاری را باید برای این خصوصیت تامین کرد. این مقدار میتواند یک رشته استاتیک یا یک عبارت محاسبه شده توسط یک تابع یا یک متغیر باشد.
همانطور که در مثال بالا مشاهده میکنید، با استفاده از متغیر currentState، المنت li در ابتدا در حالت inactive قرار دارد. با کلیک اول بر روی المنت، تابع toggleState باعث تغییر وضعیت المنت از وضعیت inactive به وضعیت active خواهد شد (inactive=>active) بنابراین انیمیشن زیر اجرا خواهد شد.
transition('inactive => active', animate('100ms ease-in'))
با کلیک دوباره، المنت از وضعیت active به inactive خواهد رفت (active=>inactive)، بنابراین انیمیشن زیر اجرا میشود.
نکات تکمیلی
transition('inactive => active, active => inactive', animate('100ms ease-out'))
یا به شکل سادهتر:
transition('inactive <=> active', animate('100ms ease-out'))
کاراکتر * جایگزین تمامی حالتهای موجود در برنامه خواهد بود. برای مثال:
'* <= active': بر روی تمامی گذارهای از حالت active به هر حالت دیگر، اعمال خواهد شد.
'active <= *': بر روی تمامی گذارهای از هر حالت به حالت active، اعمال خواهد شد.
'* <= *': بر روی تمامی گذارها اعمال خواهد شد.
همانطور که قبلا ذکر شد، تابع animate در پارامتر دوم خود یک تابع style یا keyframes را دریافت میکند. در صورتیکه بخواهیم در مدت زمان اجرای انیمیشن بر روی المنت، استایلی را نیز همراه کنیم، میتوانیم از تابع style استفاده کنیم. اما این استایل بعد از اتمام انیمیشن بر روی المنت باقی نخواهد ماند؛ چون حالت (state) مقصد برای خود استایل تعریف شدهاست. علاوه بر این، در تابع transition میتوان به شکل زیر یک استایل خطی را نیز تعریف کرد:
transition('inactive => active', [ style({ backgroundColor: '#cfd8dc', transform: 'scale(1.3)' }), animate('80ms ease-in', style({ backgroundColor: '#eee', transform: 'scale(1)' })) ]),
این تعریف استایل در تابع transition در شروع گذار بلافاصله بر روی المنت اعمال خواهد شد و در طول انیمیشن استایل را از دست خواهد داد و به استایل مقصد خواهد رسید.
در اینجا یک مثال بسیار ساده از نحوه پیاده سازی انیمیشن در Angular را مورد برسی قرار دادیم. در بخش بعدی نحوهی پیاده سازی انیمیشنهای پیشرفته که قابلیت اعمال بر روی المنتها را هنگام اضافه شدن به صفحه و ترک صفحه را خواهند داشت، مورد بررسی قرار میدهیم.
ایجاد کامپوننت جدید ReducerButtons
برای توضیح مفاهیم این قسمت، فایل جدید src\components\ReducerButtons.tsx را به همراه محتوای زیر ایجاد میکنیم:
import React, { useReducer } from "react"; const initialState = { rValue: true }; type State = { rValue: boolean; }; type Action = { type: string; }; function reducer(state: State, action: Action) { switch (action.type) { case "one": return { rValue: true }; case "two": return { rValue: false }; default: return state; } } export const ReducerButtons = () => { const [state, dispatch] = useReducer(reducer, initialState); return ( <div> {state?.rValue && <h1>Visible</h1>} <button onClick={() => dispatch({ type: "one" })}>Action One</button> <button onClick={() => dispatch({ type: "two" })}>Action Two</button> </div> ); };
- این کامپوننت دو دکمه را رندر میکند تا توسط آنها بتوان چندین Action مختلف را جهت مدیریت حالت، سبب شد؛ مانند Action One و Two.
- initialState را در این مثال، یک شیء ساده در نظر گرفتهایم که تنها دارای یک مقدار boolean است.
- سپس نیاز به یک تابع ویژه را به نام reducer، داریم که مقدار state جاری و یک action را دریافت میکند. این تابع بر اساس نوع Action ای که به آن میرسد، state جدیدی را بازگشت میدهد و در قسمت رندر آن، با بررسی state?.rValue، سبب نمایش عبارتی خواهیم شد.
- در حین تعریف هوک useReducer، قسمت dispatch آن، تابعی است که یک Action را اجرا میکند. فراخوانی آنرا در رویداد onClick دو دکمهی تعریف شده مشاهده میکنید. این تابع یک شیء را دریافت میکند که type اکشن ارسالی به تابع reducer را مقدار دهی میکند.
توسط useReducer برای ایجاد تغییرات در شیء state کامپوننت جاری، از مفهومی به نام dispatch actions استفاده میشود. action در اینجا به معنای رخدادن چیزی است؛ مانند کلیک بر روی یک دکمه و یا دریافت اطلاعاتی از یک API. در این حالت مقایسهای بین وضعیت قبلی state و وضعیت فعلی آن صورت میگیرد و تغییرات مورد نیاز جهت اعمال به UI، محاسبه خواهند شد. اصلیترین جزء آن، تابعی است به نام Reducer. این تابع، یک تابع خالص است و دو آرگومان را دریافت میکند. تابع Reducer، بر اساس action و یا رخدادی، ابتدا کل state برنامه را دریافت میکند و سپس خروجی آن بر اساس منطق این تابع، یک state جدید خواهد بود. اکنون که این state جدید را داریم، برنامهی React ما میتواند به تغییرات آن گوش فرا داده و بر اساس آن، UI را به روز رسانی کند.
اولین قسمتی را که در حین کار با useReducer توسط TypeScript به آن برخورد خواهیم کرد، نمایش خطاهایی در مورد نوعهای پارامترهای state و action تابع reducer است. در حالت متداول جاوا اسکریپتی آن، این پارامترها، بدون نوع ذکر میشوند که در اینجا به any تفسیر خواهند شد و یک چنین تعاریفی با توجه به strict بودن تنظیمات tsconfig.json برنامه، مجاز نیست. به همین جهت نیاز به تعریف دو type جدید به نامهای State و Action در اینجا وجود دارد تا خطاهای بدون نوع بودن پارامترهای تابع reducer برطرف شوند. نوع Action به همراه حداقل یک خاصیت به نام action رشتهای است و نوع State بر اساس initialState ای که تعریف کردیم، دارای یک خاصیت متناظر boolean است.
نکتهی جالب دومی که در اینجا توسط TypeScript گوشزد میشود، الزام به ذکر حالت default مربوط به switch ای است که در تابع reducer تعریف کردهایم. اگر این حالت را حذف کنیم، بلافاصله خطای زیر را در قسمت تعریف useReducer نمایش میدهد:
عنوان میکند که خروجی تابع reducer، یک state جدید است؛ اما ممکن است از نوع never هم باشد که قابلیت ترجمهی به نوع state را ندارد.
بهبود تعاریف نوعهای useReducer
تا اینجا مهمترین تغییرات تایپاسکریپتی صورت گرفته، تعریف نوعهای پارامترهای تابع reducer است. اکنون فرض کنید میخواهیم، سومین Action را هم به کامپوننت جاری اضافه کنیم:
<button onClick={() => dispatch({ type: "three" })}>Action Three</button>
type Action = { type: "one" | "two" | "three"; };
و یا حتی اگر مقدار action.type ای را در تابع reducer به اشتباه وارد کردیم، باز هم برنامه کامپایل نمیشود:
import React, { useReducer } from "react"; const initialState = { rValue: true }; type State = { rValue: boolean; }; type Action = { type: "one" | "two" | "three"; }; function reducer(state: State, action: Action) { switch (action.type) { case "one": return { rValue: true }; case "two": return { rValue: false }; case "three": return { rValue: false }; } } export const ReducerButtons = () => { const [state, dispatch] = useReducer(reducer, initialState); return ( <div> {state?.rValue && <h1>Visible</h1>} <button onClick={() => dispatch({ type: "one" })}>Action One</button> <button onClick={() => dispatch({ type: "two" })}>Action Two</button> <button onClick={() => dispatch({ type: "three" })}>Action Three</button> </div> ); };
با توجه به تجزیه و تحلیل انجام شده تمامی اشیا از کلاس پایه به نام Shape ارث بری دارند حال به توضیح کدهای این کلاس میپردازیم. (به دلیل اینکه توضیحات این کلاس در دو پست نوشته خواهد شد برای این کلاسها از partial class استفاده شده است)
using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Net; namespace PWS.ObjectOrientedPaint.Models { /// <summary> /// Shape (Base Class) /// </summary> public abstract partial class Shape { #region Fields (1) private Brush _backgroundBrush; #endregion Fields #region Properties (16) /// <summary> /// Gets or sets the brush. /// </summary> /// <value> /// The brush. /// </value> public Brush BackgroundBrush { get { return _backgroundBrush ?? (_backgroundBrush = new SolidBrush(BackgroundColor)); } private set { _backgroundBrush = value ?? new SolidBrush(BackgroundColor); } } /// <summary> /// Gets or sets the color of the background. /// </summary> /// <value> /// The color of the background. /// </value> public Color BackgroundColor { get; set; } /// <summary> /// Gets or sets the end point. /// </summary> /// <value> /// The end point. /// </value> public PointF EndPoint { get; set; } /// <summary> /// Gets or sets the color of the fore. /// </summary> /// <value> /// The color of the fore. /// </value> public Color ForeColor { get; set; } /// <summary> /// Gets or sets the height. /// </summary> /// <value> /// The height. /// </value> public float Height { get { return Math.Abs(StartPoint.Y - EndPoint.Y); } set { if (value > 0) EndPoint = new PointF(EndPoint.X, StartPoint.Y + value); } } /// <summary> /// Gets or sets a value indicating whether this instance is fill. /// </summary> /// <value> /// <c>true</c> if this instance is fill; otherwise, <c>false</c>. /// </value> public bool IsFill { get; set; } /// <summary> /// Gets or sets a value indicating whether this instance is selected. /// </summary> /// <value> /// <c>true</c> if this instance is selected; otherwise, <c>false</c>. /// </value> public bool IsSelected { get; set; } /// <summary> /// Gets or sets my pen. /// </summary> /// <value> /// My pen. /// </value> public Pen Pen { get { return new Pen(ForeColor, Thickness); } } /// <summary> /// Gets or sets the type of the shape. /// </summary> /// <value> /// The type of the shape. /// </value> public ShapeType ShapeType { get; protected set; } /// <summary> /// Gets the size. /// </summary> /// <value> /// The size. /// </value> public SizeF Size { get { return new SizeF(Width, Height); } } /// <summary> /// Gets or sets the start point. /// </summary> /// <value> /// The start point. /// </value> public PointF StartPoint { get; set; } /// <summary> /// Gets or sets the thickness. /// </summary> /// <value> /// The thickness. /// </value> public byte Thickness { get; set; } /// <summary> /// Gets or sets the width. /// </summary> /// <value> /// The width. /// </value> public float Width { get { return Math.Abs(StartPoint.X - EndPoint.X); } set { if (value > 0) EndPoint = new PointF(StartPoint.X + value, EndPoint.Y); } } /// <summary> /// Gets or sets the X. /// </summary> /// <value> /// The X. /// </value> public float X { get { return StartPoint.X; } set { if (value > 0) StartPoint = new PointF(value, StartPoint.Y); } } /// <summary> /// Gets or sets the Y. /// </summary> /// <value> /// The Y. /// </value> public float Y { get { return StartPoint.Y; } set { if (value > 0) StartPoint = new PointF(StartPoint.X, value); } } /// <summary> /// Gets or sets the index of the Z. /// </summary> /// <value> /// The index of the Z. /// </value> public int Zindex { get; set; } #endregion Properties } }
خصوصیات:
- BackgroundColor: در صورتی که شی مورد نظر به صورت توپررسم شود، این خاصیت رنگ پس زمینه شی را مشخص میکند.
- BackgroundBrush: خاصیتی است که با توجه به خاصیت BackgroundColor یک الگوی پر کردن زمینه شی میسازد.
- StartPoint: نقطه شروع شی را در خود نگهداری میکند.
- EndPoint: نقطه انتهای شی را در خود نگهداری میکند. (قبلا گفته شد که هر شی را در صورتی که در یک مستطیل فرض کنیم یک نقطه شروع و یک نقطه پایان دارد)
- ForeColor: رنگ قلم ترسیم شی مورد نظر را تعیین میکند.
- Height: ارتفاع شی مورد نظر را تعیین میکند ( این خصوصیت اختلاف عمودی StartPoint.Y و EndPoint.Y را محاسبه میکند و در زمان مقدار دهی EndPoint جدیدی ایجاد میکند).
- Width: عرض شی مورد نظر را تعیین میکند ( این خصوصیت اختلاف افقیStartPoint.X و EndPoint.X را محاسبه میکند و در زمان مقدار دهی EndPoint جدیدی ایجاد میکند).
- IsFill: این خصوصیت تعیین کننده توپر و یا توخالی بودن شی است.
- IsSelected: این خاصیت تعیین میکند که آیا شی انتخاب شده است یا خیر (در زمان انتخاب شی چهار مربع کوچک روی شی رسم میشود).
- Pen: قلم خط ترسیم شی را مشخص میکند. (قلم با ضخامت دلخواه)
- ShapeType: این خصوصیت نوع شی را مشخص میکند (این خاصیت بیشتر برای زمان پیش نمایش ترسیم شی در زمان اجراست البته به نظر خودم اضافه هست اما راه بهتری به ذهنم نرسید)
- Size: با استفاده از خصوصیات Height و Width ایجاد شده و تعیین کننده Size شی است.
- Thickness: ضخامت خط ترسیمی شی را مشخص میکند، این خاصیت در خصوصیت Pen استفاده شده است.
- X: مقدار افقی نقطه شروع شی را تعیین میکند در واقع StartPoint.X را برمیگرداند (این خاصیت اضافی بوده و جهت راحتی کار استفاده شده میتوان آن را ننوشت).
- Y: مقدار عمودی نقطه شروع شی را تعیین میکند در واقع StartPoint.Y را برمیگرداند (این خاصیت اضافی بوده و جهت راحتی کار استفاده شده میتوان آن را ننوشت).
- Zindex: در زمان ترسیم اشیا ممکن است اشیا روی هم ترسیم شوند، در واقع Zindex تعیین کننده عمق شی روی بوم گرافیکی است.
در پست بعدی به توضیح متدهای این کلاس میپردازیم.
آموزش Prism #1
من از Prism به عنوان بهترین فریم ورک نام نبردم بلکه از عنوان قویترین فریم ورک استفاده کردم
"میتونیم Prism رو به عنوان قویترین فریم ورک برای پیاده سازی پروژهای بزرگ و قوی و ماژولار با تکنولوژی WPF یا Silverlight بنامیم. " که لزوما به معنی بهترین نیست.
MVVM Light در حال حاضر به عنوان محبوبترین فریم ورک برای MVVM است که این محبوبیت بیشتر به خاطر راحتی کار با اون هست.
معادل Messaging در MVVM Light در Prism شما EventAggregatorها رو در اختیار دارید.
Prism به صورت توکار از dependency Injection استفاده میکنه و دو فریم ورک هم به شما پیشنهاد میده یکی MEF و دیگری UnityContainer(مزیت).
Prism به صورت توکار از Composite UI هم پشتیبانی میکند. به تصویر زیر دقت کنید:
به راحتی میتونید با استفاده از RegionManager موجود در Prism نواحی هر صفحه رو تقسیم بندی کنید و هر ناحیه هم میتونه توسط یک ماژول لود شود. برای طراحی و مدیریت صفحات در MVVM Light باید خودتون دست به کار بشید.
یادگیری و استفاده از قابلیتهای MVVM Light در حد دو یا سه روز زمان میبرد در حالی که برای یادگیری قابلیتهای Prism یک کتاب نوشته شده است(^)
*در پایان دوباره تاکید میکنم که اگر نیازی به تولید و توسعه پروژه به صورت ماژولار رو ندارید بهتره که اصلا به Prism فکر نکنید.