مطالب
معرفی پروژه Orchard
معرفی پروژه Orchard:
 سیستم مدیریت محتوای Orchard توسط مایکروسافت در ژانویه سال 2011 همراه با ASP.NET MVC 3, IIS Express, SQL CE 4 ,فریم ورک Web Farm و WebMatrix ارائه شد. هدف تمامی این پروژه‌ها ایجاد قابلیتی برای توسعه آسان برنامه‌های تحت وب در محیط ویندوز بود. همانطور که PHP دارای ابزارهای مناسبی برای این منظور است. با ارائه این ابزارها مایکروسافت درخواست برنامه نویسان را برای ساده سازی تجربه توسعه وب اجابت کرد. پروژه Orchard متعلق به Outercurve Foundation (به ندرت CodePlex Foundation نیز شناخته می‌شود) است که توسط مایکروسافت پشتیبانی می‌شود. Outercurve Foundation یک سازمان غیر انتفاعی است که هدف آن تشویق و حمایت از پروژه‌های متنی بازی نظیر Orchad و یا toolkit معروف ASP.NET MVC یعنی MVC Contrib است. مایکروسافت به صورت رسمی از Orchad پشتیبانی نمی‌کند اما در حال حاضر برنامه نویسانی را جهت توسعه این سیستم استخدام کرده است.

برای پروژه Orchad سه هدف تعیین شده است :
1)فراهم نمودن و به اشتراک گذاری یک مجموعه کامپوننت جهت استفاده در برنامه‌های ASP.NET
2)ساخت تعدادی برنامه‌ی مرجع با استفاده از کامپوننت‌های فوق
3)ساخت انجمن هایی برای پشتیبانی از این کامپوننت‌ها و یا برنامه‌های مرجع

 در حال حاضر Orchard بیشتر به عنوان یک سکو (platform) برای ساخت وب سایت‌های ایجاد محتوی استفاده می‌شود آنچه در Orchard حائز اهمیت است ذکر این نکته است که این سیستم به طور کامل با استفاده از ابزار‌های متن باز نوشته شده است. Orchard از ASP.NET MVC 3.0 به همراه View engine جدید و فوق العاده آن یعنی Razor بهره می‌برد. همچنین این پروژه وابستگی زیادی به دیگر ابزارهای متن باز نظیر NHibernate برای دسترسی به داده‌ها و همچنین Autofac برای dependency injection دارد شایان ذکر است که مجوز استفاده از Orchard تحت لیسانس BSD است.

طبق اعلام وب سایت رسمی این پروژه در عرض حدود یک سالی که از ارائه این CMS می‌گذرد بیش از یک میلیون بار دانلود  و بیش از 300 ماژول و تم برای آن ساخته شده است که در گالری آن در دسترس می‌باشد. Orchard به صورت ریلیز‌های جزئی ارائه می‌شود و جدیدترن نسخه آن در هنگام نوشتن این متن 1.5.1 می‌باشد.

اما چرا به یک CMS دات نتی دیگر نیاز است ؟

تعداد زیادی سیستم‌های مدیریت محتوای تجاری و یا متن باز در طول این سال‌ها با استفاده از دات نت ارائه شده اند. (DotNetNuke (DNN بدون تردید یک از معروفترین و قدرتمندترین آن‌ها است. این CMS در ابتدا با VB.NET نوشته شد و این رویه تا مدت‌ها ادامه داشت تا اینکه در نسخه اخیر به #C تغییر کرد. اگرچه DNN و همچنین پروژه متن باز دیگری به نام Umbraco هر دو محبوب هستند اما با استفاده از WebForm‌ها پیاده سازی شده اند( البته Umbraco در نسخه 5 قصد داشت که از ASP.NET MVC استفاده کند اما علی رغم در دسترس قرار گرفتن این نسخه ظاهرا تیم Umbraco برای تمرکز بیشتر روی نسخه وب فرمی, تصمیم ندارند این پروژه را ادامه دهند.) امروزه وب فرم‌ها همانند گذشته محبوب نیستند به همین دلیل رغبت کمتری برای استفاده از این CMS‌ها  نسبت به قبل وجود دارد. با توجه به شواهد موجود بسیاری از برنامه نویسان دات نتی به سمت ASP.NET MVC مهاجرت کرده اند به همین دلیل سیستم Orchard بر مبنای این تکنولوژی نسبتا جدید دات نت پیاده شده است. با استفاده از Orchard می‌توان یک وب سایت با عملکرد بسیار بالا بدون نوشتن حتی یک خط کد ایجاد نمود. اما مانند هر سیستم مدیریت محتوی دیگری اگر بخواهیم به آن قابلیت هایی را اضافه کنیم که به صورت پیش فرض در آن نیست باید با ساختار آن به خوبی آشنا شویم و همچنین بر ابزارهای مورد نیاز این کار نیز احاطه داشته باشیم. برای دریافت اطلاعات بیشتر می‌توانید به وب سایت رسمی این پروژه در اینجا مراجعه کنید
مطالب دوره‌ها
شروع به کار با RavenDB
پیشنیاز‌های بحث
- مروری بر مفاهیم مقدماتی NoSQL
- رده‌ها و انواع مختلف بانک‌های اطلاعاتی NoSQL
- چه زمانی بهتر است از بانک‌های اطلاعاتی NoSQL استفاده کرد و چه زمانی خیر؟

لطفا یکبار این پیشنیازها را پیش از شروع به کار مطالعه نمائید؛ چون بسیاری از مفاهیم پایه‌ای و اصطلاحات مرسوم دنیای NoSQL در این سه قسمت بررسی شده‌اند و از تکرار مجدد آن‌ها در اینجا صرفنظر خواهد شد.


RavenDB چیست؟

RavenDB یک بانک اطلاعاتی سورس باز NoSQL سندگرای تهیه شده با دات نت  است. ساختار کلی بانک‌های اطلاعاتی NoSQL سندگرا، از لحاظ نحوه ذخیره سازی اطلاعات، با بانک‌های اطلاعاتی رابطه‌ای متداول، کاملا متفاوت است. در اینگونه بانک‌های اطلاعاتی، رکوردهای اطلاعات، به صورت اشیاء JSON ذخیره می‌شوند. اشیاء JSON یا JavaScript Object Notation بسیار شبیه به anonymous objects سی شارپ هستند. JSON روشی است که توسط آن JavaScript اشیاء خود را معرفی و ذخیره می‌کند. به عنوان رقیبی برای XML مطرح است؛ نسبت به XML اندکی فشرده‌تر بوده و عموما دارای اسکیمای خاصی نیست و در بسیاری از اوقات تفسیر المان‌های آن به مصرف کننده واگذار می‌شود.
در JSON عموما سه نوع المان پایه مشاهده می‌شوند:
- اشیاء که به صورت {object} تعریف می‌شوند.
- مقادیر "key":"value" که شبیه به نام خواص و مقادیر آن‌ها در دات نت هستند.
- و آرایه‌ها به صورت [array]
همچنین ترکیبی از این سه عنصر یاد شده نیز همواره میسر است. برای مثال، یک key مشخص می‌تواند دارای مقداری حاوی یک آرایه یا شیء نیز باشد.
JSON: JavaScript Object Notation

document :{ 
   key: "Value",
   another_key: {
      name: "embedded object"
   },
   some_date: new Date(),
   some_number: 12
}

C# anonymous object

var Document = new { 
   Key= "Value",
   AnotherKey= new {
      Name = "embedded object"
   },
   SomeDate = DateTime.Now(),
   SomeNumber = 12
};
به این ترتیب می‌توان به یک ساختار دلخواه و بدون اسکیما، از هر سند به سند دیگری رسید. اغلب بانک‌های اطلاعاتی سندگرا، اینگونه اسناد را در زمان ذخیره سازی، به یک سری binary tree تبدیل می‌کنند تا تهیه کوئری بر روی آن‌ها بسیار سریع شود. مزیت دیگر استفاده از JSON، سادگی و سرعت بالای Serialize و Deserialize اطلاعات آن برای ارسال به کلاینت‌ها و یا دریافت آن‌ها است؛ به همراه فشرده‌تر بودن آن نسبت به فرمت‌های مشابه دیگر مانند XML.


یک نکته مهم
اگر پیشنیازهای بحث را مطالعه کرده باشید، حتما بارها با این جمله که دنیای NoSQL از تراکنش‌ها پشتیبانی نمی‌کند، برخورد داشته‌اید. این مطلب در مورد RavenDB صادق نیست و این بانک اطلاعاتی NoSQL خاص، از تراکنش‌ها پشتیبانی می‌کند. RavenDB در Document store خود ACID عملکرده و از تراکنش‌ها پشتیبانی می‌کند. اما تهیه ایندکس‌های آن بر مبنای مفهوم عاقبت یک دست شدن عمل می‌کند.


مجوز استفاده از RavenDB

هرچند مجموعه سرور و کلاینت RavenDB سورس باز هستند، اما این مورد به معنای رایگان بودن آن نیست. مجوز استفاده از RavenDB نوع خاصی به نام AGPL است. به این معنا که یا کل کار مشتق شده خود را باید به صورت رایگان و سورس باز ارائه دهید و یا اینکه مجوز استفاده از آن‌را برای کارهای تجاری بسته خود خریداری نمائید. نسخه استاندارد آن نزدیک به هزار دلار است و نسخه سازمانی آن نزدیک به 2800 دلار به ازای هر سرور.


شروع به نوشتن اولین برنامه کار با RavenDB

ابتدا یک پروژه کنسول ساده را آغاز کنید. سپس کلاس‌های مدل زیر را به آن اضافه نمائید:
using System.Collections.Generic;

namespace RavenDBSample01.Models
{
    public class Question
    {
        public string By { set; get; }
        public string Title { set; get; }
        public string Content { set; get; }

        public List<Comment> Comments { set; get; }
        public List<Answer> Answers { set; get; }

        public Question()
        {
            Comments = new List<Comment>();
            Answers = new List<Answer>();
        }
    }
}

namespace RavenDBSample01.Models
{
    public class Comment
    {
        public string By { set; get; }
        public string Content { set; get; }
    }
}

namespace RavenDBSample01.Models
{
    public class Answer
    {
        public string By { set; get; }
        public string Content { set; get; }
    }
}
سپس به کنسول پاور شل نیوگت در ویژوال استودیو مراجعه کرده و دستورات ذیل را جهت افزوده شدن وابستگی‌های مورد نیاز RavenDB، صادر کنید:
PM> Install-Package RavenDB.Client
PM> Install-Package RavenDB.Server
به این ترتیب بسته‌های کلاینت (مورد نیاز جهت برنامه نویسی) و سرور RavenDB به پروژه جاری اضافه خواهند شد (نگارش 2.5 در زمان نگارش این مطلب؛ جمعا نزدیک به 75 مگابایت).
اکنون به پوشه packages\RavenDB.Server.2.5.2700\tools مراجعه کرده و برنامه Raven.Server.exe را اجرا کنید تا سرور RavenDB شروع به کار کند. این سرور به صورت پیش فرض بر روی پورت 8080 اجرا می‌شود. از این جهت که در RavenDB نیز همانند سایر Document Stores مطرح، امکان دسترسی به اسناد از طریق REST API و Urlها وجود دارد.
البته لازم به ذکر است که RavenDB در 4 حالت برنامه کنسول (همین سرور فوق)، نصب به عنوان یک سرویس ویندوز NT، هاست شدن در IIS و حالت مدفون شده یا Embedded قابل استفاده است.

خوب؛ همین اندازه برای برپایی اولیه RavenDB کفایت می‌کند.
using Raven.Client.Document;
using RavenDBSample01.Models;

namespace RavenDBSample01
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var store = new DocumentStore
                               {
                                   Url = "http://localhost:8080"
                               }.Initialize())
            {
                using (var session = store.OpenSession())
                {
                    session.Store(new Question
                    {
                        By = "users/Vahid",
                        Title = "Raven Intro",
                        Content = "Test...."
                    });

                    session.SaveChanges();
                }
            }
        }
    }
}
اکنون کدهای برنامه کنسول را به نحو فوق برای ذخیره سازی اولین سند خود، تغییر دهید.
کار با ایجاد یک DocumentStore که به آدرس سرور اشاره می‌کند و کار مدیریت اتصالات را برعهده دارد، شروع خواهد شد. اگر نمی‌خواهید Url را درون کدهای برنامه مقدار دهی کنید، می‌توان از فایل کانفیگ برنامه نیز برای این منظور کمک گرفت:
<connectionStrings>
   <add name="ravenDB" connectionString="Url=http://localhost:8080"/>
</connectionStrings>
در این حالت باید خاصیت ConnectionStringName شیء DocumentStore را مقدار دهی نمود.
 سپس با ایجاد Session در حقیقت یک Unit of work آغاز می‌شود که درون آن می‌توان انواع و اقسام دستورات را صادر نمود و سپس در پایان کار، با فراخوانی SaveChanges، این اعمال ذخیره می‌گردند. در RavenDB یک سشن باید طول عمری کوتاه داشته باشد و اگر تعداد عملیاتی که در آن صادر کرده‌اید، زیاد است با خطای زیر متوقف خواهید شد:
 The maximum number of requests (30) allowed for this session has been reached.
البته این نوع محدودیت‌ها عمدی است تا برنامه نویس به طراحی بهتری برسد.

در یک برنامه واقعی، ایجاد DocumentStore یکبار در آغاز کار برنامه باید انجام گردد. اما هر سشن یا هر واحد کاری آن، به ازای تراکنش‌های مختلفی که باید صورت گیرند، بر روی این DocumentStore، ایجاد شده و سپس بسته خواهند شد. برای مثال در یک برنامه ASP.NET، در فایل Global.asax در زمان آغاز برنامه، کار ایجاد DocumentStore انجام شده و سپس به ازای هر درخواست رسیده، یک سشن RavenDB ایجاد و در پایان درخواست، این سشن آزاد خواهد شد.

برنامه را اجرا کنید، سپس به کنسول سرور RavenDB که پیشتر آن‌را اجرا نمودیم مراجعه نمائید تا نمایی از عملیات انجام شده را بتوان مشاهده کرد:
Raven is ready to process requests. Build 2700, Version 2.5.0 / 6dce79a Server started in 14,438 ms
Data directory: D:\Prog\RavenDBSample01\packages\RavenDB.Server.2.5.2700\tools\Database\System
HostName: <any> Port: 8080, Storage: Esent
Server Url: http://localhost:8080/
Available commands: cls, reset, gc, q
Request #   1: GET     -   514 ms - <system>   - 404 - /docs/Raven/Replication/Destinations
Request #   2: GET     -   763 ms - <system>   - 200 - /queries/?&id=Raven%2FHilo%2Fquestions&id=Raven%2FServerPrefixForHilo
Request #   3: PUT     -   185 ms - <system>   - 201 - /docs/Raven/Hilo/questions
Request #   4: POST    -   103 ms - <system>   - 200 - /bulk_docs
        PUT questions/1
زمانیکه سرور RavenDB در حالت دیباگ در حال اجرا باشد، لاگ کلیه اعمال انجام شده را در کنسول آن می‌توان مشاهده نمود. همانطور که مشاهده می‌کنید، یک کلاینت RavenDB با این بانک اطلاعاتی با پروتکل HTTP و یک REST API ارتباط برقرار می‌کند. برای نمونه، کلاینت در اینجا با اعمال یک HTTP Verb خاص به نام PUT، اطلاعات را درون بانک اطلاعاتی ذخیره کرده است. تبادل اطلاعات نیز با فرمت JSON انجام می‌شود.
عملیات PUT حتما نیاز به یک Id از پیش مشخص دارد و این Id، پیشتر در سطری که Hilo در آن ذکر شده (یکی از الگوریتم‌های محاسبه Id در RavenDB)، محاسبه گردیده است. برای نمونه در اینجا الگوریتم Hilo مقدار "questions/1" را به عنوان Id محاسبه شده بازگشت داده است.
در سطری که عملیات Post به آدرس bulk_docs سرور ارسال گردیده است، کار ارسال یکباره چندین شیء JSON برای کاهش رفت و برگشت‌ها به سرور انجام می‌شود.

و برای کوئری گرفتن مقدماتی از اطلاعات ثبت شده می‌توان نوشت:
 using (var session = store.OpenSession())
{
  var question1 = session.Load<Question>("questions/1");
  Console.WriteLine(question1.By);
}

نگاهی به بانک اطلاعاتی ایجاد شده

در همین حال که سرور RavenDB در حال اجرا است، مرورگر دلخواه خود را گشوده و سپس آدرس http://localhost:8080 را وارد نمائید. بلافاصله، کنسول مدیریتی تحت وب این بانک اطلاعاتی که با سیلورلایت نوشته شده است، ظاهر خواهد شد:


و اگر بر روی هر سطر اطلاعات دوبار کلیک کنید، به معادل JSON آن نیز خواهید رسید:


اینبار برنامه را به صورت زیر تغییر دهید تا روابط بین کلاس‌ها را نیز پیاده سازی کند:
using System;
using Raven.Client.Document;
using RavenDBSample01.Models;

namespace RavenDBSample01
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var store = new DocumentStore
                               {
                                   Url = "http://localhost:8080"
                               }.Initialize())
            {
                using (var session = store.OpenSession())
                {
                    var question = new Question
                    {
                        By = "users/Vahid",
                        Title = "Raven Intro",
                        Content = "Test...."
                    };                 
                    question.Answers.Add(new Answer
                    {
                         By = "users/Farid",
                         Content = "بررسی می‌شود"
                    });
                    session.Store(question);

                    session.SaveChanges();
                }

                using (var session = store.OpenSession())
                {
                    var question1 = session.Load<Question>("questions/1");
                    Console.WriteLine(question1.By);
                }
            }
        }
    }
}
در اینجا یک سؤال به همراه پاسخی به آن تعریف شده است. همچنین در مرحله بعد، نحوه کوئری گرفتن مقدماتی از اطلاعات را بر اساس Id سند مرتبط، مشاهده می‌کنید. چون یک Session، الگوی واحد کار را پیاده سازی می‌کند، اگر پس از Load یک سند، خواصی از آن‌را تغییر دهیم و در پایان Session متد SaveChanges فراخوانی شود، به صورت خودکار این تغییرات به بانک اطلاعاتی نیز اعمال خواهند شد (روش به روز رسانی اطلاعات). این مورد بسیار شبیه است به مباحث پایه ای Change tracking که در بسیاری از ORMهای معروف تاکنون پیاده سازی شده‌اند. روش حذف اطلاعات نیز به همین ترتیب است. ابتدا سند مورد نظر یافت شده و سپس متد session.Delete بر روی این شیء یافت شده فراخوانی گردیده و در پایان سشن باید SaveChanges جهت نهایی شدن تراکنش فراخوانی گردد.

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


نکته جالبی که در اینجا وجود دارد، عدم نیاز به join نویسی برای دریافت اطلاعات وابسته به یک شیء است. اگر سؤالی وجود دارد، پاسخ‌های به آن و یا سایر نظرات، یکجا داخل همان سؤال ذخیره می‌شوند و به این ترتیب سرعت دسترسی نهایی به اطلاعات بیشتر شده و همچنین قفل گذاری روی سایر اسناد کمتر. این مساله نیز به ذات NoSQL و یا غیر رابطه‌ای RavenDB بر می‌گردد. در بانک‌های اطلاعاتی NoSQL، مفاهیمی مانند کلیدهای خارجی، JOIN بین جداول و امثال آن وجود خارجی ندارند. برای نمونه اگر به کلاس‌های مدل‌های برنامه دقت کرده باشید، خبری از وجود Id در آن‌ها نیست. RavenDB یک Document store است و نه یک Relation store. در اینجا کل درخت تو در توی خواص یک شیء دریافت و به صورت یک سند ذخیره می‌شود. به حاصل این نوع عملیات در دنیای بانک‌های اطلاعاتی رابطه‌ای، Denormalized data هم گفته می‌شود.
البته می‌توان به کلاس‌های تعریف شده خاصیت رشته‌ای Id را نیز اضافه کرد. در این حالت برای مثال در حالت فراخوانی متد Load، این خاصیت رشته‌ای، با Id تولید شده توسط RavenDB مانند "questions/1" مقدار دهی می‌شود. اما از این Id برای تعریف ارجاعات به سؤالات و پاسخ‌های متناظر استفاده نخواهد شد؛ چون تمام آن‌ها جزو یک سند بوده و داخل آن قرار می‌گیرند.
نظرات مطالب
استفاده از DbProviderFactory
- اگر به هر دلیلی مجبور هستید که از دات نت 2 استفاده کنید، NHibernate می‌تونه پیشنهاد خوبی باشه و نسخه مخصوص دات نت 2 هم دارد (به آرشیو قدیمی آن سایت مراجعه کنید). (پایه زبان فعلی جاوا از خیلی از جهات شبیه به دات نت 2 است)
- مایکروسافت کلا توسعه پروایدر ADO.NET مخصوص اوراکل را رسما متوقف کرده و خود اوراکل الان داره این کار رو ادامه می‌ده. خلاصه از پروایدر مایکروسافت برای کار با اوراکل استفاده نکنید.

اشتراک‌ها
بررسی کردن مجوزهای مخازن GitHub

GitHub License Checker

Adding a permissive license to your open source projects makes it easy for others to benefit from reusing your code. I typically recommend the MIT license for most projects because it’s simple, well understood, and allows the code to be used for essentially any purpose.

بررسی کردن مجوزهای مخازن GitHub
مطالب
شروع کار با Apache Cordova در ویژوال استودیو #2
در قسمت اول، با Apache Cordova  آشنا شدیم. در این قست قصد دارم در مورد Phonegap, معایب و مزایای Cordova و روش نصب و راه اندازی آن را بر روی Visual Studio، خدمت شما ارائه دهم. 

توضیح مختصری در مورد  Adobe Phonegap
در حوالی سال 2009 ، phonegap به‌واسطه‌ی استارت آپی بنام Nitobi با هدف ایجاد یک راه حل سورس باز  برای  ساخت اپلیکیشن‌های بومی موبایل با تکنولوژی‌های تحت وب، تولید شد. شرکت Adobe در حوالی سال 2011 ، Notobi را به همرا حق مالکیت phonegap خریداری کرد و هسته‌ی سورس باز آن را با نام Cordova به شرکت Apache اهدا کرد. نسبت بین Cordova و phonegap مانند نسبت بین مرورگر Blink و کروم است. در واقع phonegap ترکیبی‌است از Cordova و یک سری امکانات اضافه‌ی شرکت Adobe. تفاوت اصلی بین Cordova و Phonegap مربوط است به ابزارهای Command-Line و سرویس Build فون گپ است که در مقالات بعدی به آنها خواهیم پرداخت.
بیشتر : اینجا و اینجا

 مزایای استفاده از Cordova:
  • محیط برنامه نویسی قدرتمند
  • هسته اصلی  کد‌های همه اپلیکیشن‌ها  تولید شده شبیه به هم است
  • نیازی به یادگیری زبان‌های مربوط به هر پلتفرم را ندارید
  • کم هزینه و زمان کمتر
  • طراحی رابط گرافیکی سریع و منعطف به کمک HTML5 , CSS3 
  • برنامه نویسی آسان و سریع با javascript , Typescript
  • قابلیت اجرا بر روی چندین پلتفرم مختلف(Android,iOS,Widnows Phone )
  • قابلیت استفاده از فریم‌ورکهای تحت وب مانند Bootstrap , Angular JS, ...
  • قابلیت طراحی پلاگین برای ارتباط با سیستم عامل
  • مناسب برای برای برنامه‌های چت و استفاد از وب سرویس‌ها
  • مناسب برای ساخت بازیهای آنلاین و آفلاین با تکنولوژی‌های تحت وب
  • راحتی کار با آن برای برنامه نویسان تحت وب 

معایب  استفاده از Cordova  :
  • نداشتن ابزار گزارش خطاهای مناسب؛ درنتیجه برطرف کردن خطاها خسته کننده خواهد بود .
  • UI, UX اپلیکیشن‌ها باید به نحوی باشد که کاربر حس کند با نرم‌افزارهای بومی گوشی کار می‌کند.
  • کاهش سرعت اجرایی جزئی نسبت به سایر برنامه‌ها (به دلیل استفاده از WebView)
  • عدم دسترسی مستقیم به سیستم عامل و امکانات آن 

نصب اتوماتیک وابستگی ها
ابزارهایی که ما نیاز داریم:

لازم است تا Visual Studio 2013، با حداقل آپدیت 2 بر روی سیستم شما نصب باشد.

بعد از اتمام دانلود فایل، اقدام به نصب آن نمایید. در این حین، یک سری وابستگی‌های مربوط به خود را دانلود و نصب خواهد کرد. لیست وابستگی ها:
  • Node.js
  • Git CLI
  • Google Chrome
  • Apache Ant
  • Oracle Java JDK 7 (حتما نسخه x86 نصب شود)
  • Android SDK 
  • SQLLite For Windows Runtime
  • Apple iTunes
فایل نصاب، همه‌ی این وابستگی‌ها را به‌غیر از Android SDK، نصب می‌کند. 
در آخر هم سیستم خود را راستارت کنید.

نصب دستی وابستگی‌ها:
اگر به هر دلیلی در نصب خودکار این وابستگی‌ها  توسط نصاب با مشکل بر خورد کردید، می‌توانید تک تک آنها را دانلود کرده و نصب کنید. لینک‌های مورد نظر را هم به همین دلیل قرار دادم. 
  1. node.js را از لینک مقابل دانلود کنید:  اینجا  (پیشنهاد می‌کنیم نسخه‌ی x86 آن را نصب کنید)
  2. Google Chrome را نصب کنید
  3. Git Command Line Tools را نصب کنید و توجه کنید که در هنگام نصب، گزینه مربوط به افزودن Git را به مسیر  Command Prompt  شما، انتخاب کرده باشید.
  4. Apchage Ant را  دانلود  و در مسیری از سیستم خودتان قرار دهید. 
  5. Java JDK 7 x86 را از لینک مشخص شده دانلود کنید و سپس عملیات نصب را انجام دهید.
  6. Android SDK را از آدرس مشحص شده دانلود کنید. پکیچ‌های مورد نیاز، به این SDK افزوده شده است. بعد از دانلود آن را در مسیری از سیستم خود قرار دهید.
  7. Apple iTunes و  SQLite را دانلود و نصب کنید.
  8. اگر از ویندوز 7 استفاده می‌کنید ، WebSocket4Net را از لینک مقابل دانلود کنید ( اینجا ) و سپس  فایل net45\Release\WebSocket4Net.dll  در مسیر زیر کپی کنید:
%ProgramFiles(x86)%\Microsoft Visual Studio 12.0\Common7\IDE\CommonExtensions\Microsoft\WebClient\Diagnostics\ToolWindows 


ویژوال استودیو  پیکربندی‌های مربوط به نرم افزار‌های  thrid-party (سوم شخص/ثالث: نرم افزارهایی که برای دستکاری بر روی سیستم عامل، توسط شرکت‌هایی غیر از شرکت‌های تولید کننده سیستم عامل تولید می‌شوند) را که شما نصب کرده‌اید، تشخیص می‌دهد و مسیر‌های نصب آنها را درون متغیر‌های محیطی (environment variables)  به شکل زیر نگه می‌دارد:
ADT_HOME :به مسیر نصب اندروید اشاره می‌کند
ANT_HOME: به فولدری که Apache Ant در آن قرار دارد اشاره می‌کند
JAVA_HOME: به مسیر نصب جاوا اشاره می‌کند
GIT_HOME: به مسیر نصب GIT اشاره می‌کند.
دقت کنید باید نام‌های متغیر‌ها، دقیقا به همین نام‌ها باشند.
برای تنظیم این متغیر‌ها، به مسیر Control Panel\System and Security\System وارد شده و گزینه‌ی Advanced System Setting را انتخاب کنید. سپس در پنجره‌ی باز شده گزینه‌ی Environment Variables را انتخاب کنید و در قست system variables، این 4 متغیری که ذکر شد را ایجاد کنید. سپس نیاز است این مسیر‌ها را به system path اضافه کنید. برای این کار از همان قسمت system variables متغییر path را انتخاب کرده و گزینه‌ی ویرایش را بزنید و ابتدا محتویات آن را در یک فایل notepad کپی کنید و مسیر‌های زیر را به اول آن اضافه کنید :
%GIT_HOME%\cmd;C:\Program Files (x86)\nodejs\;%JAVA_HOME%\bin;%ANT_HOME%\bin;
%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools; C:\ProgramData\Oracle\Java\javapath;
 دقت کنید که مسیر‌های ذکر شده فقط یکبار در کل فایل وجود داشته باشند و سپس کل محتوای فایل را کپی کرده و در قسمت مربوط به path پیست کنید و با کلیک بر روی دکمه‌های OK کار را به اتمام رسانید.












نکته تکمیلی
نیازمندی Apache Cordova CTP3.1   :
یکی از سیستم عامل‌های مقابل: Windows 7, Windows 8, Windows 8.1, or Windows Server 2012 R2. 
آپدیت 4 مربوط به ویژوال استدیو (دقت کنید قبل از نصب آپدیت 4 ویژوال استدیو باید نسخه قبلی  Cordova CTP  را حذف کنید(uninstall) )
امکان توسعه اپلیکیشن‌های windows phone , windows برای کاربران ویندوز 7 وجود ندارد .


در مقاله‌ی بعدی یک پروژه جدید خواهیم ساخت .
منبع مفید برای نصب و راه اندازی :اینجا
ادامه دارد...
مطالب
قالبی خودکار برای تهیه‌ی بسته‌های نیوگت
روش‌های زیادی برای تهیه‌ی یک بسته‌ی نیوگت وجود دارند، مانند استفاده از برنامه‌ی NuGet Package Explorer و یا تهیه‌ی یک فایل nuspec و تغییر مداوم جزئیات آن، به ازای هر نگارش جدید پروژه. در ادامه قصد داریم روش خودکار سازی این تغییرات را بررسی کنیم.


الف) تهیه فایل nuspec
NuGet قابلیت پذیرش متغیرهای خود تکمیل شونده‌ای را نیز دارد. فایل nuspec یا جزئیات بسته‌ی تولیدی نیوگت، در این حالت یک چنین شکلی را پیدا می‌کند:
<?xml version="1.0"?>
<package >
 <metadata>
  <id>$id$</id>
  <version>$version$</version>
  <title>$title$</title>
  <authors>$author$</authors>
  <owners>$author$</owners>
  <licenseUrl>https://site.com/prj/LICENSE</licenseUrl>
  <projectUrl>https://site.com/prj</projectUrl>
  <requireLicenseAcceptance>false</requireLicenseAcceptance>
  <description>$description$</description>
  <copyright>Copyright 2015 My Name</copyright>
 </metadata>
</package>
برای مثال اگر پروژه‌ی ما TestNuget نام دارد، فایلی به نام TestNuget.nuspec را با محتویات فوق برای آن تهیه خواهیم کرد. همانطور که مشاهده می‌کنید، در این فایل ویژه، هیچکدام از اطلاعات شماره نگارش پروژه، نام نویسنده و غیره، از پیش تعیین نشده‌اند. این اطلاعات، از فایل AssemblyInfo.cs پروژه، به صورت خودکار دریافت خواهند شد و نکته‌ی مهم آن، قرار گرفتن این فایل nuspec در پوشه‌ی اصلی پروژه است. از این جهت که برای کامپایل آن و تبدیل به یک بسته‌ی نیوگت، فایل nuget.exe را بر روی فایل پروژه‌ی اصلی برنامه اجرا خواهیم کرد و نه بر روی این فایل nuspec.
بنابراین تکمیل اطلاعات فایل AssemblyInfo.cs را فراموش نکنید. برای مثال اطلاعات AssemblyCompany آن، در قسمت authors فایل فوق جایگزین می‌شود.


ب) تهیه فایل NuGet.exe
فایل NuGet.exe را جهت کامپایل فایل فرضی TestNuget.nuspec نیاز داریم. می‌توان آن‌را از سایت کدپلکس تهیه کرد و یا تنها کافی است بر روی Solution موجود در VS.NET کلیک راست کرده و گزینه‌ی Enable NuGet Package Restrore را انتخاب کنیم. با اینکار به صورت خودکار پوشه‌ی ویژه‌ای به نام .nuget به همراه فایل NuGet.exe ایجاد می‌شود.


ج) کامپایل فایل nuspec
در همان پوشه‌ی جدید .nuget، یک فایل bat را با محتوای ذیل تهیه کنید:
 "%~dp0NuGet.exe" pack "..\TestNuGet\TestNuGet.csproj" -Prop Configuration=Release
copy "%~dp0*.nupkg" "%localappdata%\NuGet\Cache"
pause
در این مثال، مسیر TestNuGet\TestNuGet.csproj به محل قرارگیری فایل پروژه‌ی برنامه اشاره می‌کند. در اینجا فایل nuget.exe را بر روی فایل csproj برنامه اجرا خواهیم کرد. با توجه به اینکه قرار است یک بسته‌ی عمومی منتشر شود، بهتر است تنظیمات تولید بسته‌ی نیوگت را بر روی حالت release قرار داد که در این دستور، قید شده‌است.
در ادامه برای اینکه امکان آزمایش محلی این بسته را نیز داشته باشیم، فایل بسته‌ی تولیدی، به کش محلی نیوگت، در سیستم جاری کپی می‌شود.

نکته‌ی جالب این روش، تهیه‌ی قسمت dependencies پروژه، به صورت خودکار است:
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <id>TestNuget</id>
    <version>1.0.0.0</version>
    <title>TestNuget</title>
    <authors>Vahid N.</authors>
    <owners>Vahid N.</owners>
    <licenseUrl>https://site.com/prj/LICENSE</licenseUrl>
    <projectUrl>https://site.com/prj</projectUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>This is a test.</description>
    <copyright>Copyright 2015 My Name</copyright>
    <dependencies>
      <dependency id="EntityFramework" version="6.1.2" />
    </dependencies>
  </metadata>
</package>
اطلاعاتی را که در اینجا مشاهده می‌کنید، حاصل کامپایل فایل nuspec معرفی شده‌ی در ابتدای بحث است (با اجرای فایل bat تهیه شده) که یک کپی از آن در فایل TestNuget.1.0.0.0.nupkg نهایی نیز قرار می‌گیرد. به این ترتیب دیگر نیازی نیست تا این قسمت را به صورت دستی معرفی و هر بار با به روز رسانی وابستگی‌های پروژه، شماره نگارش‌های آن‌ها را نیز به روز کرد. اطلاعات version به صورت خودکار از پروژه‌ی جاری استخراج می‌شوند.


د) آزمایش محلی بسته‌ی جدید
اکنون که فایل TestNuget.1.0.0.0.nupkg تولیدی را در آدرس localappdata%\NuGet\Cache% نیز کپی کرده‌ایم، به منوی Tools/Options مراجعه و در قسمت NuGet Package Manager آن، به قسمت Package sources، این آدرس کش محلی را نیز معرفی کنید:


به این ترتیب، بدون ارسال یک بسته به سایت اصلی نیوگت، می‌توان بسته را از کش محلی نیوگت نصب و آزمایش کرد:



فایل‌های ذکر شده در مطلب فوق را از اینجا می‌توانید دریافت کنید:
TestNuget.zip
 
مطالب
معرفی یک ابزار گزارشگیری رایگان مخصوص WPF

تا صحبت از گزارشگیری به میان بیاید احتمالا معرفی ابزارهای تجاری مانند Reporting services ، کریستال ریپورت، stimulsoft.com ، fast-report.com و امثال آن درصدر لیست توصیه کنندگان و مشاوران قرار خواهند داشت. اما خوب برای ایجاد یک گزارشگیری ساده حتما نیازی نیست تا به این نوع ابزارهای تجاری مراجعه کرد. ابزار رایگان و سورس باز جالبی هم در این باره جهت پروژه‌های WPF در دسترس است:



در ادامه در طی یک مثال قصد داریم از این کتابخانه استفاده کنیم:

1) تنظیم وابستگی‌ها
پس از دریافت کتابخانه فوق، ارجاعات زیر باید به پروژه شما اضافه شوند:
CodeReason.Reports.dll (از پروژه فوق) و ReachFramework.dll (جزو اسمبلی‌های استاندارد دات نت است)

2) تهیه منبع داده‌ گزارش
کتابخانه‌ی فوق به صورت پیش فرض با DataTable‌ کار می‌کند. بنابراین کوئری‌های شما یا باید خروجی DataTable داشته باشد یا باید از یک سری extension methods برای تبدیل IEnumerable به DataTable استفاده کرد (در پروژه پیوست شده در پایان مطلب، این موارد موجود است).
برای مثال فرض کنید می‌خواهیم رکوردهایی را از نوع کلاس Product زیر در گزارش نمایش دهیم:

namespace WpfRptTests.Model
{
public class Product
{
public string Name { set; get; }
public int Price { set; get; }
}
}
3) تعریف گزارش
الف) اضافه کردن فایل تشکیل دهنده ساختار و ظاهر گزارش
گزارش‌‌های این کتابخانه مبتنی است بر اشیاء FlowDocument استاندارد WPF . بنابراین از منوی پروژه گزینه‌ی Add new item در قسمت WPF آن یک FlowDocument جدید را به پروژه اضافه کنید ( باید دقت داشت که Build action این فایل باید به Content تنظیم گردد). ساختار ابتدایی این FlowDocument به صورت زیر خواهد بود که به آن FlowDirection و FontFamily مناسب جهت گزارشات فارسی اضافه شده است. همچنین فضای نام مربوط به کتابخانه‌ی گزارشگیری CodeReason.Reports نیز باید اضافه گردد.
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FlowDirection="RightToLeft" FontFamily="Tahoma"
xmlns:xrd="clr-namespace:CodeReason.Reports.Document;assembly=CodeReason.Reports"
PageHeight="29.7cm" PageWidth="21cm" ColumnWidth="21cm">

</FlowDocument>

مواردی که در ادامه ذکر خواهند شد محتوای این گزارش را تشکیل می‌دهند:
ب) مشخص سازی خواص گزارش

<xrd:ReportProperties>
<xrd:ReportProperties.ReportName>SimpleReport</xrd:ReportProperties.ReportName>
<xrd:ReportProperties.ReportTitle>گزارش از محصولات</xrd:ReportProperties.ReportTitle>
</xrd:ReportProperties>
در اینجا ReportName و ReportTitle باید مقدار دهی شوند (دو dependency property که در کتابخانه‌ی CodeReason.Reports تعریف شده‌اند)

ج) مشخص سازی Page Header و Page Footer
اگر می‌خواهید عباراتی در بالا و پایین تمام صفحات گزارش تکرار شوند می‌توان از SectionReportHeader و SectionReportFooter این کتابخانه به صورت زیر استفاده کرد:
    <xrd:SectionReportHeader PageHeaderHeight="2" Padding="10,10,10,0" FontSize="12">
<Table CellSpacing="0">
<Table.Columns>
<TableColumn Width="*" />
<TableColumn Width="*" />
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell>
<Paragraph>
<xrd:InlineContextValue PropertyName="ReportTitle" />
</Paragraph>
</TableCell>
<TableCell>
<Paragraph TextAlignment="Right">
<xrd:InlineDocumentValue PropertyName="PrintDate" Format="dd.MM.yyyy HH:mm:ss" />
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</xrd:SectionReportHeader>

<xrd:SectionReportFooter PageFooterHeight="2" Padding="10,0,10,10" FontSize="12">
<Table CellSpacing="0">
<Table.Columns>
<TableColumn Width="*" />
<TableColumn Width="*" />
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell>
<Paragraph>
نام کاربر:
<xrd:InlineDocumentValue PropertyName="RptBy" Format="dd.MM.yyyy HH:mm:ss" />
</Paragraph>
</TableCell>
<TableCell>
<Paragraph TextAlignment="Right">
صفحه
<xrd:InlineContextValue PropertyName="PageNumber" FontWeight="Bold" /> از
<xrd:InlineContextValue PropertyName="PageCount" FontWeight="Bold" />
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</xrd:SectionReportFooter>

دو نکته در اینجا حائز اهمیت هستند: xrd:InlineDocumentValue و xrd:InlineContextValue
InlineDocumentValue را می‌توان در کد‌های برنامه به صورت سفارشی اضافه کرد. بنابراین هر جایی که نیاز بود مقدار ثابتی از طریق کد نویسی به گزارش تزریق و اضافه شود می‌توان از InlineDocumentValue استفاده کرد. برای مثال در کدهای ViewModel برنامه که در ادامه ذکر خواهد شد دو مقدار PrintDate و RptBy به صورت زیر تعریف و مقدار دهی شده‌اند:
data.ReportDocumentValues.Add("PrintDate", DateTime.Now);
data.ReportDocumentValues.Add("RptBy", "وحید");
برای مشاهده مقادیر مجاز مربوط به InlineContextValue به فایل ReportContextValueType.cs سورس کتابخانه مراجعه کنید که شامل PageNumber, PageCount, ReportName, ReportTitle است و توسط CodeReason.Reports به صورت پویا تنظیم خواهد شد.

د) مشخص سازی ساختار تولیدی گزارش

<Section Padding="80,10,40,10" FontSize="12">
<Paragraph FontSize="24" TextAlignment="Center" FontWeight="Bold">
<xrd:InlineContextValue PropertyName="ReportTitle" />
</Paragraph>
<Paragraph TextAlignment="Center">
گزارش از لیست محصولات در تاریخ:
<xrd:InlineDocumentValue PropertyName="PrintDate" Format="dd.MM.yyyy HH:mm:ss" />
توسط:
<xrd:InlineDocumentValue PropertyName="RptBy" Format="dd.MM.yyyy HH:mm:ss" />
</Paragraph>
<xrd:SectionDataGroup DataGroupName="ItemList">
<Table CellSpacing="0" BorderBrush="Black" BorderThickness="0.02cm">
<Table.Resources>
<!-- Style for header/footer rows. -->
<Style x:Key="headerFooterRowStyle" TargetType="{x:Type TableRowGroup}">
<Setter Property="FontWeight" Value="DemiBold"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Background" Value="LightGray"/>
</Style>

<!-- Style for data rows. -->
<Style x:Key="dataRowStyle" TargetType="{x:Type TableRowGroup}">
<Setter Property="FontSize" Value="12"/>
</Style>

<!-- Style for data cells. -->
<Style TargetType="{x:Type TableCell}">
<Setter Property="Padding" Value="0.1cm"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="0.01cm"/>
</Style>
</Table.Resources>

<Table.Columns>
<TableColumn Width="0.8*" />
<TableColumn Width="0.2*" />
</Table.Columns>
<TableRowGroup Style="{StaticResource headerFooterRowStyle}">
<TableRow>
<TableCell>
<Paragraph TextAlignment="Center">
<Bold>نام محصول</Bold>
</Paragraph>
</TableCell>
<TableCell>
<Paragraph TextAlignment="Center">
<Bold>قیمت</Bold>
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>

<TableRowGroup Style="{StaticResource dataRowStyle}">
<xrd:TableRowForDataTable TableName="Product">
<TableCell>
<Paragraph>
<xrd:InlineTableCellValue PropertyName="Name" />
</Paragraph>
</TableCell>
<TableCell>
<Paragraph TextAlignment="Center">
<xrd:InlineTableCellValue PropertyName="Price" AggregateGroup="Group1" />
</Paragraph>
</TableCell>
</xrd:TableRowForDataTable>
</TableRowGroup>

<TableRowGroup Style="{StaticResource headerFooterRowStyle}">
<TableRow>
<TableCell>
<Paragraph TextAlignment="Right">
<Bold>جمع کل</Bold>
</Paragraph>
</TableCell>
<TableCell>
<Paragraph TextAlignment="Center">
<Bold>
<xrd:InlineAggregateValue AggregateGroup="Group1"
AggregateValueType="Sum"
EmptyValue="0"
FontWeight="Bold" />
</Bold>
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>

</Table>

<Paragraph TextAlignment="Center" Margin="5">
در این گزارش
<xrd:InlineAggregateValue AggregateGroup="Group1"
AggregateValueType="Count"
EmptyValue="هیچ"
FontWeight="Bold" /> محصول با جمع کل قیمت
<xrd:InlineAggregateValue AggregateGroup="Group1"
AggregateValueType="Sum"
EmptyValue="0"
FontWeight="Bold" /> وجود دارند.
</Paragraph>
</xrd:SectionDataGroup>
</Section>
برای اینکه بتوان این قسمت‌ها را بهتر توضیح داد، نیاز است تا تصاویر مربوط به خروجی این گزارش نیز ارائه شوند:




در ابتدا توسط دو پاراگراف، عنوان گزارش و یک سطر زیر آن نمایش داده شده‌اند. بدیهی است هر نوع شیء و فرمت مجاز در FlowDocument را می‌توان در این قسمت نیز قرار داد.
سپس یک SectionDataGroup جهت نمایش لیست آیتم‌ها اضافه شده و داخل آن یک جدول که بیانگر ساختار جدول نمایش رکوردهای گزارش می‌باشد، ایجاد گردیده است.
سه TableRowGroup در این جدول تعریف شده‌اند.
TableRowGroup های اولی و آخری دو سطر اول و آخر جدول گزارش را مشخص می‌کنند (سطر عناوین ستون‌ها در ابتدا و سطر جمع کل در پایان گزارش)
از TableRowGroup میانی برای نمایش رکوردهای مرتبط با نام جدول مورد گزارشگیری استفاده شده است. توسط TableRowForDataTable آن نام این جدول باید مشخص شود که در اینجا همان نام کلاس مدل برنامه است. به کمک InlineTableCellValue، خاصیت‌هایی از این کلاس را که نیاز است در گزارش حضور داشته باشند، ذکر خواهیم کرد. نکته‌ی مهم آن AggregateGroup ذکر شده است. توسط آن می‌توان اعمال جمع، محاسبه تعداد، حداقل و حداکثر و امثال آن‌را که در فایل InlineAggregateValue.cs سورس کتابخانه ذکر شده‌اند، به فیلدهای مورد نظر اعمال کرد. برای مثال می‌خواهیم جمع کل قیمت را در پایان گزارش نمایش دهیم به همین جهت نیاز بود تا یک AggregateGroup را برای این منظور تعریف کنیم.
از این AggregateGroup در سومین TableRowGroup تعریف شده به کمک xrd:InlineAggregateValue جهت نمایش جمع نهایی استفاده شده است.
همچنین اگر نیاز بود در پایان گزارش اطلاعات بیشتری نیز نمایش داده شود به سادگی می‌توان با تعریف یک پاراگراف جدید، اطلاعات مورد نظر را نمایش داد.

4) نمایش گزارش تهیه شده
نمایش این گزارش بسیار ساده است. View برنامه به صورت زیر خواهد بود:
<Window x:Class="WpfRptTests.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:CodeReason.Reports.Controls;assembly=CodeReason.Reports"
xmlns:vm="clr-namespace:WpfRptTests.ViewModel"
Title="MainWindow" WindowState="Maximized" Height="350" Width="525">
<Window.Resources>
<vm:ProductViewModel x:Key="vmProductViewModel" />
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource vmProductViewModel}}">
<c:BusyDecorator IsBusyIndicatorHidden="{Binding RptGuiModel.IsBusyIndicatorHidden}">
<DocumentViewer Document="{Binding RptGuiModel.Document}" />
</c:BusyDecorator>
</Grid>
</Window>

تعریف ابتدایی RptGuiModel به صورت زیر است (جهت مشخص سازی مقادیر IsBusyIndicatorHidden و Document در حین بایندینگ اطلاعات):

using System.ComponentModel;
using System.Windows.Documents;

namespace WpfRptTests.Model
{
public class RptGuiModel
{
public IDocumentPaginatorSource Document { get; set; }
public bool IsBusyIndicatorHidden { get; set; }
}
}
و این View اطلاعات خود را از ViewModel زیر دریافت خواهد نمود:
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using CodeReason.Reports;
using WpfRptTests.Helper;
using WpfRptTests.Model;

namespace WpfRptTests.ViewModel
{
public class ProductViewModel
{
#region Constructors (1)

public ProductViewModel()
{
RptGuiModel = new RptGuiModel();
if (Stat.IsInDesignMode) return;
//انجام عملیات نمایش گزارش در یک ترد دیگر جهت قفل نشدن ترد اصلی برنامه
showReportAsync();
}

#endregion Constructors

#region Properties (1)

public RptGuiModel RptGuiModel { set; get; }

#endregion Properties

#region Methods (3)

// Private Methods (3)

private static List<Product> getProducts()
{
var products = new List<Product>();
for (var i = 0; i < 100; i++)
products.Add(new Product { Name = string.Format("Product{0}", i), Price = i });

return products;
}

private void showReport()
{
try
{
//Show BusyIndicator
RptGuiModel.IsBusyIndicatorHidden = false;

var reportDocument =
new ReportDocument
{
XamlData = File.ReadAllText(@"Report\SimpleReport.xaml"),
XamlImagePath = Path.Combine(Environment.CurrentDirectory, @"Report\")
};

var data = new ReportData();

// تعریف متغیرهای دلخواه و مقدار دهی آن‌ها
data.ReportDocumentValues.Add("PrintDate", DateTime.Now);
data.ReportDocumentValues.Add("RptBy", "وحید");

// استفاده از یک سری اطلاعات آزمایشی به عنوان منبع داده
data.DataTables.Add(getProducts().ToDataTable());

var xps = reportDocument.CreateXpsDocument(data);
//انقیاد آن به صورت غیر همزمان در ترد اصلی برنامه
DispatcherHelper.DispatchAction(
() => RptGuiModel.Document = xps.GetFixedDocumentSequence()
);
}
catch (Exception ex)
{
//وجود این مورد ضروری است زیرا بروز استثناء در یک ترد به معنای خاتمه آنی برنامه است
//todo: log errors
}
finally
{
//Hide BusyIndicator
RptGuiModel.IsBusyIndicatorHidden = true;
}
}

private void showReportAsync()
{
var thread = new Thread(showReport);
thread.SetApartmentState(ApartmentState.STA); //for DocumentViewer
thread.Start();
}

#endregion Methods
}
}

توضیحات:
برای اینکه حین نمایش گزارش، ترد اصلی برنامه قفل نشود، از ترد استفاده شد و استفاده ترد به همراه DocumentViewer کمی نکته دار است:
- ترد تعریف شده باید از نوع STA باشد که در متد showReportAsync مشخص شده است.
- حین بایندیگ Document تولید شده توسط کتابخانه‌ی گزارشگیری به خاصیت Document کنترل، حتما باید کل عملیات در ترد اصلی برنامه صورت گیرد که سورس کلاس DispatcherHelper را در فایل پیوست خواهید یافت.

کل عملیات این ViewModel در متد showReport رخ می‌دهد، ابتدا فایل گزارش بارگذاری می‌شود، سپس متغیرهای سفارشی مورد نظر تعریف و مقدار دهی خواهند شد. در ادامه یک سری داده آزمایشی تولید و به DataTables گزارش ساز اضافه می‌شوند. در پایان XPS Document متناظر آن تولید شده و به کنترل نمایشی برنامه بایند خواهد شد.

دریافت سورس این مثال

نظرات مطالب
استخراج تمام XPathهای یک محتوای HTMLایی به کمک کتابخانه HtmlAgilityPack
برای انتخاب یک کتابخانه صرفا به سرعت آن نباید توجه کرد. این موارد برای انتخاب کتابخانه‌های ثالث، مهم هستند:
- آیا این کتابخانه محلی برای بحث و رفع اشکال دارد؟
- آیا سورس باز است؟ (غیر الزامی؛ اما یک امتیاز مثبت)
- آیا به همراه مثال‌های کاربردی است؟
- آیا مستندات قابل قبولی دارد؟
- آیا در جستجویی که انجام شده، کسی از آن در پروژه‌های خودش استفاده می‌کند؟
- آیا هر از چندگاهی به روز می‌شود؟ آخرین باری که به روز شده چه زمانی بوده؟
- آیا استفاده از آن در انواع و اقسام پروژه‌ها مجاز است؟ مجوز استفاده از آن به چه نحوی است؟