اشتراکها
froala/wysiwyg-editor 1.2.6 منتشر شد
اشتراکها
AutoMapper 3.3 منتشر شد
پس از ایجاد یک Solution جدید توسط قالب WPF Framework، هشت پروژه به صورت خودکار اضافه خواهند شد:
1) پروژه ریشه که بسته به نامی که در ابتدای کار انتخاب میکنید، تغییر نام خواهد یافت.
برای مثال اگر نام وارد شده در ابتدای کار MyWpfFramework باشد، این پروژه ریشه نیز، MyWpfFramework نام خواهد داشت. از آن صرفا جهت افزودن Viewهای برنامه استفاده میکنیم. کلیه Viewها در پوشه View قرار خواهند گرفت و با توجه به ساختار خاصی که در اینجا انتخاب شده، این Viewها باید از نوع Page انتخاب شوند تا با سیستم راهبری فریم ورک هماهنگ کار کنند.
در داخل پوشه Views، هر بخش از برنامه را میتوان داخل یک زیر پوشه قرار داد. برای مثال قسمت Login سیستم، دارای سه صفحه ورود، نمایش پیام خوش آمد و نمایش صفحه عدم دسترسی است.
متناظر با هر Page اضافه شده، در پروژه MyWpfFramework.Infrastructure یک ViewModel در صورت نیاز اضافه خواهد شد. قرار داد ما در اینجا ترکیب نام View به علاوه کلمه ViewModel است. برای مثال اگر نام View اضافه شده به پروژه ریشه برنامه، LoginPage است، نام ViewModel متناظر با آن باید LoginPageViewModel باشد تا به صورت خودکار توسط برنامه ردیابی و وهله سازی گردد.
این پروژه از کتابخانه MahApps.Metro استفاده میکند و اگر به فایل MainWindow.xaml.cs آن مراجعه کنید، ارث بری پنجره اصلی برنامه را از کلاس MetroWindow مشاهده خواهید نمود. این فایلها نیازی به تغییر خاصی نداشته و به همین نحو در این قالب قابل استفاده هستند.
و در پوشه Resources آن یک سری قلم و آیکون را میتوانید مشاهده نمائید.
2) پروژه MyWpfFramework.Common
در این پروژه کلاسهایی قرار میگیرند که قابلیت استفاده در انواع و اقسام پروژههای WPF را دارند و الزاما وابسته به پروژه جاری نیستند. یک سری کلاسهای کمکی در این پروژه Common قرار گرفتهاند و قسمتهای مختلف سیستم را تغذیه میکنند؛ مانند خواندن اطلاعات از فایل کانفیگ، هش کردن کلمه عبور، یک سری متد عمومی برای کار با EF، کلاسهای عمومی مورد نیاز در حین استفاده از الگوی MVVM، اعتبارسنجی و امثال آن.
در این پروژه از کلاس PageAuthorizationAttribute آن جهت مشخص سازی وضعیت دسترسی به صفحات تعریف شده در پروژه ریشه استفاده خواهد شد.
نمونهای از آنرا برای مثال با مراجعه به سورس صفحه About.xaml.cs میتوانید مشاهده کنید که در آن AuthorizationType.AllowAnonymous تنظیم شده و به این ترتیب تمام کاربران اعتبارسنجی نشده میتوانند این صفحه را مشاهده کنند.
همچنین در این پروژه کلاس BaseViewModel قرار دارد که جهت مشخص سازی کلیه کلاسهای ViewModel برنامه باید مورد استفاده قرار گیرد. سیستم طراحی شده، به کمک این کلاس پایه است که میتواند به صورت خودکار ViewModelهای متناظر با Viewها را یافته و وهله سازی کند (به همراه تمام وابستگیهای تزریق شده به آنها).
به علاوه کلاس DataErrorInfoBase آن برای یکپارچه سازی اعتبارسنجی با EF طراحی شده است. اگر به کلاس BaseEntity.cs مراجعه کنید که در پروژه MyWpfFramework.DomainClasses قرار دارد، نحوه استفاده آنرا ملاحظه خواهید نمود. به این ترتیب حجم بالایی از کدهای تکرای، کپسوله شده و قابلیت استفاده مجدد را پیدا میکنند.
قسمتهای دیگر پروژه Common، برای ثبت وقایع برنامه مورد استفاده قرار میگیرند. استفاده از آنها را در فایل App.xaml.cs پروژه ریشه برنامه ملاحظه میکنید و نیاز به تنظیم خاص دیگری در اینجا وجود ندارد.
3) پروژه MyWpfFramework.DataLayer
کار تنظیمات EF در اینجا انجام میشود (و قسمت عمدهای از آن انجام شده است). تنها کاری که در آینده برای استفاده از آن نیاز است انجام شود، مراجعه به کلاس MyWpfFrameworkContext.cs و افزودن DbSetهای لازم است. همچنین اگر نیاز به تعریف نگاشتهای اضافهتری وجود داشت، میتوان از پوشه Mappings آن استفاده کرد.
در این پروژه الگوی واحد کار پیاده سازی شده است و همچنین سعی شده تمام کلاسهای آن دارای کامنتهای کافی جهت توضیح قسمتهای مختلف باشند.
کلاس MyDbContextBase به اندازه کافی غنی سازی شدهاست، تا در وقت شما، در زمینه تنظیم مباحثی مانند اعتبارسنجی و نمایش پیغامهای لازم به کاربر، یک دست سازی ی و ک ورودی در برنامه و بسیاری از نکات ریز دیگر صرفه جویی شود.
در اینجا از خاصیت ContextHasChanges جهت بررسی وضعیت Context جاری و نمایش پیغامی به کاربر در مورد اینکه آیا مایل هستید تغییرات را ذخیره کنید یا خیر استفاده میشود.
در متد auditFields آن یک سری خاصیت کلاس BaseEntity که پایه تمامی کلاسهای Domain model برنامه خواهد بود به صورت خودکار مقدار دهی میشوند. مثلا این رکورد را چه کسی ثبت کرده یا چه کسی ویرایش و در چه زمانی. به این ترتیب دیگر نیازی نیست تا در برنامه نگران تنظیم و مقدار دهی آنها بود.
کلاس MyWpfFrameworkMigrations به حالت AutomaticMigrationsEnabled تنظیم شده است و ... برای یک برنامه دسکتاپ WPF کافی و مطلوب است و ما را از عذاب به روز رسانی دستی ساختار بانک اطلاعاتی برنامه با تغییرات مدلها، رها خواهد ساخت. عموما برنامههای دسکتاپ پس از طراحی، آنچنان تغییرات گستردهای ندارند و انتخاب حالت Automatic در اینجا میتواند کار توزیع آنرا نیز بسیار ساده کند. از این جهت که بانک اطلاعاتی انتخابی از نوع SQL Server CE نیز عمدا این هدف را دنبال میکند: عدم نیاز به نگهداری و وارد شدن به جزئیات نصب یک بانک اطلاعاتی بسیار پیشرفته مانند نگارشهای کامل SQL Server. هرچند زمانیکه با EF کار میکنیم، سوئیچ به بانکهای اطلاعاتی صرفا با تغییر رشته اتصالی فایل app.config برنامه اصلی و مشخص سازی پروایدر مناسب قابل انجام خواهد بود.
در فایل MyWpfFrameworkMigrations، توسط متد addRolesAndAdmin کاربر مدیر سیستم در آغاز کار ساخت بانک اطلاعاتی به صورت خودکار افزوده خواهد شد.
4) پروژه MyWpfFramework.DomainClasses
کلیه کلاسهای متناظر با جداول بانک اطلاعاتی در پروژه MyWpfFramework.DomainClasses قرار خواهند گرفت. نکته مهمی که در اینجا باید رعایت شود، مزین کردن این کلاسها به کلاس پایه BaseEntity میباشد که نمونهای از آنرا در کلاس User پروژه میتوانید ملاحظه کنید.
BaseEntity چند کار را با هم انجام میدهد:
- اعمال خودکار DataErrorInfoBase جهت یکپارچه سازی سیستم اعتبارسنجی EF با WPF (برای مثال به این ترتیب خطاهای ذکر شده در ویژگیهای خواص کلاسها توسط WPF نیز خوانده خواهند شد)
- اعمال ImplementPropertyChanged به کلاسهای دومین برنامه. به این ترتیب برنامه کمکی Fody که کار Aspect oriented programming را انجام میدهد، اسمبلی برنامه را ویرایش کرده و متدها و تغییرات لازم جهت پیاده سازی INotifyPropertyChanged را اضافه میکند. به این ترتیب به کلاسهای دومین بسیار تمیزی خواهیم رسید با حداقل نیاز به تغییرات و نگهداری ثانویه.
- فراهم آوردن فیلدهای مورد نیاز جهت بازرسی سیستم؛ مانند اینکه چه کسی یک رکورد را ثبت کرده یا ویرایش و در چه زمانی
نقشهای سیستم در کلاس SystemRole تعریف میشوند. به ازای هر نقش جدیدی که نیاز بود، تنها کافی است یک خاصیت bool را در اینجا اضافه کنید. سپس نام این خاصیت در ویژگی PageAuthorizationAttribute به صورت خودکار قابل استفاده خواهد بود. برای مثال به پروژه ریشه مراجعه و به فایل AddNewUser.xaml.cs دقت کنید؛ چنین تعریفی را در بالای کلاس مرتبط مشاهده خواهید کرد:
در اینجا AuthorizationType سه حالت را میتواند داشته باشد:
اگر حالت ApplyRequiredRoles را انتخاب کردید، در پارامتر اختیاری دوم ویژگی PageAuthorization نیاز است نام یک یا چند خاصیت کلاس SystemRole را قید کنید. بدیهی است کاربر متناظر نیز باید دارای این نقشها باشد تا بتواند به این صفحه دسترسی پیدا کند، یا خیر.
5) پروژه MyWpfFramework.Models
در پروژه MyWpfFramework.Models کلیه Modelهای مورد استفاده در UI که الزاما قرار نیست در بانک اطلاعاتی قرارگیرند، تعریف خواهند شد. برای نمونه مدل صفحه لاگین در آن قرار دارد و ذکر دو نکته در آن حائز اهمیت است:
- ویژگی ImplementPropertyChanged کار پیاده سازی INotifyPropertyChanged را به صورت خودکار سبب خواهد شد.
- کلاس پایه DataErrorInfoBase سبب میشود تا مثلا در اینجا اگر از ویژگی Required استفاده کردید، اطلاعات آن توسط برنامه خوانده شود و با WPF یکپارچه گردد.
6) پروژه MyWpfFramework.Infrastructure.csproj
در پروژه MyWpfFramework.Infrastructure.csproj تعاریف ViewModelهای برنامه اضافه خواهند شد.
این پروژه دارای یک سری کلاس پایه است که تنظیمات IoC برنامه را انجام میدهد. برای مثال FrameFactory.cs آن یک کنترل Frame جدید را ایجاد کرده است که کار تزریق وابستگیها را به صورت خودکار انجام خواهد داد. فایل IocConfig آن جایی است که کار سیم کشی کلاسهای لایه سرویس و اینترفیسهای متناظر با آنها انجام میشود. البته پیش فرضهای آن را اگر رعایت کنید، نیازی به تغییری در آن نخواهید داشت. برای مثال در آن scan.TheCallingAssembly قید شده است. در این حالت اگر نام کلاس لایه سرویس شما Test و نام اینترفیس متناظر با آن ITest باشد، به صورت خودکار به هم متصل خواهند شد.
همانطور که پیشتر نیز عنوان شد، در پوشه ViewModels آن، به ازای هر View یک ViewModel خواهیم داشت که نام آن مطابق قرار داد، نام View مدنظر به همراه کلمه ViewModel باید درنظر گرفته شود تا توسط برنامه شناخته شده و مورد استفاده قرار گیرد. همچنین هر ViewModel نیز باید دارای کلاس پایه BaseViewModel باشد تا توسط IoC Container برنامه جهت تزریق وابستگیهای خودکار در سازندههای کلاسها شناسایی شده و وهله سازی گردد.
7) پروژه MyWpfFramework.ServiceLayer
کلیه کلاسهای لایه سرویس که منطق تجاری برنامه را پیاده سازی میکنند (خصوصا توسط EF) در این لایه قرار خواهند گرفت. در اینجا دو نمونه سرویس کاربران و سرویس عمومی AppContextService را ملاحظه میکنید.
سرویس AppContextService قلب سیستم اعتبارسنجی سیستم است و در IocConfig برنامه به صورت سینگلتون تعریف شده است. چون در برنامههای دسکتاپ در هر لحظه فقط یک نفر وارد سیستم میشود و نیاز است تا پایان طول عمر برنامه، اطلاعات لاگین و نقشهای او را در حافظه نگه داری کرد.
8) پروژه MyWpfFramework.Tests
یک پروژه خالی Class library هم در اینجا جهت تعریف آزمونهای واحد سیستم درنظر گرفته شده است.
1) پروژه ریشه که بسته به نامی که در ابتدای کار انتخاب میکنید، تغییر نام خواهد یافت.
برای مثال اگر نام وارد شده در ابتدای کار MyWpfFramework باشد، این پروژه ریشه نیز، MyWpfFramework نام خواهد داشت. از آن صرفا جهت افزودن Viewهای برنامه استفاده میکنیم. کلیه Viewها در پوشه View قرار خواهند گرفت و با توجه به ساختار خاصی که در اینجا انتخاب شده، این Viewها باید از نوع Page انتخاب شوند تا با سیستم راهبری فریم ورک هماهنگ کار کنند.
در داخل پوشه Views، هر بخش از برنامه را میتوان داخل یک زیر پوشه قرار داد. برای مثال قسمت Login سیستم، دارای سه صفحه ورود، نمایش پیام خوش آمد و نمایش صفحه عدم دسترسی است.
متناظر با هر Page اضافه شده، در پروژه MyWpfFramework.Infrastructure یک ViewModel در صورت نیاز اضافه خواهد شد. قرار داد ما در اینجا ترکیب نام View به علاوه کلمه ViewModel است. برای مثال اگر نام View اضافه شده به پروژه ریشه برنامه، LoginPage است، نام ViewModel متناظر با آن باید LoginPageViewModel باشد تا به صورت خودکار توسط برنامه ردیابی و وهله سازی گردد.
این پروژه از کتابخانه MahApps.Metro استفاده میکند و اگر به فایل MainWindow.xaml.cs آن مراجعه کنید، ارث بری پنجره اصلی برنامه را از کلاس MetroWindow مشاهده خواهید نمود. این فایلها نیازی به تغییر خاصی نداشته و به همین نحو در این قالب قابل استفاده هستند.
و در پوشه Resources آن یک سری قلم و آیکون را میتوانید مشاهده نمائید.
2) پروژه MyWpfFramework.Common
در این پروژه کلاسهایی قرار میگیرند که قابلیت استفاده در انواع و اقسام پروژههای WPF را دارند و الزاما وابسته به پروژه جاری نیستند. یک سری کلاسهای کمکی در این پروژه Common قرار گرفتهاند و قسمتهای مختلف سیستم را تغذیه میکنند؛ مانند خواندن اطلاعات از فایل کانفیگ، هش کردن کلمه عبور، یک سری متد عمومی برای کار با EF، کلاسهای عمومی مورد نیاز در حین استفاده از الگوی MVVM، اعتبارسنجی و امثال آن.
در این پروژه از کلاس PageAuthorizationAttribute آن جهت مشخص سازی وضعیت دسترسی به صفحات تعریف شده در پروژه ریشه استفاده خواهد شد.
نمونهای از آنرا برای مثال با مراجعه به سورس صفحه About.xaml.cs میتوانید مشاهده کنید که در آن AuthorizationType.AllowAnonymous تنظیم شده و به این ترتیب تمام کاربران اعتبارسنجی نشده میتوانند این صفحه را مشاهده کنند.
همچنین در این پروژه کلاس BaseViewModel قرار دارد که جهت مشخص سازی کلیه کلاسهای ViewModel برنامه باید مورد استفاده قرار گیرد. سیستم طراحی شده، به کمک این کلاس پایه است که میتواند به صورت خودکار ViewModelهای متناظر با Viewها را یافته و وهله سازی کند (به همراه تمام وابستگیهای تزریق شده به آنها).
به علاوه کلاس DataErrorInfoBase آن برای یکپارچه سازی اعتبارسنجی با EF طراحی شده است. اگر به کلاس BaseEntity.cs مراجعه کنید که در پروژه MyWpfFramework.DomainClasses قرار دارد، نحوه استفاده آنرا ملاحظه خواهید نمود. به این ترتیب حجم بالایی از کدهای تکرای، کپسوله شده و قابلیت استفاده مجدد را پیدا میکنند.
قسمتهای دیگر پروژه Common، برای ثبت وقایع برنامه مورد استفاده قرار میگیرند. استفاده از آنها را در فایل App.xaml.cs پروژه ریشه برنامه ملاحظه میکنید و نیاز به تنظیم خاص دیگری در اینجا وجود ندارد.
3) پروژه MyWpfFramework.DataLayer
کار تنظیمات EF در اینجا انجام میشود (و قسمت عمدهای از آن انجام شده است). تنها کاری که در آینده برای استفاده از آن نیاز است انجام شود، مراجعه به کلاس MyWpfFrameworkContext.cs و افزودن DbSetهای لازم است. همچنین اگر نیاز به تعریف نگاشتهای اضافهتری وجود داشت، میتوان از پوشه Mappings آن استفاده کرد.
در این پروژه الگوی واحد کار پیاده سازی شده است و همچنین سعی شده تمام کلاسهای آن دارای کامنتهای کافی جهت توضیح قسمتهای مختلف باشند.
کلاس MyDbContextBase به اندازه کافی غنی سازی شدهاست، تا در وقت شما، در زمینه تنظیم مباحثی مانند اعتبارسنجی و نمایش پیغامهای لازم به کاربر، یک دست سازی ی و ک ورودی در برنامه و بسیاری از نکات ریز دیگر صرفه جویی شود.
در اینجا از خاصیت ContextHasChanges جهت بررسی وضعیت Context جاری و نمایش پیغامی به کاربر در مورد اینکه آیا مایل هستید تغییرات را ذخیره کنید یا خیر استفاده میشود.
در متد auditFields آن یک سری خاصیت کلاس BaseEntity که پایه تمامی کلاسهای Domain model برنامه خواهد بود به صورت خودکار مقدار دهی میشوند. مثلا این رکورد را چه کسی ثبت کرده یا چه کسی ویرایش و در چه زمانی. به این ترتیب دیگر نیازی نیست تا در برنامه نگران تنظیم و مقدار دهی آنها بود.
کلاس MyWpfFrameworkMigrations به حالت AutomaticMigrationsEnabled تنظیم شده است و ... برای یک برنامه دسکتاپ WPF کافی و مطلوب است و ما را از عذاب به روز رسانی دستی ساختار بانک اطلاعاتی برنامه با تغییرات مدلها، رها خواهد ساخت. عموما برنامههای دسکتاپ پس از طراحی، آنچنان تغییرات گستردهای ندارند و انتخاب حالت Automatic در اینجا میتواند کار توزیع آنرا نیز بسیار ساده کند. از این جهت که بانک اطلاعاتی انتخابی از نوع SQL Server CE نیز عمدا این هدف را دنبال میکند: عدم نیاز به نگهداری و وارد شدن به جزئیات نصب یک بانک اطلاعاتی بسیار پیشرفته مانند نگارشهای کامل SQL Server. هرچند زمانیکه با EF کار میکنیم، سوئیچ به بانکهای اطلاعاتی صرفا با تغییر رشته اتصالی فایل app.config برنامه اصلی و مشخص سازی پروایدر مناسب قابل انجام خواهد بود.
در فایل MyWpfFrameworkMigrations، توسط متد addRolesAndAdmin کاربر مدیر سیستم در آغاز کار ساخت بانک اطلاعاتی به صورت خودکار افزوده خواهد شد.
4) پروژه MyWpfFramework.DomainClasses
کلیه کلاسهای متناظر با جداول بانک اطلاعاتی در پروژه MyWpfFramework.DomainClasses قرار خواهند گرفت. نکته مهمی که در اینجا باید رعایت شود، مزین کردن این کلاسها به کلاس پایه BaseEntity میباشد که نمونهای از آنرا در کلاس User پروژه میتوانید ملاحظه کنید.
BaseEntity چند کار را با هم انجام میدهد:
- اعمال خودکار DataErrorInfoBase جهت یکپارچه سازی سیستم اعتبارسنجی EF با WPF (برای مثال به این ترتیب خطاهای ذکر شده در ویژگیهای خواص کلاسها توسط WPF نیز خوانده خواهند شد)
- اعمال ImplementPropertyChanged به کلاسهای دومین برنامه. به این ترتیب برنامه کمکی Fody که کار Aspect oriented programming را انجام میدهد، اسمبلی برنامه را ویرایش کرده و متدها و تغییرات لازم جهت پیاده سازی INotifyPropertyChanged را اضافه میکند. به این ترتیب به کلاسهای دومین بسیار تمیزی خواهیم رسید با حداقل نیاز به تغییرات و نگهداری ثانویه.
- فراهم آوردن فیلدهای مورد نیاز جهت بازرسی سیستم؛ مانند اینکه چه کسی یک رکورد را ثبت کرده یا ویرایش و در چه زمانی
نقشهای سیستم در کلاس SystemRole تعریف میشوند. به ازای هر نقش جدیدی که نیاز بود، تنها کافی است یک خاصیت bool را در اینجا اضافه کنید. سپس نام این خاصیت در ویژگی PageAuthorizationAttribute به صورت خودکار قابل استفاده خواهد بود. برای مثال به پروژه ریشه مراجعه و به فایل AddNewUser.xaml.cs دقت کنید؛ چنین تعریفی را در بالای کلاس مرتبط مشاهده خواهید کرد:
[PageAuthorization(AuthorizationType.ApplyRequiredRoles, "IsAdmin, CanAddNewUser")]
/// <summary> /// وضعیت اعتبار سنجی صفحه را مشخص میکند /// </summary> public enum AuthorizationType { /// <summary> /// همه میتوانند بدون اعتبار سنجی، دسترسی به این صفحات داشته باشند /// </summary> AllowAnonymous, /// <summary> /// کاربران وارد شده به سیستم بدون محدودیت به این صفحات دسترسی خواهند داشت /// </summary> FreeForAuthenticatedUsers, /// <summary> /// بر اساس نام نقشهایی که مشخص میشوند تصمیم گیری خواهد شد /// </summary> ApplyRequiredRoles }
5) پروژه MyWpfFramework.Models
در پروژه MyWpfFramework.Models کلیه Modelهای مورد استفاده در UI که الزاما قرار نیست در بانک اطلاعاتی قرارگیرند، تعریف خواهند شد. برای نمونه مدل صفحه لاگین در آن قرار دارد و ذکر دو نکته در آن حائز اهمیت است:
[ImplementPropertyChanged] // AOP public class LoginPageModel : DataErrorInfoBase
- کلاس پایه DataErrorInfoBase سبب میشود تا مثلا در اینجا اگر از ویژگی Required استفاده کردید، اطلاعات آن توسط برنامه خوانده شود و با WPF یکپارچه گردد.
6) پروژه MyWpfFramework.Infrastructure.csproj
در پروژه MyWpfFramework.Infrastructure.csproj تعاریف ViewModelهای برنامه اضافه خواهند شد.
این پروژه دارای یک سری کلاس پایه است که تنظیمات IoC برنامه را انجام میدهد. برای مثال FrameFactory.cs آن یک کنترل Frame جدید را ایجاد کرده است که کار تزریق وابستگیها را به صورت خودکار انجام خواهد داد. فایل IocConfig آن جایی است که کار سیم کشی کلاسهای لایه سرویس و اینترفیسهای متناظر با آنها انجام میشود. البته پیش فرضهای آن را اگر رعایت کنید، نیازی به تغییری در آن نخواهید داشت. برای مثال در آن scan.TheCallingAssembly قید شده است. در این حالت اگر نام کلاس لایه سرویس شما Test و نام اینترفیس متناظر با آن ITest باشد، به صورت خودکار به هم متصل خواهند شد.
همانطور که پیشتر نیز عنوان شد، در پوشه ViewModels آن، به ازای هر View یک ViewModel خواهیم داشت که نام آن مطابق قرار داد، نام View مدنظر به همراه کلمه ViewModel باید درنظر گرفته شود تا توسط برنامه شناخته شده و مورد استفاده قرار گیرد. همچنین هر ViewModel نیز باید دارای کلاس پایه BaseViewModel باشد تا توسط IoC Container برنامه جهت تزریق وابستگیهای خودکار در سازندههای کلاسها شناسایی شده و وهله سازی گردد.
7) پروژه MyWpfFramework.ServiceLayer
کلیه کلاسهای لایه سرویس که منطق تجاری برنامه را پیاده سازی میکنند (خصوصا توسط EF) در این لایه قرار خواهند گرفت. در اینجا دو نمونه سرویس کاربران و سرویس عمومی AppContextService را ملاحظه میکنید.
سرویس AppContextService قلب سیستم اعتبارسنجی سیستم است و در IocConfig برنامه به صورت سینگلتون تعریف شده است. چون در برنامههای دسکتاپ در هر لحظه فقط یک نفر وارد سیستم میشود و نیاز است تا پایان طول عمر برنامه، اطلاعات لاگین و نقشهای او را در حافظه نگه داری کرد.
8) پروژه MyWpfFramework.Tests
یک پروژه خالی Class library هم در اینجا جهت تعریف آزمونهای واحد سیستم درنظر گرفته شده است.
سلام
چطور میشه این پارامتر رو در wpf مقدار دهی کرد؟
من از مشکل رو در wpf دارم و در بعضی از فرمهای برنامه cpu usage بالا میره.
نظرات مطالب
مروری سریع بر اصول مقدماتی MVVM
پیشنیاز MVVM مباحث Binding در Silverlight و WPF است. یک کتاب فارسی رو در این زمینه در اینجا میتونید دریافت کنید: (^)
مرتبط با سیلورلایت است اما ... مباحث کلی آن با WPF تفاوتی ندارد و اصول یکی است.
مرتبط با سیلورلایت است اما ... مباحث کلی آن با WPF تفاوتی ندارد و اصول یکی است.
نظرات مطالب
مروری بر کاربرد DoEvents
در wpf هم مشکل freez شدن UI وجود دارد با این تفاوت که استفاده از DoEvents امکان پذیر نیست و راه حلهای مشابه هم چندان چنگی به دل نمیزنند. آیا راهی اصولی برای wpf وجود دارد؟
مطالب
کتابخانه GMap.Net
نقشه گوگل در حال حاضر یکی از محبوبترین و کاملترین نقشههای جهان است و امکانات خوبی هم دارد. در این راستا بسیاری از مردم سعی در استفاده از این نقشهها و امکانات آنها دارند. به همین دلیل گوگل در بستههای api خود نیز این مورد را گنجانده است. ولی استفاده از این api مستلزم نوشتن کدهای جاوا اسکرپیتی و شناخت توابع و ثابتهای api گوگل است. اما در هر صورت این مستندات مورد مطالعه قرار میگیرند.
سال گذشته بود که به بررسی کتابخانههای موجود برای دات نت که به ساخت نقشههای گوگل (+ ) میپردازند پرداختم. ولی مشکلی که وجود داشت، همه آنها در نهایت یک تصویر jpeg تحویل میدادند. ولی من میخواستم نقشهی من زنده و واکنشگرا باشد تا کاربر بتواند روی آن حرکت کند، زوم کند، مارکرها را جابجا کند و امکانات دیگری که در این نقشه در دسترس است را داشته باشد. برای همین شروع به ساخت یک class library کردم تا کاربر بتواند در محیط سی شارپ، تنظیمات را با اسامی قابل شناخت و یک intellisense قدرتمند بنویسد و در نهایت بر اساس اطلاعات کاربر، این کدها به صورت جاوا اسکریپت تولید شود. میتوانید سورس نهایی کتابخانهی GMap.Net را در گیت هاب، به همراه یک پروژهی نمونه ببینید.
پروژهی وابسته این کتابخانه، MS Ajax Minifier جهت کم حجم کردن کدهای جاوا اسکریپت است. در مورد این کتابخانه در سایت جاری بحث شده است.
برای نصب این کتابخانه میتوانید از طریق دستور زیر در Nuget عمل کنید:
در این کتابخانه مواردی که مورد توجه قرار گرفته است، تنظیمات نقشه و بعد از آن overlayها هستند که شامل مارکرها و اشکال مختلف میباشند. این اشکال شامل رسم مستطیل بر روی نقشه، چند ضلعیها و ... نیز میشوند.
برای شروع نیاز است که یک نمونه از کلاس GoogleMapApi را ایجاد کنید. بعد از آن با استفاده از خصوصیت SetLocation، مختصات مرکز نقشه را تنظیم نمایید. سپس با استفاده از خصوصیات دیگر نیز میتوانید نقشه را تنظیم نمایید. تعدادی از این خصوصیات مثل SetZoomVisibility هستند که با استفاده از آن میتوانید تنظیمات زوم را روی نقشه پیاده سازی کنید. البته فعال کردن این گزینه به تنهایی کافی نیست و باید از طریق خصوصیت ZoomControlOption پیکربندی کنترل زوم را نیز اینجام دهید که این پیکربندی شامل موقعیت قرارگیری کنترلهای زوم و اندازهی دکمهها میباشد و مابقی تنظیمات هم بدین شکل هستند:
به غیر از تنظیمات نقشه، Overlayهای زیر در این کلاس پشتیبانی میشوند:
کد زیر و تصویر زیر نمونهای از کاربرد این کلاس است:
بعد از ایجاد چنین کلاسی نیاز است تا آن را در ویوو ترسیم کنیم. ابتدا یک div برای ناحیهی نقشه ایجاد میکنیم و سپس خروجی متد ShowMapForMVC را در ناحیهی Head صفحه چاپ میکنیم. این خروجی به طور خودکار یک MVCHTMLString را بر میگرداند. در صورتیکه از وب فرم استفاده میکنید، میتوانید از گزینهی ShowMap استفاده کنید.
در نهایت نقشهی زیر نمایش داده میشود:
کم حجم کردن کدها
در صورتیکه به سورس صفحه نگاهی بیندازید، میبینید که کدهای جاوا اسکریپت، داخل صفحه نوشته شدهاند. اگر بخواهید برای کم حجمتر شدن کد، عملیات minify را انجام دهید، با true شدن خصوصیت minified با استفاده از کتابخانهی وابستهاش (MS Ajax Minifier) اینکار را انجام میدهد.
انتقال کدها به یک فایل خارجی
بسیاری از ما برای نوشتن کدهای جاوا اسکریپت، از یک فایل خارجی استفاده میکنیم. برای داشتن این قابلیت میتوانید به جای ShowMapForMVC متد CallJs را صدا بزنید تا کتابخانه api گوگل را صدا بزند و سپس در یک اکشن متد، متد GiveJustJS را صدا بزنید و طبق مقالهی موجود در سایت جاری محتوای آن را برگردانید و به عنوان یک فایل JS به این اکشن متد لینک بدهید. کدهای زیر به شما نحوهی این کار را نشان میدهند:
ابتدا در یک اکشن متد، کد زیر را وارد میکنیم:
بعد از آن در ویووی مربوطه کد زیر را داریم:
بدین ترتیب کدهای شما داخل یک فایل خارجی قرار میگیرند.
نحوهی کارکرد این کتابخانه
برای آشنایی با نحوهی کارکرد آن باید بدانید که اساس کار این کتابخانه string interpolation است. این کتابخانه کلاسی را به صورت Partial دارد که بین چندین فایل تقسیم شده است و هر یک از فایلها، با نام محتوای آن نامگذاری شدهاند. Public methods متدهای عمومی، private methods متدهای خصوصی، Constants یا ثابتها که حاوی تمام دستورات جاوا اسکریپتی هستند و در نهایت خود کلاس اصلی GoogleMapApi که حاوی کدهای اجرایی و تشکیل کد جاوا اسکریپت میباشد. در کنار کلاس اصلی، کلاسهای Overlay هم قرار دارند که شامل اطلاعات اشیاء روی نقشهها هستند؛ مثل مارکرها و چندضلعیها و ... و در نهایت یک سری کلاس و نوع شمارشی Enum شامل خصوصیتهایی که برای تنظیمات و پیکربندی نقشه به کار میروند.
کلاس GoogleMapApi برای ایجاد کدها، دادههایی را که برای هر کلاس در نظر گرفتهاید، با استفاده از interpolation و ثابتهای حاوی کد جاوا اسکریپت، در یک رشتهی جدید قرار میدهند و این رشتهها با اتصال درست در موقعیت خود، کد نهایی جاوا اسکریپت را تولید میکنند.
سال گذشته بود که به بررسی کتابخانههای موجود برای دات نت که به ساخت نقشههای گوگل (+ ) میپردازند پرداختم. ولی مشکلی که وجود داشت، همه آنها در نهایت یک تصویر jpeg تحویل میدادند. ولی من میخواستم نقشهی من زنده و واکنشگرا باشد تا کاربر بتواند روی آن حرکت کند، زوم کند، مارکرها را جابجا کند و امکانات دیگری که در این نقشه در دسترس است را داشته باشد. برای همین شروع به ساخت یک class library کردم تا کاربر بتواند در محیط سی شارپ، تنظیمات را با اسامی قابل شناخت و یک intellisense قدرتمند بنویسد و در نهایت بر اساس اطلاعات کاربر، این کدها به صورت جاوا اسکریپت تولید شود. میتوانید سورس نهایی کتابخانهی GMap.Net را در گیت هاب، به همراه یک پروژهی نمونه ببینید.
پروژهی وابسته این کتابخانه، MS Ajax Minifier جهت کم حجم کردن کدهای جاوا اسکریپت است. در مورد این کتابخانه در سایت جاری بحث شده است.
برای نصب این کتابخانه میتوانید از طریق دستور زیر در Nuget عمل کنید:
Install-Package GMap.Net
در این کتابخانه مواردی که مورد توجه قرار گرفته است، تنظیمات نقشه و بعد از آن overlayها هستند که شامل مارکرها و اشکال مختلف میباشند. این اشکال شامل رسم مستطیل بر روی نقشه، چند ضلعیها و ... نیز میشوند.
برای شروع نیاز است که یک نمونه از کلاس GoogleMapApi را ایجاد کنید. بعد از آن با استفاده از خصوصیت SetLocation، مختصات مرکز نقشه را تنظیم نمایید. سپس با استفاده از خصوصیات دیگر نیز میتوانید نقشه را تنظیم نمایید. تعدادی از این خصوصیات مثل SetZoomVisibility هستند که با استفاده از آن میتوانید تنظیمات زوم را روی نقشه پیاده سازی کنید. البته فعال کردن این گزینه به تنهایی کافی نیست و باید از طریق خصوصیت ZoomControlOption پیکربندی کنترل زوم را نیز اینجام دهید که این پیکربندی شامل موقعیت قرارگیری کنترلهای زوم و اندازهی دکمهها میباشد و مابقی تنظیمات هم بدین شکل هستند:
به غیر از تنظیمات نقشه، Overlayهای زیر در این کلاس پشتیبانی میشوند:
عنوان | توضیحات |
Marker | یک نشانه گذار که برای مشخص کردن یک محل بر روی نقشه به کار میرود. این علامت گذار شامل خصوصیتهایی چون نقطهی قرارگیری، آیکن، عنوان و انیمیشنی برای نحوهی نمایش آن میباشد. همچنین شامل یک خصوصیت دیگر از نوع InfoWindow است که به شما امکان نمایش یک پنجرهی توضیحات را نیز بر روی مارکر میدهد. این محتوا میتواند به صورت HTML نمایش یابد. |
Circle | در صورتیکه بخواهید ناحیهای دایرهای شکل را بر روی نقشه مشخص کنید، کاربرد دارد. با دادن نقطهی مرکزی و شعاع میتوانید دایره را ترسیم کنید. همچنین شامل خصوصیات ظاهری چون رنگ داخل و حاشیهها و میزان شفافیت نیز میباشد. |
Rectangle | به رسم یک مستطیل میپردازد و تنها لازم است دو مختصات را به آن بدهید و بر اساس این دو نقطه، ناحیهی مستطیلی شکل ترسیم میگردد. در صورتیکه نقاط بیشتری را به آن اضافه کنید، فقط دوتای اولی در نظر گرفته میشوند. این گزینه شامل خصوصیات ظاهری نیز میگردد. |
Polyline | برای ترسیم مسیرها به صورت چند ضلعی به کار میرود و الزامی به بستن مسیرها نیست. دارای خصوصیات ظاهری نیز میباشد. |
polygon | کاملا شبیه Ployline است؛ با این تفاوت که یک چند ضلعی بسته است و میتواند داخل آن با رنگ پر باشد. برای بستن این چند ضلعی لازم نیست تا کاری انجام دهید. خود کلاس، نقطهی اول و آخر را به هم وصل میکند. |
خصوصیات آیتمهای بالا، شامل موارد زیر میشود:
نام خصوصیت | توضیحات |
Id | در سازندهی هر کدام به طور اجباری قرار گرفته است. این id برای زمانی است که بخواهید با استفاده از جاوااسکرپیت با آن ارتباط برقرار کنید. |
Editable | با فعال کردن این خاصیت، به کاربر این اجازه را میدهید که بتواند روی Overlay ویرایش انجام دهد. |
StrokeWeight | ضخامت لبهها را مشخص میکند. |
StrokeColor | رنگ لبه را مشخص میکند. |
StrokeOpacity | میزان شفافیت لبه را بین 0 تا 1 مشخص میکند. |
FillColor | بعضی از المانها مانند چند ضلعیهای بسته و مستطیل که ناحیهی داخلی دارند، شامل این گزینه هستند و رنگ داخل این ناحیه را مشخص میکنند. |
FillOpacity | میزان شفافیت خصوصیت بالا را از 0 تا 1 مشخص میکند. |
Points | با استفاده از این خاصیت میتوانید مختصات را با استفاده از کلاس Location به آن اضافه کنید. برای دایره خصوصیت Point وجود دارد. |
Radius | برای دایره کاربرد دارد. با مقدار نوع Int میتوانید شعاع آن را مقدار دهی کنید. |
public class MiladTower { public GoogleMapApi TestMarker() { var map=new GoogleMapApi(true); var location = new Location(35.7448416, 51.3753212); map.SetLocation(location); map.SetZoom(17); map.SetMapType(MapTypes.ROADMAP); map.SetBackgroundColor(Color.Aqua); map.ZoomControlVisibilty(true); map.ZoomOptions = new zoomControlOptions() { Position = Position.TOP_LEFT, ZoomStyle = ZoomStyle.SMALL }; Marker marker=new Marker("mymarker1"); marker.InfoWindow=new InfoWindow("iw1") { Content = "<b>Milad Tower</b><i>in Tehran</i><br/>Milad Tower is the highest tower in iran,many people and tourists visit it each year, but it's so expensive that i cant afford it as iranian citizen<br/>please see more info at <a href=\"https://en.wikipedia.org/wiki/Milad_Tower\"><img width='16px' height='16px' src='https://en.wikipedia.org/favicon.ico'/>wikipedia</a>" }; marker.MarkerPoint = location; map.Markers.Add(marker); var circle=new CircleMarker("mymarker2"); circle.FillColor = Color.Green; circle.FillOpacity = 0.6f; circle.StrokeColor = Color.Red; circle.StrokeOpacity = 0.8f; circle.Point = location; circle.Radius = 30; circle.Editable = true; circle.StrokeWeight = 3; map.Circles.Add(circle); Rectangle rect=new Rectangle("rect1"); rect.FillColor = Color.Black; rect.FillOpacity = 0.4f; rect.Points.Add(new Location(35.74728723483808, 51.37550354003906)); rect.Points.Add(new Location(35.74668641224311, 51.376715898513794)); map.Rectangles.Add(rect); Polyline polyline=new Polyline("poly1"); polyline.Points.Add(new Location(35.74457043569041, 51.373915672302246)); polyline.Points.Add(new Location(35.74470976097927, 51.37359380722046)); polyline.Points.Add(new Location(35.744378863020074, 51.37337923049927)); polyline.StrokeColor = Color.Blue; polyline.StrokeWeight = 2; map.Polylines.Add(polyline); Polygon polygon=new Polygon("poly2"); polygon.Points.Add(new Location(35.746494844665094, 51.374655961990356)); polygon.Points.Add(new Location(35.74635552250061, 51.37283205986023)); polygon.Points.Add(new Location(35.74598109297522, 51.372681856155396)); polygon.Points.Add(new Location(35.7454934611854, 51.37361526489258)); polygon.FillColor = Color.Black; polygon.FillOpacity = 0.5f; polygon.StrokeColor = Color.Gray; polygon.StrokeWeight = 1; map.Polygons.Add(polygon); return map; } }
@section javascript { @{ var map = new MiladTower().TestMarker(); @map.ShowMapForMvc("mapdiv") } } <br/><br/> <div id="mapdiv" style="width:600px;height:600px;"></div>
در نهایت نقشهی زیر نمایش داده میشود:
کم حجم کردن کدها
در صورتیکه به سورس صفحه نگاهی بیندازید، میبینید که کدهای جاوا اسکریپت، داخل صفحه نوشته شدهاند. اگر بخواهید برای کم حجمتر شدن کد، عملیات minify را انجام دهید، با true شدن خصوصیت minified با استفاده از کتابخانهی وابستهاش (MS Ajax Minifier) اینکار را انجام میدهد.
انتقال کدها به یک فایل خارجی
بسیاری از ما برای نوشتن کدهای جاوا اسکریپت، از یک فایل خارجی استفاده میکنیم. برای داشتن این قابلیت میتوانید به جای ShowMapForMVC متد CallJs را صدا بزنید تا کتابخانه api گوگل را صدا بزند و سپس در یک اکشن متد، متد GiveJustJS را صدا بزنید و طبق مقالهی موجود در سایت جاری محتوای آن را برگردانید و به عنوان یک فایل JS به این اکشن متد لینک بدهید. کدهای زیر به شما نحوهی این کار را نشان میدهند:
ابتدا در یک اکشن متد، کد زیر را وارد میکنیم:
public ActionResult MiladJs() { var output = new MiladTower().TestMarker().GiveJustJs("mapdiv"); Response.ContentType = "text/javascript"; return Content(output); }
بعد از آن در ویووی مربوطه کد زیر را داریم:
@section javascript { @{ var map = new MiladTower().TestMarker(); @map.CallJs() <script type="text/javascript" src="@Url.Action("MiladJs","Home")"></script> } } <br/><br/> <div id="mapdiv" style="width:600px;height:600px;"></div>
نحوهی کارکرد این کتابخانه
برای آشنایی با نحوهی کارکرد آن باید بدانید که اساس کار این کتابخانه string interpolation است. این کتابخانه کلاسی را به صورت Partial دارد که بین چندین فایل تقسیم شده است و هر یک از فایلها، با نام محتوای آن نامگذاری شدهاند. Public methods متدهای عمومی، private methods متدهای خصوصی، Constants یا ثابتها که حاوی تمام دستورات جاوا اسکریپتی هستند و در نهایت خود کلاس اصلی GoogleMapApi که حاوی کدهای اجرایی و تشکیل کد جاوا اسکریپت میباشد. در کنار کلاس اصلی، کلاسهای Overlay هم قرار دارند که شامل اطلاعات اشیاء روی نقشهها هستند؛ مثل مارکرها و چندضلعیها و ... و در نهایت یک سری کلاس و نوع شمارشی Enum شامل خصوصیتهایی که برای تنظیمات و پیکربندی نقشه به کار میروند.
کلاس GoogleMapApi برای ایجاد کدها، دادههایی را که برای هر کلاس در نظر گرفتهاید، با استفاده از interpolation و ثابتهای حاوی کد جاوا اسکریپت، در یک رشتهی جدید قرار میدهند و این رشتهها با اتصال درست در موقعیت خود، کد نهایی جاوا اسکریپت را تولید میکنند.
از virtual pc که یک ویندوز اکس پی بر روی آن نصب کردهام برای اتصال به VPN استفاده میکنم. (متاسفانه آخرین نگارش vmware برای اینکار جواب نداد)
زمان اتصال به VPN کل سیستم وارد شبکه مورد نظر خواهد شد و این مورد شاید بهدلایلی برای مثال قطع اینترنت و یا اعمال پالیسیهای شبکه بر روی کامپیوتر کاری جالب نباشد (استفاده از VPN برای اتصال به یک شبکه دومین ویندوزی). اما با نصب ماشین مجازی و اجرای یک سیستم عامل دیگر به موازات سیستم عامل اصلی، کار اتصال به VPN از داخل ماشین مجازی صورت خواهد گرفت و تمام این اعمال هم از سیستم عامل مادر مجزا و ایزوله خواهند بود.
یک ویندوز اکس پی با اختصاص 200 مگ رم هم کار میکند و عملا باری را بر روی سیستم عامل مادر تحمیل نخواهد کرد. همچنین حتما از منوی action گزینه install or update virtual machine additions را انتخاب کنید تا کارآیی سیستم عامل مجازی را بهبود بخشید. حداقل فایده آن این است که اشارهگر ماوس را به سادگی میتوان از ماشین مجازی خارج کرد و هر بار نیازی به فشردن دکمه ALT سمت راست نخواهد بود!
اولین مشکلی که هنگام کار با یک ماشین مجازی خود نمایی میکند بحث انتقال فایل بین سیستم عامل مادر (ویندوزی که شما ماشین مجازی را روی آن نصب کردهاید) و ماشین مجازی است. عمومیترین راه، ایجاد یک فایل iso از فایلهای مورد نظر است و سپس انتخاب منوی CD و گزینه capture iso image . این روش بر روی vmware هم جواب میدهد (معرفی فایل iso بعنوان CD-ROM آن). خوشبختانه عمل drag & drop (از سیستم عامل مادر به ماشین مجازی) که شاید در وحله اول به ذهن نرسد اینجا بخوبی کار خواهد کرد و مشکل ساخت فایلهای iso را برطرف میکند. (البته vmware کمی پیشرفتهتر است و حتی copy و Paste را نیز پشتیبانی میکند. اما خوب، رایگان نیست!)
مشکل بعدی با ms virtual pc افزایش تدریجی حجم آن است. روز اول 2 گیگ، روز سوم 4 گیگ، هفته بعد میشود 6 گیگ! برای فشرده سازی آن میتوان به روش زیر عمل کرد:
به مسیر زیر مراجعه کنید: (اگر پیشفرضهای نصب را پذیرفتهاید)
C:\Program Files\Microsoft Virtual PC\Virtual Machine Additions
فایل Virtual Disk Precompactor.iso را از طریق منوی CD و گزینه capture iso image باز کنید. برنامهای به صورت خودکار اجرا خواهد شد که سیستم عامل مجازی را آماده فشرده سازی میکند. پس از پایان کار، سیستم عامل مجازی را خاموش کنید. سپس به منوی file گزینه virtual disk wizard مراجعه نمائید. در صفحه بعدی گزینه ویرایش یک ماشین مجازی موجود را انتخاب کرده و فایل ماشین مجازی مورد نظر را که پیشتر برای فشرده سازی آماده کردیم به آن معرفی کنید. در صفحه بعد گزینه compact it را انتخاب کرده و در ادامه میتوانید مسیر جدیدی را مشخص کنید یا انتخاب کنید که فایل نهایی فشرده شده جایگزین فایل موجود شود.
با اینکار یک ماشین مجازی 6 گیگابایتی به 3 گیگ کاهش حجم یافت که قابل توجه است.
برای استفاده از اینترنت سیستم عامل مادر در ms virtual pc میشود از منوی edit ، گزینه setting و انتخاب networking در صفحه ظاهر شده، تنظیم اولین adapter شبکه را بر روی shared networking NAT قرار داد و همه چیز به خوبی کار خواهد کرد. (البته برای استفاده از اینترنت در vmware باید روی کانکشن اینترنت خود در سیستم عامل مادر کلیک راست کرد و سپس انتخاب گزینه advanced و فعال سازی internet connection sharing بر روی کارت شبکه مجازی نصب شده آن ضروری خواهد بود)