فایل‌های پروژه‌ها
DNTViewer.V1.1.zip
- لینک به صفحات داخلی سایت موجود در بانک اطلاعاتی، از همان بانک اطلاعاتی آفلاین خوانده خواهد شد.
- بهبود کیفیت جستجوی مطالب
مطالب
شروع کار با Apache Cordova در ویژوال استودیو #1
Apache Cordova  یک فریمورک سورس باز برای ساخت اپلیکیشن‌های چند سکویی موبایل (cross platform) با استفاده از Html5 می‌باشد.
طی چند مقاله، با استفاده کردن از این فریمورک در VS آشنا خوهیم شد.
هدف خالقان Cordova یافتن یک راه ساده برای تولید اپلیکیشن‌های چند سکویی موبایل بود که برای رسیدن به این هدف تصمیم گرفتند از تکنولوژی‌های بومی (native) و تکنولوژی‌های وب استفاده کنند. به این نوع از اپلیکیشن‌های موبایل، Hybrid Application می‌گویند.
  Cordova دارای  قابلیت‌های بومی بالایی است و مهم‌تر اینکه به طور طبیعی توسط مرورگرها پشتیبانی می‌شود. بعد از تولد Corodva، این فریمورک تبدیل شده است به  بهترین روش تولید اپلیکیشن‌هایی که بر روی چند نوع پلتفرم کار می‌کنند.
پیشتر محدودیتی که وجود داشت شامل این بود که اپلیکیشن‌های موبایل، به چیزهایی بیشتر از HTML و مرورگرهای وب، نیاز داشتند. برخی از این نیاز‌ها عبارتند از ارتباط متقابل وب اپلیکیشن‌ها با دوربین یا لیست شماره‌های تماس گوشی که برطرف کردن آن هم به راحتی امکان پذیر نبود.
Cordova برای مقابله با این محدودیت، مجموعه‌ای از رابط‌های برنامه کاربردی را برای توسعه قابلیت‌های بومی device، مانند لیست مخاطبین، دوربین، تشخیص دهنده‌ی تغییر جهت گوشی (accelerometer) و مانند این موارد، در نظر گرفته است.


Cordova شامل یک سری کامپوننت به شرح زیر است:
  1. سورس کدی برای هر Container و برنامه محلی برای هر یک از سکوهای موبایل که پشتیبانی می‌شوند. container، کد‌های Html5 را بر روی دستگاه (Device) رندر می‌کند. (در مطالب بعدی در مورد این مطلب توضیح خواهم داد)
  2. مجموعه‌ای از رابط‌های برنامه‌ی کاربردی که امکان دسترسی به قابلیت‌های بومی دستگاه را به برنامه‌ی وبی که درون آن در حال اجرا است، می‌دهند.
  3. مجموعه‌ای از ابزارها برای مدیریت فرآیند ایجاد پروژه، مدیریت پلاگین‌ها، ساخت (با استفاده از SDK‌های محلی) برنامه‌های محلی و تست برنامه بر روی دستگاه موبایل یا شبیه ساز  .
 
برای ساخت یک برنامه‌ی Cordova، در واقع شما یک وب اپلیکیشن می‌سازید و آن را داخل Container محلی، بسته بندی می‌کنید. سپس تست کرده و بعد از دیباگ می‌توانید اپلیکیشن را توزیع کنید.

فرآیند بسته بندی :

 داخل اپلیکیشن محلی، رابط کاربری اپلیکیشن شامل یک صفحه‌ی نمایش که خود آن چیزی نیست به غیر از یک Web View که از فضای نمایش دستگاه استفاده می‌کند. زمانی که برنامه آغاز به کار می‌کند، برنامه‌ی وب نوشته شده، درون این web view لود میشود و کنترل‌های موجود، برای تعامل کاربر با برنامه‌ی وب، در اختیار آن قرار می‌گیرند. مانند تعامل کاربر با محتوا، در برنامه‌ها ی تحت وب، لینک‌ها، کدهای نوشته شده‌ی js در فایل‌ها و یا حتی می‌تواند به اینترنت دسترسی داشته باشد و محتوا را از یک وب سرور تغذیه کند.

درباره Web Views
Web View جزء برنامه‌های بومی است که برای رندر کردن محتوای وب (به عنوان نمونه صفحه HTML) درون اپلیکیشن بومی یا صفحه نمایش استفاده می‌شود. در اصل Web View یک Wrapper برنامه نویسی شده قابل دسترس برای نمایش محتوای صفحات وب توکار است.
به عنوان مثال:
در اندروید با استفاده از WebView موجود در (Using andoid.webkit.WebView) , در iOS با UIWebView موجود در (Using System/Library/Framworks/UIKit.framewor)  به این هدف دست پیدا می‌کنند. وب اپلیکیشن ما درون این Container مانند سایر وب اپلیکیشن‌هایی است که هر روز با آنها سرو کار دارید و آنها را در مرورگر موبایل خود اجرا می‌کنید و می‌توانید بین صفحات Navigation داشته باشید. وب اپلیکیشن‌های معمول باید روی یک سرور هاست شوند. در برنامه نویسی چند سکویی با Cordova، این کار می‌تواند درون Cordova Application انجام گیرد.
شاید سؤالی در ذهن شما وجود داشته باشد که مرورگر معمولا به اپلیکیشن‌های موجود در دستگاه، سخت افزار و یا API‌های بومی دستگاه، دسترسی ندارد. برای مثال شاید بگویید که یک وب اپلیکیشن معمولا به لیست مخاطبین با دوربین دستگاه و ... دسترسی ندارد. 
جواب : در واقع امکان دسترسی به این قابلیت‌ها توسط اپلیکیشن بومی (native mobile application) ایجاد می‌شود.
Cordova مجموعه ای از API‌های جاوااسکریپت را به عنوان اهرم اجازه برای دسترسی  برنامه وب درون cordova container به قابلیت‌های بومی دستگاه، در اختیار توسعه دهندگان قرار داده است.

این API‌ها در دو بخش پیاده سازی می‌شوند:
1-کتابخانه‌ی جاوااسکریپت که اجازه‌ی استفاده از قابلیت‌های بومی را به وب اپلیکیشن می‌دهد و کد بومی مشابه در Container اجرا می‌شود که مربوط است به بخش بومی این API ها. در اصل یک کتابخانه‌ی جاوا اسکریپت وجود دارد، اما بخش بومی API‌ها وابسته به سکوی (platform) انتخاب شده پیاده سازی می‌شود.
اگر شما از API‌های موجود استفاده نکنید، می‌توانید آنها را از کتابخانه جاوااسکریپت و native container حذف کنید. این کار به صورت دستی شاید خوشایند نباشد ولی چون در Cordova 3.0 همه‌ی API ها از بیرون وارد می‌شوند، می‌توانید با استفاده از بحث مدیریت پلاگین آن، پلاگین‌ها را اضافه یا حذف کنید. در بخش‌های بعد با مثال‌هایی عملی  این مباحث را کار خواهیم کرد. 
 ادامه دارد.. 

مطالب
آشنایی با SASS یا Syntactically Awesome Stylesheets و روش نصب و استفاده از آن

استفاده از CSS علاوه بر جذابیت و قابلیت‌های مفید آن، پیچیدگی هایی دارد و کدهای شما معمولا طولانی می‌شود و هرچه کدها طولانی‌تر شوند، مدیریت آن نیز سخت‌تر می‌گردد. اما با استفاده از SASS ، قابلیت هایی به Css اضافه می‌شود که قبلا وجود نداشت، از جمله استفاده از varible ها، نوشتن کدهای تو در تو ( nesting ) و . با استفاده از SASS کدهای CSS کوتاه‌تر شده و در نتیجه سریعتر اجرا شوند. SASS   با CSS3 سازگار است. همچنین امکان مشاهده فایلهای آن (با پسوند .scss ) توسط افزونه Firesass For Firebug وجود دارد.

دو syntax برای SASS وجود دارد: یکی SCSS (Sassy CSS) که شکل توسعه یافته CSS3 می باشدو دیگری که قدیمی‌تر است، Indented syntax می‌باشد که در آن به جای استفاده از براکت، از تورفتگی خطهای کد استفاده می‌شود و همچنین از به جای استفاده از سمی کولن ، باید به خط جدید بروید.

 

قابلیتهای موجود در SASS :

1- Variables

متغیرها امکان ایجاد تغییرات در کدهای CSS را بسیار راحتتر می‌سازند. به عنوان مثال یک متغیر برای یک کد رنگ دلخواه تعریف می‌کنید، از این به بعد به جای استفاده از کد رنگ در کدهای CSS ، از متغیر تعریف شده  برای آن بهره می‌گیرید، به این ترتیب ، چنانچه در آینده نیاز به تغییر این کد رنگ داشته باشید، تنها با تغییر آن در متغیر ، در کل فایل CSS تغییر ایجاد خواهد شد . برای تعریف متغیر ، در ابتدای اسم دلخواه خود از علامت $ استفاده کنید:

$myColor:   #ff0000;
 
body {
    color: $myColor;
}
.box{
Border-color:$myColor;
}

Nesting -2 یا selector ‌های تو در تو:  

می توانید selector ‌ها را مانند کدهای html به صورت hirearchy تعریف کنید:

nav {
     ul {
          list-style: none;
         }
      li { display: inline-block; }
      a {
          text-decoration: none;
         }
}
کدهای بالا بعد از تولید شدن در مرورگر به شکل زیر دیده  می‌شود:

nav ul {
  list-style: none;
}
nav li {
  display: inline-block;
}
nav a {
  text-decoration: none;
}

3- Partials
:

می توانید قطعاتی از کدهای CSS را به صورت Partial SASS تعریف کنید و سپس آن را در فایلهای SASS دیگر استفاده نمایید.همانند Partialview در MVC ، هنگام نام گذاری آن از _ در ابتدای نام استفاده نمایید. فایل partial SASS دارای پسوند   .SCSS می باشد : " "_myPartial.scss

برای استفاده از _myPartial.scss در فایل sass دیگر ، از دایرکتیو @import استفاده کنید:

@import "myPartial"
همچنین می‌توانید نام چندین partial را پشت هم بنویسید:
@import "mypartial1","myPartial2"
نمونه کد:
/*_myPartial1.scss  codes…*/
html,body,ul,ol {
  margin:  0;
  padding: 0;
}
 
/*_myPartial2.scss  codes…*/
 
@import "myPartial1"
 
body, {
 background-color: #efefef;
}
 کدها بعد از تولید در مرورگر:

html, body, ul, ol {
  margin: 0;
  padding: 0;
}
body {
  background-color: #efefef;
  }

4- Mixins :

از آنجایی که استفاده و نوشتن بعضی property ‌های CSS سخت می‌باشد، می‌توانید از روش mixin استفاده کرده و قطعه کدهایی را ایجاد کنید که بتوانید در کدهایتان از آنها بارها و بارها استفاده کنید. به عنوان مثال قطع کدی برای border-radius ایجاد کنید ، (همانطور که میدانید border-radius برای مرورگرهای مختلف ، حالتهای مختلفی تعریف می‌شود.). برای ایجاد mixin ، در ابتدای قطع کد از @mixin استفاده نمایید و برای استفاده ازآن ، از @include استفاده نمایید:  

@mixin cssProperty $yourCustomName{
…
Your css properties…
}

نمونه کد:
ایجاد mixin:

@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
     -moz-border-radius: $radius;
      -ms-border-radius: $radius;
       -o-border-radius: $radius;
          border-radius: $radius;
}

استفاده از mixin:

.box { @include border-radius(10px); }

Extend/Inheritance -5 :

@XETEND به شما این امکان را می‌دهد تا بخشی از Property ‌های یک selector را برای استفاده در selector ‌های دیگر به اشتراک بگذارید:

.message {
  border: 1px solid #ccc;
  padding: 10px;
  color: #333;
}
.success {
  @extend .message;
  border-color: green;
}

کدها بعد از تولید شدن به صورت زیر دیده می‌شوند:

.message, .success {
  border: 1px solid #cccccc;
  padding: 10px;
  color: #333;
}
 
 .success {
  border-color: green;
}

6- Operators :

می توانید از عملگرهای ضرب و تقسیم و جمع و تفریق در کدهای CSS خود استفاده نمایید:

article[role="main"] {
  float: left;
  width: 600px / 960px * 100%;
}

 
نصب SASS :

حال که با SASS آشنا شدید ، انگیزه کافی برای دانستن روش نصب و استفاده آن خواهید داشت. برای استفاده از SASS می توانید از نرم افزارهایی که برای ویندوز ، مک و لینوکس وجود دارند، استفاده کنید از جمله این نرم افزارها :

CodeKit , Compass.app , Hammer , Koala , LiveReload , Mixture , Prepros , Prepros Pro , Scout


روش دیگر استفاده از command line می‌باشد:

چنانچه سیستم عامل شما ویندوز می‌باشد، برای استفاده از sass ابتدا باید  rubby را نصب نمایید. سپس در Cmd خط زیر را اجرا کنید:

gem install sass

چنانچه به خطایی برخوردید، ابتدا gem توسط sudo را نصب کنید:

sudo gem install sass

 سپس توسط خط زیر چک کنید که SASS نصب شده است یا خیر:

sass -v
خط فوق، ورژن SASS نصب شده را برای شما می‌گرداند که نشان می‌دهد نصب SASS با موفقیت صورت گرفته است:  
 
Sass 3.2.12 (Media Mark)

برای کسب اطلاعات بیشتر و روش نصب در سایر سیستم عاملها به این  لینک مراجعه نمایید.

SassScript :

فایل SASS اسکریپتی برای اجرای یک سری از فانکشنها دارد، از جمله :

- rgb($red, $green, $blue)   /* برای ایجاد کد رنگ rgb */

برای مشاهده لیست کامل این فانکشنها به این لینک مراجعه کنید.

 
 منبع
مطالب
ایجاد Drop Down List های آبشاری توسط Kendo UI
پیشتر مطلبی را در مورد ایجاد Drop Down List‌های به هم پیوسته توسط jQuery Ajax در این سایت مطالعه کرده بودید. شبیه به همان مطلب را اینبار قصد داریم توسط Kendo UI پیاده سازی کنیم.


مدل‌های برنامه

در اینجا قصد داریم لیست گروه‌ها را به همراه محصولات مرتبط با آن‌ها، توسط دو drop down list نمایش دهیم:
public class Category
{
    public int CategoryId { set; get; }
    public string CategoryName { set; get; }
 
    [JsonIgnore]
    public IList<Product> Products { set; get; }
}


public class Product
{
    public int ProductId { set; get; }
    public string ProductName { set; get; }
}
از ویژگی JsonIgnore جهت عدم درج لیست محصولات، در خروجی JSON نهایی تولیدی گروه‌ها، استفاده شده‌است.


منبع داده JSON سمت سرور

پس از مشخص شدن مدل‌های برنامه، اکنون توسط دو اکشن متد، لیست گروه‌ها و همچنین لیست محصولات یک گروه خاص را با فرمت JSON بازگشت می‌دهیم:
using System.Linq;
using System.Text;
using System.Web.Mvc;
using KendoUI12.Models;
using Newtonsoft.Json;
 
namespace KendoUI12.Controllers
{
 
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View(); // shows the page.
        }
 
        [HttpGet]
        public ActionResult GetCategories()
        {
            return new ContentResult
            {
                Content = JsonConvert.SerializeObject(CategoriesDataSource.Items),
                ContentType = "application/json",
                ContentEncoding = Encoding.UTF8
            };
        }
 
        [HttpGet]
        public ActionResult GetProducts(int categoryId)
        {
 
            var products = CategoriesDataSource.Items
                            .Where(category => category.CategoryId == categoryId)
                            .SelectMany(category => category.Products)
                            .ToList();
 
            return new ContentResult
            {
                Content = JsonConvert.SerializeObject(products),
                ContentType = "application/json",
                ContentEncoding = Encoding.UTF8
            };
        }
    }
}
بار اولی که صفحه بارگذاری می‌شود، توسط یک درخواست Ajax ایی، لیست گروه‌ها دریافت خواهد شد. سپس با انتخاب یک گروه، اکشن متد GetProducts جهت بازگرداندن لیست محصولات آن گروه، فراخوانی می‌گردد.
در اینجا به عمد از JsonConvert.SerializeObject استفاده شده‌است تا ویژگی JsonIgnore کلاس گروه‌ها، توسط کتابخانه‌ی JSON.NET مورد استفاده قرار گیرد (ASP.NET MVC برخلاف ASP.NET Web API به صورت پیش فرض از JSON.NET استفاده نمی‌کند).


کدهای سمت کاربر برنامه

کدهای جاوا اسکریپتی Kendo UI را جهت تعریف دو drop down list به هم مرتبط و آبشاری، در ادامه ملاحظه می‌کنید:
<!--نحوه‌ی راست به چپ سازی -->
<div class="k-rtl k-header demo-section">
    <label for="categories">گروه‌ها: </label><input id="categories" style="width: 270px" />
    <label for="products">محصولات: </label><input id="products" disabled="disabled" style="width: 270px" />
</div>
 
@section JavaScript
{
    <script type="text/javascript">
        $(function () {
            $("#categories").kendoDropDownList({
                optionLabel: "انتخاب گروه...",
                dataTextField: "CategoryName",
                dataValueField: "CategoryId",
                dataSource: {
                    transport: {
                        read: {
                            url: "@Url.Action("GetCategories", "Home")",
                            dataType: "json",
                            contentType: 'application/json; charset=utf-8',
                            type: 'GET'
                        }
                    }
                }
            });
 
            $("#products").kendoDropDownList({
                autoBind: false, // won’t try and read from the DataSource when it first loads
                cascadeFrom: "categories", // the id of the DropDown you want to cascade from
                optionLabel: "انتخاب محصول...",
                dataTextField: "ProductName",
                dataValueField: "ProductId",
                dataSource: {
                    // When the serverFiltering is disabled, then the combobox will not make any additional requests to the server.
                    serverFiltering: true, // the DataSource will send filter values to the server
                    transport: {
                        read: {
                            url: "@Url.Action("GetProducts", "Home")",
                            dataType: "json",
                            contentType: 'application/json; charset=utf-8',
                            type: 'GET',
                            data: function () {
                                return { categoryId: $("#categories").val() };
                            }
                        }
                    }
                }
            });
        });
    </script>
 
    <style scoped>
        .demo-section {
            width: 100%;
            height: 100px;
        }
    </style>
}
دراپ داون اول، به صورت متداولی تعریف شده‌است. ابتدا فیلدهای Text و Value هر ردیف آن مشخص و سپس منبع داده آن به اکشن متد GetCategories تنظیم گردیده‌است. به این ترتیب با اولین بار مشاهده‌ی صفحه، این دراپ داون پر خواهد شد.
سپس دراپ دوم که وابسته‌است به دراپ داون اول، با این نکات طراحی شده‌است:
الف) خاصیت autoBind آن به false تنظیم شده‌است. به این ترتیب این دراپ داون در اولین بار نمایش صفحه، به سرور جهت دریافت اطلاعات مراجعه نخواهد کرد.
ب) خاصیت cascadeFrom آن به id دراپ داون اول تنظیم شده‌است.
ج) در منبع داده‌ی آن دو تغییر مهم وجود دارند:
- خاصیت serverFiltering به true تنظیم شده‌است. این مورد سبب خواهد شد تا آیتم گروه انتخاب شده، به سرور ارسال شود.
- خاصیت data نیز تنظیم شده‌است. این مورد پارامتر categoryId اکشن متد GetProducts را تامین می‌کند و مقدار آن از مقدار انتخاب شده‌ی دراپ داون اول دریافت می‌گردد.

اگر برنامه را اجرا کنیم، برای بار اول لیست گروه‌ها دریافت خواهند شد:


سپس با انتخاب یک گروه، لیست محصولات مرتبط با آن در دراپ داون دوم ظاهر می‌گردند:



کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید.
اشتراک‌ها
پلتفرم خودکار یک پلتفرم رایگان و متن باز (Open Source) برای تولید نرم افزار تحت وب با تکنولوژی مایکروسافت
پلتفرم خودکار یه پروژه متن بازه و ایده اصلی اش تولید یک نرم افزار تحت وب از صفر تا صد به صورت آنلاین و بدون نیاز به ابزار هایی مثل ویژوال استدیو Sql Management Studio و TFS  و غیره و تنها با یک مرورگر ساده مثل Chrome .


پلتفرم خودکار  همانند ویژوال استدیو دو حالت Release و دیباگ دارد که این امکان را به برنامه نویسان می‌دهد که کدهای اجرایی در سمت سرور و کلاینت در دو حالت دیباگ و Release کاملا مختلف و مجزا باشند.

یعنی شما برای ساخت یک وب سایت می‌تونید تمام کدهای سمت سرور و کلاینت و دیتابیس رو از طریق یک مرورگر وب بنویسید و اگه نیاز به کامپایل باشه , خود پلتفرم این کار رو انجام میده.
تعدادی از این کدها : C# VB.Net SQL CSS JavaScript SASS LESS Coffee و غیره

اما غیر از اینها پلتفرم خودکار شامل یه سورس کنترل و مدیریت ورژن و Build System و Load Module  اختصاصی هم میشه .یعتی عملا شما نیازی به سورس کنترل‌های آنلاین
مثل GitHub , ... را ندارید و می‌تونید دسترسی ویرایش و یا Build و یا Test و یا اجرا رو در سطح یک خط کد تا یک پروژه به طور کامل به سایر برنامه نویسان بدهید.

برای طراحی و ساخت دیتابیس تون و مدیریت Migration‌‌ها هم یک ابزار انلاین داره که پشت صحنه از Entity FrameWork استفاده می‌کنه و تمامی امکانات Entity FrameWork   برای ساخت و پشتیبانی دیتابیس رو به صورت آنلاین در اختیار شما می‌زاره.

وابسته به فریم ورک خاصی در سمت کلاینت نیست .ولی پیش فرض اش JQUERY و بوت استرپ استفاده می‌کنه. شما می‌تونید N تا فریم ورک و قالب متفاوت تعریف کنید , به طوری که برای مثال یه صفحه وبسایتتون با React و صفحه دیگه با انگولار باشه .

برای دیباگ تحت وب هم امکاناتی در اختیار برنامه نویس قرار می‌ده مثل ریموت دیباگ و یا دیباگ در ویژوال استدیو.این‌ها بخشی از امکانات پلتفرم خودکاره برای آشنایی بیشتر با امکانات پلتفرم از لینک‌های زیر استفاده کنید.

حدود 70 ساعت آموزش در آپارات  :


خودم تا حالا دو تا وبسایت باهاش نوشتم و البته چند تا دیگه هم در دست توسعه است. وبسایت های کارشناسان.نت با قالب بوت استرپ و jquery  نوشته شده و داستان موفقیت با قالب Material و jquer نوشته شده است.

دوستان عزیز قصد دارم ورژن core پلتفرم خودکار  رو بنویسم و یه سری امکانات جدید مثل کامپایلر و BuildSystem ری اکت رو اضافه کنم و هوش مصنوعی IDE رو هم افزایش بدم. اگر علاقه مند به همکاری هستید برام پیام بذارید.

با توجه به متن باز بودن پلتفرم , سود مالی وجود نداره ولی می‌تونه رزومه خوبی براتون بشه و از اون مهمتره می‌تونه پروژه فوق العاده ارزشمند و کاربردی باشه. 

پلتفرم خودکار یک پلتفرم رایگان و متن باز (Open Source) برای تولید نرم افزار تحت وب با تکنولوژی مایکروسافت
مطالب
ASP.NET MVC #1

چرا ASP.NET MVC ؟

با وجود فریم ورک پخته‌ای به نام ASP.NET web forms، اولین سؤالی که حین سوئیچ به ASP.NET MVC مطرح می‌شود این است: «برای چی؟». بنابراین تا به این سؤال پاسخ داده نشود، هر نوع بحث فنی در این مورد بی فایده است.

مزایای ASP.NET MVC نسبت به ASP.NET web forms

1) سادگی نوشتن آزمون‌های واحد
مهم‌ترین دلیل استفاده از ASP.NET MVC صرفنظر از تمام دلایل دیگر، بحث طراحی ویژه آن جهت ساده سازی تهیه آزمون‌های واحد است. مشکل اصلی نوشتن آزمون‌های واحد برای برنامه‌های ASP.NET web forms، درگیر شدن مستقیم با تمام جزئیات طول عمر یک صفحه است. به علاوه فایل‌های code behind هر چند به ظاهر کدهای منطق یک صفحه را از کدهای HTML مانند آن جدا می‌کنند اما در عمل حاوی ارجاعات مستقیمی به تک تک عناصر بصری موجود در صفحه هستند (حس غلط جدا سازی کدها از اجزای یک فرم). اگر قرار باشد برای این وب فرم‌ها و صفحات، آزمون واحد بنویسیم باید علاوه بر شبیه سازی چرخه طول عمر صفحه و همچنین رخدادهای رسیده، کار وهله سازی تک تک عناصر بصری را نیز عهده دار شویم. اینجا است که ASP.NET web forms گزینه‌ی مطلوبی برای این منظور نخواهد بود و اگر نوشتن آزمون واحد برای آن غیرممکن نباشد، به همین دلایل آنچنان مرسوم هم نیست.
البته شاید بپرسید که این مساله چه اهمیتی دارد؟ امکان نوشتن ساده‌تر آزمون‌های واحد مساوی است با امکان ساده‌تر اعمال تغییرات به یک پروژه بزرگ. تغییرات در پروژه‌های بزرگی که آزمون واحد ندارند واقعا مشکل است. یک قسمت را تغییر می‌دهید، 10 قسمت دیگر به هم می‌ریزند. اینجا است که مدام باید به کارفرما گفت: «نه!»، «نمیشه!» یا به عبارتی «نمی‌تونم پروژه رو جمع کنم!» چون نمی‌تونم سریع برآورد کنم که این تغییرات کدام قسمت‌ها را تحت تاثیر قرار می‌دهند، کجا به هم ریخت. من باید خودم سریع بتونم مشخص کنم با این تغییر جدید چه قسمت‌هایی به هم ریخته تا اینکه دو روز بعد زنگ بزنند: «باز جایی رو تغییر دادی، یکجای دیگر کار نمی‌کنه!»

2) دستیابی به کنترل بیشتر بر روی اجزای فریم ورک
در طراحی ASP.NET MVC همه‌جا interface ها قابل مشاهد هستند. همین مساله به معنای افزونه پذیری اکثر قطعات تشکیل دهنده ASP.NET MVC است؛ برخلاف ASP.NET web forms. برای مثال تابحال چندین view engine، routing engine و غیره توسط برنامه نویس‌های مستقل برای ASP.NET MVC طراحی شده‌اند که هیچکدام با ASP.NET web forms میسر نیست. برای مثال از view engine پیش فرض آن خوشتان نمی‌آید؟ عوضش کنید! سیستم اعتبار سنجی توکار آن‌را دوست ندارید؟ آن‌را با یک نمونه بهتر تعویض کنید و الی آخر ...
به علاوه طراحی بر اساس interface ها یک مزیت دیگر را هم به همراه دارد و آن هم ساده سازی mocking (تقلید) آن‌ها است جهت ساده سازی نوشتن آزمون‌های واحد.

3) سرعت بیشتر اجرا
ASP.NET MVC یک سری از قابلیت‌های ذاتی ASP.NET web forms را مانند ViewState حذف کرده است. اگر وب را جستجو کنید، برنامه نویس‌های ASP.NET web forms مدام از این مساله شکایت دارند و راه‌ حل‌های مختلفی را جهت حذف یا فشرده سازی آن ارائه می‌دهند. ViewState در ابتدای امر جهت شبیه سازی محیط دسکتاپ در وب درنظر گرفته شده بود و مهاجرت ساده‌تر برنامه نویس‌های VB6 به وب، اما واقعیت این است که اگر یک برنامه نویس ASP.NET web forms به اندازه آن توجهی نداشته باشد، ممکن است حجم آن در یک صفحه پیچیده تا 500 کیلوبایت یا بیشتر هم برسد. همین مساله بر روی سرعت دریافت و اجرا تاثیر گذار خواهد بود.

4) کنترل‌های ASP.NET web forms آنچنان آش دهن‌سوزی هم نیستند!
خوب، ViewState حذف شده، بنابراین اکثر کنترل‌های ASP.NET web forms هم کاربرد آنچنانی در ASP.NET MVC نخواهند داشت؛ اما واقعیت این است که اکثر اوقات اگر شروع به سفارشی سازی یک کنترل توکار ASP.NET web forms کنید تا مطابق نیازهای کاری شما رفتار کند، پس از مدتی به یک کنترل کاملا از نو بازنویسی شده خواهید رسید! بنابراین در ابتدای امر تا 80 درصد کار اینطور به نظر می‌رسد که به عجب سرعت بالایی در توسعه دست یافته‌ایم، اما هنگامیکه قرار است این 20 درصد پایانی را پر کنیم، به این نتیجه خواهیم رسید که این کنترل‌ها با این وضع ابتدایی که دارند قابل استفاده نیستند و نیاز به دستکاری قابل ملاحظه‌ای دارند تا نیازهای واقعی کاری را برآورده کنند.

5) کنترل کامل بر روی HTML نهایی تولیدی
اگر علاقمند به کار با jQuery باشید، مدام نیاز خواهید تا با ID کنترل‌ها و عناصر صفحه کار کنید. پیشتر ASP.NET web forms این ID را یک طرفه و به صورت مقدار منحصربفردی تولید می‌کرد که جهت کار با فریم ورک‌های جاوا اسکریپتی عموما مشکل ساز بود. البته ASP.NET web forms در نگارش‌های جدید خود مشکل عدم امکان مقدار دهی ClientId سفارشی را برای کنترل‌های وب خود برطرف کرده است و این مورد را می‌توان دستی هم تنظیم کرد ولی در کل باز هم آنچنان کنترلی رو خروجی HTML نهایی کنترل‌های تولیدی نیست مگر اینکه مانند مورد چهارم یاد شده یک کنترل را از صفر بازنویسی کنید!
همچنین اگر باز هم بیشتر با jQuery و ASP.NET web forms کار کرده باشید می‌دانید که jQuery آنچنان سنخیتی با ViewState و Postback وب فرم‌ها ندارد و همین مساله عموما مشکل‌زا است. علاوه بر آن اخیرا مایکروسافت توسعه ASP.NET Ajax خود را تقریبا در حالت تعلیق و واگذار شده به شرکت‌های ثالث درآورده است و توصیه آن‌ها استفاده از jQuery Ajax است. اینجا است که مدل ASP.NET MVC سازگاری کاملی را با jQuery Ajax دارد هم از لحاظ نبود ViewState و هم از جنبه‌ی کنترل کامل بر روی markup نهایی تولیدی.
یا برای مثال خروجی پیش فرض یک GridView، جدول HTML ایی است که این روزها همه‌جا علیه آن صحبت می‌شود. البته یک سری آداپتور CSS friendly برای اکثر این کنترل‌ها موجود است و ... باز هم دستکاری بیش از حد کنترل‌های پیش فرض جهت رسیدن به خروجی دلخواه. تمام این‌ها را در ASP.NET MVC می‌شود با معادل‌های بسیار باکیفیت افزونه‌های jQuery جایگزین کرد و از همه مهم‌تر چون ViewState و مفاهیمی مانند PostBack حذف شده، استفاده از این افزونه‌ها مشکل ساز نخواهد بود.

6) استفاده از امکانات جدید زبان‌های دات نتی
طراحی اصلی ASP.NET web forms مربوط است به دوران دات نت یک؛ زمانیکه نه Generics وجود داشت، نه LINQ و نه آنچنان مباحث TDD یا استفاده از ORMs متداول بود. برای مثال شاید ایجاد یک strongly typed web form الان کمی دور از ذهن به نظر برسد، زمانیکه اصل آن بر مبنای بکارگیری گسترده datatable و dataset بوده است (با توجه به امکانات زبان‌های دات نتی در آن دوران). بنابراین اگر علاقمند هستید که این امکانات جدید را بکاربگیرید، ASP.NET MVC برای استفاده از آن‌ها طراحی شده است!

7) از ASP.NET web forms ساده‌تر است
طراحی ASP.NET MVC بر اساس ایده Convention over configuration است. به این معنا که اجزای آن بر اساس یک سری قرار داد در کنار هم مشغول به کار هستند. مشخص است View باید کجا باشد، نام کنترلرها چگونه باید تعیین شوند و قرار داد مرتبط به آن چیست، مدل باید کجا قرار گیرد، قرار داد پردازش آدرس‌های صفحات سایت به چه نحوی است و الی آخر. خلاصه در بدو امر با یک فریم ورک حساب شده که شما را در مورد نحوه استفاده صحیح از آن راهنمایی می‌کند، مواجه هستید.
به همین ترتیب هر پروژه MVC دیگری را هم که مشاهده کنید، سریع می‌توانید تشخیص دهد قراردادهای بکارگرفته شده در آن چیست. بنابراین اگر قرار است ASP.NET را امروز شروع کنید و هیچ سابقه‌ای هم از وب فرم‌ها ندارید، یک راست با ASP.NET MVC شروع کنید.

8) محدود به پیاده سازی مایکروسافت نیست
پیاده سازی‌های مستقلی هم از ASP.NET MVC توسط اشخاص و گروه‌های خارج از مایکروسافت وجود دارد: ^، ^، ^، ^ و ...


و در پایان یکی دیگر از دلایل سوئیچ به ASP.NET MVC ، «یاد گرفتن یک چیز جدید است» یا به عبارتی فرا گرفتن یک روش دیگر برای حل مسایل، هیچگاه ضرری را به همراه نخواهد داشت که هیچ، بلکه باعث بازتر شدن میدان دید نیز خواهد گردید.


یک دیدگاه دیگر
ASP.NET MVC برای شما مناسب نخواهد بود اگر ...
1) با پلی‌مرفیزم مشکل دارید.
ASP.NET MVC پر است از interfaces، abstract classes، virtual methods و امثال آن. بنابراین اگر تازه کار هستید، ابتدا باید مفاهیم شیءگرایی را تکمیل کنید.

2) اگر نمی‌توانید فریم ورک خودتون رو بر پایه ASP.NET MVC بنا کنید!
ASP.NET MVC برخلاف وب فرم‌ها به همراه آنچنان تعداد بالایی کنترل و افزونه از پیش مهیا شده نیست. در بدو امر شما فقط یک سری url helper، html helper و ajax helper ساده را خواهید دید؛ این نقطه ضعف ASP.NET MVC نیست. عمدا به این نحو طراحی شده است. همانطور که عنوان شد اکثر اجزای این فریم ورک قابل تعویض است. بنابراین دست شما را باز گذاشته است تا با پیاده سازی این اینترفیس‌ها، امکانات جدیدی را خلق کنید. البته پس از این چندین و چند سال که از ارائه آن می‌گذرد، به اندازه کافی افزونه برای ASP.NET MVC طراحی شده است که به هیچ عنوان احساس کمبود نکنید یا اینکه نیازی هم نداشته باشید تا آنچنان فریم ورک خاصی را بر پایه ASP.NET MVC تهیه کنید. برای مثال پروژه MvcContrib موجود است یا شرکت telerik یک مجموعه سورس باز کامل مخصوص ASP.NET MVC را ارائه داده است و الی آخر.

3) اگر نمی‌توانید از کتابخانه‌های سورس باز استفاده کنید.
همانطور که عنوان شد ASP.NET MVC به همراه کوهی از کنترل‌ها ارائه نشده است. اکثر افزونه‌های آن سورس باز هستند و کار با آن‌ها هم دنیای خاص خودش را دارد. چگونه باید کتابخانه‌های مناسب را پیدا کرد، کجا سؤال پرسید، کجا باگ گزارش داد، چگونه مشارکت کرد و غیره. خلاصه منتظر یک بسته شکیل حاضر و آماده نباید بود. خود ASP.NET MVC هم تحت مجوز MSPL به صورت سورس باز در دسترس است.


و یک نکته تکمیلی
مایکروسافت مدتی است شروع کرده به پرورش و زمزمه ایده «یک ASP.NET واحد». به عبارتی قصد دارند در یکی دو نگارش بعد، این دو (وب فرم و MVC) را یکی کنند. هم اکنون اگر مطالب وبلاگ‌ها را مطالعه کنید زیرساخت آن به نام ASP.NET Web API آماده شده است و در مرحله بتا است. نکته جالب اینجا است که این Web API امکان تعریف یکپارچه و مستقیم کنترلر‌های MVC را در وب فرم‌ها میسر می‌کند. ولی باز هم نام آن Controller است یعنی جزئی از ASP.NET MVC و کسی می‌تواند از آن استفاده کند که با MVC‌ مشکلی نداشته باشد. بنابراین یادگیری MVC هیچ ضرری نخواهد داشت و جای دوری نخواهد رفت!



مطالب
آموزش ایجاد برنامه های چند زبانه در WPF
با گسترش استفاده از کامپیوتر در بسیاری از امور روزمره انسان‌ها سازگار بودن برنامه‌ها با سلیقه کاربران به یکی از نیاز‌های اصلی برنامه‌های کامپیوتری تبدیل شده است. بدون شک زبان و فرهنگ یکی از مهم‌ترین عوامل در ایجاد ارتباط نزدیک بین برنامه و کاربر به شمار می‌رود و نقشی غیر قابل انکار در میزان موفقیت یک برنامه به عهده دارد. از این رو در این نوشته تلاش بر آن است تا یکی از ساده‌ترین و در عین حال کارا‌ترین راه‌های ممکن برای ایجاد برنامه‌های چند زبانه با استفاده از تکنولوژی WPF آموزش داده شود.

مروری بر روش‌های موجود
همواره روش‌های مختلفی برای پیاده سازی یک ایده در دنیای نرم افزار وجود دارد که هر روش را می‌توان بر حسب نیاز مورد استفاده قرار داد. در برنامه‌های مبتنی بر WPF معمولا از دو روش عمده برای این منظور استفاده می‌شود:

1-استفاده از فایل‌های resx
در این روش که برای Win App نیز استفاده می‌شود، اطلاعات مورد نیاز برای هر زبان به شکل جدول هایی دارای کلید و مقدار در داخل یک فایل .resx نگهداری می‌شود و در زمان اجرای برنامه بر اساس انتخاب کاربر اطلاعات زبان مورد نظر از داخل فایل  resx خوانده شده و نمایش داده می‌شود. یکی از ضعف هایی که این روش در عین ساده بودن دارد این است که همه اطلاعات مورد نیاز داخل assembly اصلی برنامه قرار می‌گیرد و امکان افزودن زبان‌های جدید بدون تغییر دادن برنامه اصلی ممکن نخواهد بود.

2-استفاده از فایل‌های csv که به فایل‌های dll تبدیل می‌شوند
در این روش با استفاده از ابزار‌های موجود در کامپایلر WPF برای هر کنترل یک property به نام Uid ایجاد شده و مقدار دهی می‌شود. سپس با ابزار دیگری ( که جزو ابزار‌های کامپایلر محسوب نمی‌شود ) از فایل csproj پروژه یک خروجی اکسل با فرمت csv ایجاد می‌شود که شامل Uid‌های کنترل‌ها و مقادیر آن‌ها است. پس از ترجمه متون مورد نظر به زبان مقصد با کمک ابزار دیگری فایل اکسل مورد نظر به یک net assembly تبدیل می‌شود و داخل پوشه ای با نام culture استاندارد ذخیره می‌شود. ( مثلا برای زبان فارسی نام پوشه fa-IR خواهد بود ). زمانی که برنامه اجرا می‌شود بر اساس culture ای که در سیستم عامل انتخاب شده است و در صورتی که برای آن culture فایل dll ای موجود باشد، زبان مربوط به آن culture را load خواهد کرد. با وجود این که این روش مشکل روش قبلی را ندارد و بیشتر با ویژگی‌های WPF سازگار است اما پروسه ای طولانی برای انجام کار‌ها دارد و به ازای هر تغییری باید کل مراحل هر بار تکرار شوند. همچنین مشکلاتی در نمایش برخی زبان‌ها ( از جمله فارسی ) در این روش مشاهده شده است.

روش سوم!
روش سوم اما کاملا بر پایه WPF و در اصطلاح WPF-Native می‌باشد. ایده از آنجا ناشی شده است که برای ایجاد skin در برنامه‌های WPF استفاده می‌شود. در ایجاد برنامه‌های Skin-Based به این شیوه عمل می‌شود که skin‌های مورد نظر به صورت style هایی در داخل ResourceDictionary ‌ها قرار می‌گیرند. سپس آن ResourceDictionary به شکل dll کامپایل می‌شود. در برنامه اصلی نیز همه کنترل‌ها style هایشان را به شکل dynamic resource از داخل یک ResourceDictionary مشخص شده load می‌کنند. حال کافی است برای تغییر skin فعلی، ResourceDictionary  مورد نظر از dll مشخص load شود و ResourceDictionary ای که در حال حاضر در برنامه از آن استفاده می‌شود با ResourceDictionary ای که load شده جایگزین شود. کنترل‌ها مقادیر جدید را از ResourceDictionary جدید به شکل کاملا خودکار دریافت خواهند کرد.
به سادگی می‌توان از این روش برای تغییر زبان برنامه نیز استفاده کرد با این تفاوت که این بار، به جای Style ها، String‌های زبان‌های مختلف را درون resource‌ها نگهداری خواهیم کرد.

یک مثال ساده
در این قسمت نحوه پیاده سازی این روش با ایجاد یک نمونه برنامه ساده که دارای دو زبان انگلیسی و فارسی خواهد بود آموزش داده می‌شود.
ابتدا یک پروژه WPF Application در Visual Studio 2010 ایجاد کنید. در MainWindow سه کنترل Button قرار دهید و یک ComboBox که قرار است زبان‌های موجود را نمایش دهد و با انتخاب یک زبان، نوشته‌های درون Button‌ها متناسب با آن تغییر خواهند کرد.

توجه داشته باشید که برای Button‌ها نباید به صورت مستقیم مقداری به Content شان داده شود. زیرا مقدار مورد نظر از داخل ResourceDictionary که خواهیم ساخت به شکل dynamic گرفته خواهد شد. پس در این مرحله یک ResourceDictionary به پروژه اضافه کرده و در آن resource هایی به شکل string ایجاد می‌کنیم. هر resource دارای یک Key می‌باشد که بر اساس آن، Button مورد نظر، مقدار آن Resource را load خواهد کرد. فایل ResourceDictionary را
Culture_en-US.xaml نامگذاری کنید و مقادیر مورد نظر را به آن اضافه نمایید.  

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <system:String x:Key="button1">Hello!</system:String>
    <system:String x:Key="button2">How Are You?</system:String>
    <system:String x:Key="button3">Are You OK?</system:String>
 
</ResourceDictionary>

دقت کنید که namespace ای که کلاس string در آن قرار دارد به فایل xaml اضافه شده است و پیشوند system به آن نسبت داده شده است.

با افزودن یک ResourceDictionary به پروژه، آن ResourceDictionary به MergedDictionary کلاس App اضافه می‌شود. بنابراین فایل App.xaml به شکل زیر خواهد بود:

<Application x:Class="BeRMOoDA.WPF.LocalizationSample.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
 
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Culture_en-US.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
 
    </Application.Resources>
</Application>

برای اینکه بتوانیم محتوای Button‌های موجود را به صورت داینامیک و در زمان اجرای برنامه، از داخل Resource‌ها بگیریم، از DynamicResource استفاده می‌کنیم.

<Button Content="{DynamicResource ResourceKey=button1}" />
<Button Content="{DynamicResource ResourceKey=button2}" />
<Button Content="{DynamicResource ResourceKey=button3}" />

بسیار خوب! اکنون باید شروع به ایجاد یک ResourceDictionary برای زبان فارسی کنیم و آن را به صورت یک فایل dll کامپایل نماییم.
برای این کار یک پروژه جدید در قسمت WPF از نوع User control ایجاد می‌کنیم و نام آن را Culture_fa-IR_Farsi قرار می‌دهیم. لطفا شیوه نامگذاری را رعایت کنید چرا که در ادامه به آن نیاز خواهیم داشت.
پس از ایجاد پروژه فایل UserControl1.xaml را از پروژه حذف کنید و یک ResourceDictionary با نام Culture_fa-IR.xaml اضافه کنید. محتوای آن را پاک کنید و محتوای فایل Culture_en-US.xaml را از پروژه قبلی به صورت کامل در فایل جدید کپی کنید. دو فایل باید ساختار کاملا یکسانی از نظر key برای Resource‌های موجود داشته باشند. حالا زمان ترجمه فرا رسیده است! رشته‌های دلخواه را ترجمه کنید و پروژه را build نمایید. 
پس از ترجمه فایل Culture_fa-IR.xaml به شکل زیر خواهد بود:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Culture_fa-IR_Farsi.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <system:String x:Key="button1">سلام!</system:String>
    <system:String x:Key="button2">حالت چطوره؟</system:String>
    <system:String x:Key="button3">خوبی؟</system:String>
</ResourceDictionary>
خروجی این پروژه یک فایل با نام Culture_fa-IR_Farsi.dll خواهد بود که حاوی یک ResourceDictionary برای زبان فارسی می‌باشد.

در ادامه میخواهیم راهکاری ارئه دهیم تا بتوان فایل‌های dll مربوط به زبان‌ها را در زمان اجرای برنامه اصلی، load کرده و نام زبان‌ها را در داخل ComboBox ای که داریم نشان دهیم. سپس با انتخاب هر زبان در ComboBox، محتوای Button‌ها بر اساس زبان انتخاب شده تغییر کند.
برای سهولت کار، نام فایل‌ها را به گونه ای انتخاب کردیم که بتوانیم ساده‌تر به این هدف برسیم. نام هر فایل از سه بخش تشکیل شده است:
Culture_[standard culture notation]_[display name for this culture].dll
یعنی اگر فایل Culture_fa-IR_Farsi.dll را در نظر بگیریم، Culture نشان دهنده این است که این فایل مربوط به یک culture می‌باشد. fa-IR نمایش استاندارد culture برای کشور ایران و زبان فارسی است و Farsi هم مقداری است که می‌خواهیم در ComboBox برای این زبان نمایش داده شود.
پوشه ای با نام Languages در کنار فایل اجرایی برنامه اصلی ایجاد کنید و فایل Culture_fa-IR_Farsi.dll را درون آن کپی کنید. تصمیم داریم همه dll‌های مربوط به زبان‌ها را داخل این پوشه قرار دهیم تا مدیریت آن‌ها ساده‌تر شود. 
برای مدیریت بهتر فایل‌های مربوط به زبان‌ها یک کلاس با نام CultureAssemblyModel خواهیم ساخت که هر instance از آن نشانگر یک فایل زبان خواهد بود. یک کلاس با این نام به پروژه اضافه کنید و property‌های زیر را در آن تعریف نمایید:

public class CultureAssemblyModel
    {
        //the text will be displayed to user as language name (like Farsi)
        public string DisplayText { get; set; }
        //name of .dll file (like Culture_fa-IR_Farsi.dll)
        public string Name { get; set; }
        //standar notation of this culture (like fa-IR)
        public string Culture { get; set; }
        //name of resource dictionary file inside the loaded .dll (like Culture_fa-IR.xaml)
        public string XamlFileName { get; set; }
    }
اکنون باید لیست culture‌های موجود را از داخل پوشه languages خوانده و نام آنها را در ComboBox نمایش دهیم.
برای خواندن لیست culture‌های موجود، لیستی از CultureAssmeblyModel‌ها ایجاد کرده و با استفاده از متد LoadCultureAssmeblies، آن را پر می‌کنیم.

//will keep information about loaded assemblies
public List<CultureAssemblyModel> CultureAssemblies { get; set; }
 
//loads assmeblies in languages folder and adds their info to list
 void LoadCultureAssemblies()
 {
      //we should be sure that list is empty before adding info (do u want to add some cultures more than one? of course u dont!)
      CultureAssemblies.Clear();
      //creating a directory represents applications directory\languages
      DirectoryInfo dir = new DirectoryInfo(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\languages");
      //getting all .dll files in the language folder and its sub dirs. (who knows? maybe someone keeps each culture file in a seperate folder!)
      var assemblies = dir.GetFiles("*.dll", SearchOption.AllDirectories);
      //for each found .dll we will create a model and set its properties and then add to list  for (int i = 0; i < assemblies.Count(); i++)
      {
string name = assemblies[i].Name;
  CultureAssemblyModel model = new CultureAssemblyModel() { DisplayText = name.Split('.', '_')[2], Culture = name.Split('.', '_')[1], Name = name  , XamlFileName =name.Substring(0, name.LastIndexOf(".")) + ".xaml" }; CultureAssemblies.Add(model); } }
پس از دریافت اطلاعات culture‌های موجود، زمان نمایش آن‌ها در ComboBox است. این کار بسیار ساده است، تنها کافی است ItemsSource آن را با لیستی از CultureAssmeblyModel‌ها که ساختیم، مقدار دهی کنیم.

comboboxLanguages.ItemsSource = CultureAssemblies;
البته لازم به ذکر است که برای نمایش فقط نام هر CultureAssemblyModel در ComboBox، باید ItemTemplate مناسبی برای ComboBox ایجاد کنیم. در مثال ما ItemTemplate به شکل زیر خواهد بود:

<ComboBox HorizontalAlignment="Left" Margin="10" VerticalAlignment="Top" MinWidth="100" Name="comboboxLanguages">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <Label Content="{Binding DisplayText}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
</ComboBox>
توجه داشته باشید که با وجود اینکه فقط نام را در ComboBox نشان می‌دهیم، اما باز هم هر آیتم از ComboBox یک instance از نوع CultureAssemblyModel می‌باشد.

در مرحله بعد، قرار است متدی بنویسیم که اطلاعات زبان انتخاب شده را گرفته و با جابجایی ResourceDictionary ها، زبان برنامه را تغییر دهیم.
متدی با نام LoadCulture در کلاس App ایجاد می‌کنیم که یک CultureAssemblyModel به عنوان ورودی دریافت کرده و ResourceDictionary داخل آن را load می‌کند و آن را با ResourceDictionary فعلی موجود در App.xaml جابجا می‌نماید.
با این کار، Button هایی که قبلا مقدار Content خود را از Resource‌های موجود دریافت می‌کردند، اکنون از Resource‌های جابجا شده خواهند گرفت و به این ترتیب زبان انتخاب شده بر روی برنامه اعمال می‌شود.

//loads selected culture
 public void LoadCulture(CultureAssemblyModel culture)
 {
     //creating a FileInfo object represents .dll file of selected cultur
     FileInfo assemblyFile = new FileInfo("languages\\" + culture.Name);
     //loading .dll into memory as a .net assembly
     var assembly = Assembly.LoadFile(assemblyFile.FullName);
     //getting .dll file name
     var assemblyName = assemblyFile.Name.Substring(0, assemblyFile.Name.LastIndexOf("."));
     //creating string represents structure of a pack uri (something like this: /{myassemblyname;component/myresourcefile.xaml}
     string packUri = string.Format(@"/{0};component/{1}", assemblyName, culture.XamlFileName);
     //creating a pack uri
     Uri uri = new Uri(packUri, UriKind.Relative);
     //now we have created a pack uri that represents a resource object in loaded assembly
     //and its time to load that as a resource dictionary (do u remember that we had resource dictionary in culture assemblies? don't u?)
     var dic = Application.LoadComponent(uri) as ResourceDictionary;
     dic.Source = uri;
     //here we will remove current merged dictionaries in our resource dictionary and add recently-loaded resource dictionary as e merged dictionary
     var mergedDics = this.Resources.MergedDictionaries;
     if (mergedDics.Count > 0)
          mergedDics.Clear();
     mergedDics.Add(dic);
 }
برای ارسال زبان انتخاب شده به این متد، باید رویداد SelectionChanged را برای ComboBox مدیریت کنیم:

void comboboxLanguages_SelectionChanged(object sender, SelectionChangedEventArgs e)
 {
     var selectedCulture = (CultureAssemblyModel)comboboxLanguages.SelectedItem;
     App app = Application.Current as App;
     app.LoadCulture(selectedCulture);
 }

کار انجام شد!
از مزیت‌های این روش می‌توان به WPF-Native بودن، سادگی در پیاده سازی، قابلیت load کردن هر زبان جدیدی در زمان اجرا بدون نیاز به کوچک‌ترین تغییر در برنامه اصلی و همچنین پشتیبانی کامل از نمایش زبان‌های مختلف از جمله فارسی اشاره کرد. 





نظرات مطالب
چگونگی گزارشگیری از Business Objects مانند List توسط StimulSoft
این روش بسیار زمانبر است؛ تصور کنید می‌خواهید از چندین جدول با تعداد فیلد‌های زیاد گزارش‌های مختلف تهیه کنید. اگر قرار به ایجاد دستی همه‌ی این فیلد‌ها در BO باشد که فاتحه وقت شما خوانده است و همچنین احتمال خطای شما در انتخاب نام و نوع فیلد بسیار خواهد بود.
برای انجام بهتر این کار در Stimul Report باید ابتدا لیست جنریک مورد نظر را به گزارش ارسال کنیم و سپس آن را در حالت Design نمایش داده و پس از ایجاد عناصر گزارش آن را در محل مورد نظر ذخیره نماییم. (لیست ارسالی به صورت خودکار در گزارش‌ساز نشان داده خواهد شد و تنها کاری که باید کنید گرفتن و کشیدن فیلدهای مورد نظر به داخل Data-Header-Footer ریپورت است).
برای مثال (با فرض استفاده از reportViewer):
stiReportMain.Dictionary.Report.BusinessObjectsStore.Clear();
reportViewer.Report.BusinessObjectsStore.Clear();
stiReportMain.RegBusinessObject("MyCategory", "documents", list);
stiReportMain.Design();
(کد فوق فقط برای طراحی گزارش است و باید یکبار اجرا شود).
پس از اجرای برنامه و طراحی گزارش مورد نظر آن را ذخیره می‌کنیم و برای استفاده کافی‌است از کد زیر استفاده کنیم:
stiReportMain.Dictionary.Report.BusinessObjectsStore.Clear();
reportViewer.Report.BusinessObjectsStore.Clear();
stiReportMain.RegBusinessObject("MyCategory", "documents", list);
stiReportMain.Dictionary.SynchronizeBusinessObjects();
stiReportMain.Compile();
stiReportMain.RenderWithWpf(true); //Or Render();
نکته ۱: documents لیست جنریک دریافتی از EF یا هر ORM دیگست.
نکته ۲:در صورتی که از شی StiReport استفاده کنید حتی نیاز به دادن آدرس فایل گزارش نخواهید داشت و فایل گزارش درون برنامه شما ذخیره خواهد شد. برای ویرایش آن نیز می‌توانید از فلش ظاهر شده کنار StiReport آن را ویرایش و مجددا ذخیره کنید.