مطالب
روش‌هایی برای بهبود سرعت برنامه‌های مبتنی بر Entity framework
در این مطلب تعدادی از شایع‌ترین مشکلات حین کار با Entity framework که نهایتا به تولید برنامه‌هایی کند منجر می‌شوند، بررسی خواهند شد.

مدل مورد بررسی

    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public virtual ICollection<BlogPost> BlogPosts { get; set; }
    }

    public class BlogPost
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }

        [ForeignKey("UserId")]
        public virtual User User { get; set; }
        public int UserId { get; set; }
    }
کوئری‌هایی که در ادامه بررسی خواهند شد، بر روی رابطه‌ی one-to-many فوق تعریف شده‌اند؛ یک کاربر به همراه تعدادی مطلب منتشر شده.


مشکل 1: بارگذاری تعداد زیادی ردیف
 var data = context.BlogPosts.ToList();
در بسیاری از اوقات، در برنامه‌های خود تنها نیاز به مشاهده‌ی قسمت خاصی از یک سری از اطلاعات، وجود دارند. به همین جهت بکارگیری متد ToList بدون محدود سازی تعداد ردیف‌های بازگشت داده شده، سبب بالا رفتن مصرف حافظه‌ی سرور و همچنین بالا رفتن میزان داده‌ای که هر بار باید بین سرور و کلاینت منتقل شوند، خواهد شد. یک چنین برنامه‌هایی بسیار مستعد به استثناهایی از نوع out of memory هستند.
راه حل:  با استفاده از Skip و Take، مباحث صفحه‌ی بندی را اعمال کنید.


مشکل 2: بازگرداندن تعداد زیادی ستون
 var data = context.BlogPosts.ToList();
فرض کنید View برنامه، در حال نمایش عناوین مطالب ارسالی است. کوئری فوق، علاوه بر عناوین، شامل تمام خواص تعریف شده‌ی دیگر نیز هست. یک چنین کوئری‌هایی نیز هربار سبب هدر رفتن منابع سرور می‌شوند.
راه حل: اگر تنها نیاز به خاصیت Content است، از Select و سپس ToList استفاده کنید؛ البته به همراه نکته 1.
 var list = context.BlogPosts.Select(x => x.Content).Skip(15).Take(15).ToList();


مشکل 3: گزارشگیری‌هایی که بی‌شباهت به حمله‌ی به دیتابیس نیستند
 foreach (var post in context.BlogPosts)
{
     Console.WriteLine(post.User.Name);
}
فرض کنید قرار است رکوردهای مطالب را نمایش دهید. در حین نمایش این مطالب، در قسمتی از آن باید نام نویسنده نیز درج شود. با توجه به رابطه‌ی تعریف شده، نوشتن post.User.Name به ازای هر مطلب، بسیار ساده به نظر می‌رسد و بدون مشکل هم کار می‌کند. اما ... اگر خروجی SQL این گزارش را مشاهده کنیم، به ازای هر ردیف نمایش داده شده، یکبار رفت و برگشت به بانک اطلاعاتی، جهت دریافت نام نویسنده یک مطلب وجود دارد.
این مورد به lazy loading مشهور است و در مواردی که قرار است با یک مطلب و یک نویسنده کار شود، شاید اهمیتی نداشته باشد. اما در حین نمایش لیستی از اطلاعات، بی‌شباهت به یک حمله‌ی شدید به بانک اطلاعاتی نیست.
راه حل: در گزارشگیری‌ها اگر نیاز به نمایش اطلاعات روابط یک موجودیت وجود دارد، از متد Include استفاده کنید تا Lazy loading لغو شود.
 foreach (var post in context.BlogPosts.Include(x=>x.User))


مشکل 4:  فعال بودن بی‌جهت مباحث ردیابی اطلاعات
 var data = context.BlogPosts.ToList();
در اینجا ما فقط قصد داریم که لیستی از اطلاعات را دریافت و سپس نمایش دهیم. در این بین، هدف، ویرایش یا حذف اطلاعات این لیست نیست. یک چنین کوئری‌هایی مساوی هستند با تشکیل dynamic proxies مخصوص EF جهت ردیابی تغییرات اطلاعات (مباحث AOP توکار). EF توسط این dynamic proxies، محصور کننده‌هایی را برای تک تک آیتم‌های بازگشت داده شده از لیست تهیه می‌کند. در این حالت اگر خاصیتی را تغییر دهید، ابتدا وارد این محصور کننده (غشاء نامرئی) می‌شود، در سیستم ردیابی EF ذخیره شده و سپس به شیء اصلی اعمال می‌گردد. به عبارتی شیء در حال استفاده، هر چند به ظاهر post.User است اما در واقعیت یک User دارای روکشی نامرئی از جنس dynamic proxy‌های EF است. تهیه این روکش‌ها، هزینه‌بر هستند؛ چه از لحاظ میزان مصرف حافظه و چه از نظر سرعت کار.
راه حل: در گزاشگیری‌ها، dynamic proxies را توسط متد AsNoTracking غیرفعال کنید:
 var data = context.BlogPosts.AsNoTracking().Skip(15).Take(15).ToList();


مشکل 5: باز کردن  تعداد اتصالات زیاد به بانک اطلاعاتی در طول یک درخواست

هر Context دارای اتصال منحصربفرد خود به بانک اطلاعاتی است. اگر در طول یک درخواست، بیش از یک Context مورد استفاده قرار گیرد، بدیهی است به همین تعداد اتصال باز شده به بانک اطلاعاتی، خواهیم داشت. نتیجه‌ی آن فشار بیشتر بر بانک اطلاعاتی و همچنین کاهش سرعت برنامه است؛ از این لحاظ که اتصالات TCP برقرار شده، هزینه‌ی بالایی را به همراه دارند.
روش تشخیص:
        private void problem5MoreThan1ConnectionPerRequest() 
        {
            using (var context = new MyContext())
            {
                var count = context.BlogPosts.ToList();
            }
        }
داشتن متدهایی که در آن‌ها کار وهله سازی و dispose زمینه‌ی EF انجام می‌شود (متدهایی که در آن‌ها new Context وجود دارد).
راه حل: برای حل این مساله باید از روش‌های تزریق وابستگی‌ها استفاده کرد. یک Context وهله سازی شده‌ی در طول عمر یک درخواست، باید بین وهله‌های مختلف اشیایی که نیاز به Context دارند، زنده نگه داشته شده و به اشتراک گذاشته شود.


مشکل 6: فرق است بین IList و IEnumerable
DataContext = from user in context.Users
                      where user.Id>10
                      select user;
خروجی کوئری LINQ نوشته شده از نوع IEnumerable است. در EF، هربار مراجعه‌ی مجدد به یک کوئری که خروجی IEnumerable دارد، مساوی است با ارزیابی مجدد آن کوئری. به عبارتی، یکبار دیگر این کوئری بر روی بانک اطلاعاتی اجرا خواهد شد و رفت و برگشت مجددی صورت می‌گیرد.
زمانیکه در حال تهیه‌ی گزارشی هستید، ابزارهای گزارشگیر ممکن است چندین بار از نتیجه‌ی کوئری شما در حین تهیه‌ی گزارش استفاده کنند. بنابراین برخلاف تصور، data binding انجام شده، تنها یکبار سبب اجرای این کوئری نمی‌شود؛ بسته به ساز و کار درونی گزارشگیر، چندین بار ممکن است این کوئری فراخوانی شود.
راه حل: یک ToList را به انتهای این کوئری اضافه کنید. به این ترتیب از نتیجه‌ی کوئری، بجای اصل کوئری استفاده خواهد شد و در این حالت تنها یکبار رفت و برگشت به بانک اطلاعاتی را شاهد خواهید بود.


مشکل 7: فرق است بین IQueryable و IEnumerable

خروجی IEnumerable، یعنی این عبارت را محاسبه کن. خروجی IQueryable یعنی این عبارت را درنظر داشته باش. اگر نیاز است نتایج کوئری‌ها با هم ترکیب شوند، مثلا بر اساس رابط کاربری برنامه، کاربر بتواند شرط‌های مختلف را با هم ترکیب کند، باید از ترکیب IQueryableها استفاده کرد تا سبب رفت و برگشت اضافی به بانک اطلاعاتی نشویم.


مشکل 8: استفاده از کوئری‌های Like دار
 var list = context.BlogPosts.Where(x => x.Content.Contains("test"))
این نوع کوئری‌ها که در نهایت به Like در SQL ترجمه می‌شوند، سبب full table scan خواهند شد که کارآیی بسیار پایینی دارند. در این نوع موارد توصیه شده‌است که از روش‌های full text search استفاده کنید.


مشکل 9: استفاده از Count بجای Any

اگر نیاز است بررسی کنید مجموعه‌ای دارای مقداری است یا خیر، از Count>0 استفاده نکنید. کارآیی Any و کوئری SQL ایی که تولید می‌کند، به مراتب بیشتر و بهینه‌تر است از Count>0.


مشکل 10: سرعت insert پایین است

ردیابی تغییرات را خاموش کرده و از متد جدید AddRange استفاده کنید. همچنین افزونه‌هایی برای Bulk insert نیز موجود هستند.


مشکل 11: شروع برنامه کند است

می‌توان تمام مباحث نگاشت‌های پویای کلاس‌های برنامه به جداول و روابط بانک اطلاعاتی را به صورت کامپایل شده در برنامه ذخیره کرد. این مورد سبب بالا رفتن سرعت شروع برنامه خصوصا در حالتیکه تعداد جداول بالا است می‌شود.
نظرات مطالب
آشنایی با NHibernate - قسمت پنجم
در کامنت‌های فوق توضیح دادم. این توضیحات مربوط به نگارش 2 بود. الان نگارش 3 را که دریافت کنید LINQ با آن یکپارچه است و نیازی به دریافت پروایدر کمکی نیست و پروایدر قدیمی هم منسوخ شده و دیگر ادامه نخواهد یافت.
مطالب
مروری بر کتابخانه ReactJS - قسمت ششم - اعتبارسنجی

تا اینجای کار ساخت کامپوننت‌ها را با React.createClass که تفاوتی با توسعه (ارث بری) از کلاس React.Component ندارد، انجام داده‌ایم. اما ساخت کامپوننت‌ها به صورت یک تابع هم مزیت‌هایی را دارد. اول از همه باید بدانیم که ساخت کامپوننت توسط تابع، بدون وضعیت خواهد بود که به آن Stateless میگویند. به دلیل نداشتن وضعیت، کامپوننت‌های تابعی را کمی بهتر میشود برای استفاده مجدد به کار برد. در کامپوننت‌های غیر تابعی که Stateful هستند به دلیل احتمال وابستگی وضعیت کامپوننت به خارج از کلاس، مانند مثال قسمت چهارم که کامپوننت در انتظار کلیک یک دکمه خاص توسط کاربر بود، مدیریت استفاده مجدد ازکامپوننت چالش برانگیز خواهد شد.


اعتبارسنجی داده‌های ورودی 

برای مدیریت بهتر کامپوننت‌ها جهت استفاده مجدد از آنها بهتر است ورودی‌های کامپوننت را اعتبارسنجی کنیم. این ورودی‌ها چه برای استفاده داخلی کامپوننت، یا جهت مشخص کردن وضعیت آن، بر رفتار کامپوننت تاثیر زیادی دارند. React مجموعه‌ای از اعتبار سنجی‌ها را دارد که میشود به کامپوننت اضافه کرد. باید توجه داشته باشیم که پیام‌های خطای این اعتبارسنجی‌ها فقط در حالت Development Mode قابل استفاده هستند. به زبان ساده اگر از react.min.js استفاده کنید، پیام‌های خطا را نخواهید دید. باید فایل‌ها را به نوع react.js تبدیل کنید. اعتبارسنجی React در زمان توسعه و برای توسعه دهندگان استفاده میشود. 

مثال نوشیدنی‌ها در قسمت چهارم میتوانست نام نوشیدنی و قیمت آن را نمایش دهد و همچنین میتوانستیم به لیست نوشیدنی‌ها، موردی را اضافه کنیم. اگر ورودی قیمت، اعتبارسنجی نشود، میتوان رشته‌ای را بجای عدد به عنوان قیمت به کامپوننت ارسال کرد. نحوه اعتبارسنجی قیمت نوشیدنی‌ها به صورت زیر است. 

const MenuItem = props => (
    <li className="list-group-item">
        <span className="badge">{props.price}</span>
        <p>{props.item}</p>
    </li>
)

MenuItem.propTypes = {
    price: React.PropTypes.number
};

شیء propTypes را به کامپوننت اضافه کرده‌ایم و در تنظیمات آن میتوانیم برای هر پارامتر ورودی یکی از  اعضای PropTypes از React را که مناسب حال پارامتر است، انتخاب کنیم. در مثال بالا مشخص کرده‌ایم که ورودی price باید عدد باشد و اگر مثلا رشته‌ای را بجای عدد ارسال کنیم، پیام خطای زیر را در Console خواهیم داشت. 

Warning: Failed prop type: Invalid prop `price` of type `string` supplied to `MenuItem`, expected `number`.
    in MenuItem (created by Menu)
    in Menu

یا میتوانستیم از React.PropTypes.number.isRequired استفاده کنیم تا درج مقداری برای این ورودی الزامی باشد. اگر اعتبارسنجی‌های React کافی نبودند میتوانیم اعتبارسنجی‌های سفارشی خودمان را ایجاد کنیم. در مثال زیر میخواهیم ورودی price بیشتر از 15000 نباشد.

MenuItem.propTypes = {
    price: (props, price)=>{
        if(props[price] > 15000){
            return new Error("Too expensive!");
        }
    }
};
اگر در ساخت  کامپوننت‌ها از React.creatClass یا Reac.Component استفاده کرده‌ایم، میتوانیم اعتبار سنجی را به عنوان یک عضو استاتیک در داخل کلاس معرفی کنیم. مانند مثال زیر.
let MenuItem = React.createClass({
    propTypes: {
        price: React.PropTypes.number
    }
});

class MenuItem extends React.Component{
    static propTypes = {
        price: React.PropTypes.number
    };
}

نوعهای دیگر برای اعتبارسنجی شامل موارد زیر هستند و  البته مرجع تمام اعتبارسنجی‌های React را میتوانید در اینجا بررسی کنید. 

  • React.PropTypes.array
  • React.PropTypes.bool
  • React.PropTypes.number
  • React.PropTypes.object
  • React.PropTypes.string


مقدار پیش‌فرض داده‌های ورودی

یکی از امکانات مفید دیگر برای مدیریت مقدارهای ورودی، مشخص کردن مقدار پیش‌فرضی برای یک پارامتر است. برای مثال اگر برای قیمت یک نوشیدنی مقداری وارد نشد، یک حداقل قیمت برای آن در نظر بگیریم، هر چند که ایده و روشی اشتباه است! 

MenuItem.defaultProps = {
    price: 1000
};

همانطور که می‌بینید روش کار مشابه با اعتبارسنجی است و برای مشخص کردن مقدار پیش‌فرض برای React.creatClass از متد getDefaultProps که عضوی از React است، استفاده میکنیم. 

let MenuItem = React.createClass({
    getDefaultProps() {
        return { price: 200 }
    },
    render() {
        return (
            <li className="list-group-item">
                <span className="badge">{this.props.price}</span>
                <p>{this.props.item}</p>
            </li>
        );
    }
});
در قسمت بعد ورودی‌های کاربر را از UI به کامپوننت‌ها، بررسی میکنیم.
مطالب
استفاده از Twitter Bootstrap در کارهای روزمره طراحی وب
پس از آشنایی مقدماتی با Twitter Bootstrap، در این قسمت قصد داریم تا با ویژگی‌هایی از آن آشنا شویم که در کارهای رومزه طراحی وب بسیار مورد استفاده هستند؛ مانند تایپوگرافی، جداول، فرم‌ها، دکمه‌ها، تصاویر و آیکون‌ها.

تایپوگرافی
هدف از تایپوگرافی، چیدمان متن به نحوی است که واضح، خوانا و مشخص باشد؛ همچنین مباحث زیبایی ارائه را نیز به آن اضافه کنید. برای مثال تنظیم فاصله بین حروف و کلمات، فاصله بین خطوط و یا رعایت یک سری نسبت‌های ویژه مانند نسبت طلایی جهت دعوت خواننده به مطالعه مطالب، بجای فراری دادن او، در مباحث تایپوگرافی رعایت می‌شوند. خوشبختانه Twitter Bootstrap به همراه یک سری تنظیمات تایپوگرافی پیش فرض است که در ادامه آن‌ها را مرور خواهیم کرد.
پیش فرض‌های ابتدایی آن‌را مانند قلم با اندازه 14px، قلم پیش فرض Helvetica، فاصله بین خطوط و رنگ متن را در فایل bootstrap.css می‌توانید مشاهده کنید:
body {
    margin: 0;"Helvetica Neue", Helvetica, Arial, sans-serif;
    color: #333333;
    background-color: #ffffff;
}
در اینجا اثر تنظیمات bootstrap را بر روی تگ‌های h1 تا h6 ملاحظه می‌کنید:
 

 
        <div class="row-fluid">
            <div class="span12">
                <h1>
                    سرتیتر 1
                </h1>
                <h2>
                    سرتیتر 2
                </h2>
                <h3>
                    سرتیتر 3
                </h3>
                <h4>
                    سرتیتر 4
                </h4>
                <h5>
                    سرتیتر 5
                </h5>
                <h6>
                    سرتیتر 6
                </h6>
            </div>
        </div>

همچنین اگر نیاز باشد تا نسبت به متنی جلب توجه خواننده را جلب کرد می‌توان از کلاس lead استفاده نمود. به علاوه bootstrap پیش فرض‌هایی را به المان‌های small، strong و em نیز اعمال می‌کند:
        <div class="row-fluid">
            <div class="span12">
                <p class="lead">
                    تیتر</p>
                <p>
                    متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن
                    متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن
                    متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن
                    متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن متن
                </p>
                <small>اندازه کوچک</small> <strong>متن ضخیم</strong> <em>متن ایتالیک</em>
            </div>
        </div>

روش دیگر جلب توجه به یک متن در bootstrap، استفاده از کلاس‌های text مانند text-error و امثال آن می‌باشد:

 
 
        <div class="row-fluid">
            <div class="span12">
                <p class="muted">
                    متن غیرفعال</p>
                <p class="text-warning">
                    نمایش اخطار به کاربر</p>
                <p class="text-error">
                    نمایش خطا به کاربر</p>
                <p class="text-info">
                    نمایش اطلاعات به کاربر</p>
                <p class="text-success">
                    نمایش موفقیت آمیز بودن عملیات</p>
            </div>
        </div>

bootstrap تنظیماتی را به المان abbreviation موجود در HTML 5 نیز اعمال می‌کند. در این حالت کاربر با نزدیک ساختن اشاره‌گر ماوس به متن مشخص شده، یک tooltip توضیح دهنده نیز ظاهر خواهد شد:

 
 
        <div class="row-fluid">
            <div class="span12">
                <p>
                    My
                    <abbr title="منظور واحد پردازش مرکزی است">
                        CPU</abbr>
                    has N Cores.
                </p>
            </div>
        </div>

در bootstrap المان آدرس نیز شیوه نامه خاص خودش را داشته و به صورت یک قطعه خاص ظاهر می‌شود:
 

        <div class="row-fluid">
            <div class="span12">
                <address>
                    وحید نصیری
                    <br />
                    ایران، تهران
                    <br />
                    <abbr title="Phone">
                        P:</abbr>
                    12345678
                    <br />
                    <abbr title="Cell">
                        C:</abbr>
                    12345678
                </address>
            </div>
        </div>

 
در اینجا تاثیر bootstrap را بر روی المان blockquote ملاحظه می‌کنید؛ همچنین به همراه المان  citeبرای ذکر ماخذ نقل قول ذکر شده:

 
        <div class="row-fluid">
            <div class="span12">
                <blockquote>
                    <p>
                        جهت نمایش نقل قول
                    </p>
                    <small><cite title="کاربر شماره 2">از شخصی</cite> </small>
                </blockquote>
            </div>
        </div>

 
در bootstrap برای حذف بولت‌های کنار یک لیست مرتب، فقط کافی است از کلاس unstyled استفاده شود:
 

        <div class="row-fluid">
            <div class="span6">
                <ul class="unstyled">
                    <li>یک </li>
                    <li>دو </li>
                    <li>سه </li>
                </ul>
            </div>
            <div class="span6">
                <ol>
                    <li>یک </li>
                    <li>دو </li>
                    <li>سه </li>
                </ol>
            </div>
        </div>

 
به علاوه امکان تعریف دو نوع خاص از definition list نیست وجود دارد (المان dl در اینجا). در حالت عادی، ابتدا عنوان مشخص شده با dt یا definition term به صورت ضخیم ظاهر می‌شود؛ به همراه توضیحات ارائه شده در المان dd آن در سطر بعدی. اگر از کلاس dl-horizontal استفاده شود، همانند تصویر ذیل، عنوان در کنار توضیحات در یک سطر قرار خواهد گرفت:
 

        <div class="row-fluid">
            <div class="span12">
                <dl class="dl-horizontal">
                    <dt>عنوان</dt>
                    <dd>
                        توضیحات بلند در اینجا</dd>
                </dl>
            </div>
        </div>

 
در bootstrap امکان اعمال شیوه نامه ابتدایی به کدهای برنامه‌ها نیز وجود دارد. اگر از تگ code استفاده شود، فرض بر این است که قرار است اطلاعاتی را در یک سطر نمایش دهید. اگر اطلاعات کدها، بیشتر از یک سطر است، می‌توان از تگ pre استفاده کرد. در اینجا با اعمال کلاس pre-scrollable به تگ pre، به صورت خودکار یک اسکرول عمودی به قطعه کدها اعمال خواهد شد:
 

 
        <div class="row-fluid">
            <div class="span6">
                <code>inline code</code>
            </div>
            <div class="span6">
                <pre class="pre-scrollable">
                code
                code
                code
                </pre>
            </div>
        </div>



استفاده از جداول و تاثیر bootstrap بر آن‌ها

در ادامه کدهای یک جدول متداول را که مزین شده‌است به کلاس‌های bootstrap ملاحظه می‌کنید:
    <div class="container-fluid">
        <div class="row-fluid">
            <div class="span12">
                <table 
class="table table-striped table-hover table-bordered table-condensed">
                    <caption>
                        عنوانی خاص در اینجا</caption>
                    <thead>
                        <tr>
                            <th>
                                ستون یک
                            </th>
                            <th>
                                ستون دو
                            </th>
                            <th>
                                ستون سه
                            </th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr class="error">
                            <td>
                                1 متن یک
                            </td>
                            <td>
                                1 متن دو
                            </td>
                            <td>
                                1 متن سه
                            </td>
                        </tr>
                        <tr>
                            <td>
                                2 متن یک
                            </td>
                            <td>
                                2 متن دو
                            </td>
                            <td>
                                2 متن سه
                            </td>
                        </tr>
                        <tr>
                            <td>
                                3 متن یک
                            </td>
                            <td>
                                3 متن دو
                            </td>
                            <td>
                                3 متن سه
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>

در اینجا ذکر caption اختیاری است. وجود thead و tbody به تشخیص هدر و ردیف‌ها جهت اعمال شیوه‌نامه‌های متناظر کمک می‌کنند. همچنین کلاس‌های ذیل نیز به جدول اعمال شده‌اند:
table: سبب می‌شود تا تنظیمات ابتدایی bootstrap به جدول طراحی شده، اعمال شوند.
 table-striped: رنگ زمینه سطرها را یک در میان تغییر می‌دهد.
 table-hover: سبب می‌شود تا با عبور اشاره‌گر ماوس از روی سطرها، رنگ زمینه آن‌ها تغییر کنند.
 table-bordered: حاشیه‌ای را به جدول و ردیف‌ها اعمال می‌کنند. همچنین سبب نمایش گوشه‌های گرد نیز می‌شود.
 table-condensed: اندکی padding اعمال شده به سلول‌های جداول را کاهش می‌دهد و جدول را فشرده‌تر می‌کند.

در جدول فوق، کلاس نمونه error به یک tr نیز اعمال شده‌است تا اثر آن‌را بر روی یک ردیف بهتر بتوان ملاحظه کرد.



طراحی فرم‌ها و تاثیر bootstrap بر آن‌ها

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

1) فرم‌های عمودی
 

    <div class="container-fluid">
        <div class="row-fluid">
            <div class="span12">
                <form action="/signup" method="post">
                <fieldset>
                    <legend>ثبت نام</legend>
                    <label>
                        ایمیل:</label>
                    <input name="email" type="text" />
                    <label>
                        نام:</label>
                    <input name="name" type="text" />
                </fieldset>
                </form>
            </div>
        </div>
    </div>

 
در اینجا یک فرم ساده را مشاهده می‌کنید. بدون bootstrap، تمام عناصر این فرم در یک سطر نمایش داده می‌شوند. اما با صرفا فعال سازی css مرتبط با آن، به شکل مدرن فوق خواهیم رسید.
همانطور که ملاحظه می‌کنید، کلیه عناصر را به صورت یک پشته عمودی در صفحه قرار داده‌است و نکته مهم اینجا است که هیچگونه شیوه نامه خاص و اضافه‌تری به فرم فوق از طرف ما اعمال نشده است.

نکته: اگر می‌خواهید همان حالت پیش فرض مرورگر، یعنی قرار دادن تمام عناصر در پشت سر هم را فعال کنید، تنها کافی است کلاس form-inline را به form تعریف شده فوق اضافه نمائید.

2) نکاتی در مورد checkboxes و radio buttons
در حالت پیش فرض، با تعریف یک label و checkbox، برچسب متناظر با آن اندکی بالاتر از checkbox قرار گرفته شده در صفحه ظاهر می‌شود. برای رفع این مشکل تنها کافی است کلاس checkbox به label اعمال شود (و برای radio button از کلاس radio استفاده خواهد شد):
<label class="checkbox">
       <input type="checkbox" name="isMale" />
 مذکر</label>
این مثال را یکبار با کلاس checkbox و بار دیگر بدون آن آزمایش کنید تا تفاوت را بهتر بتوان درک کرد.

نکته: برای قرار دادن چندین checkbox یا radio button در یک سطر (با توجه به حالت چیدمان عمودی پیش فرض فرم‌ها)، ابتدا  آن‌ها را داخل یک div قرار دهید. سپس به تمام checkboxها یا radio buttonها کلاس inline را نیز اضافه نمائید. برای مثال:

 
 
                  <div>
                        <label class="radio inline">
                            <input type="radio" name="isMale" />
                            مذکر</label>
                        <label class="radio inline">
                            <input type="radio" name="isFemale" />
                            مؤنث</label>
                    </div>

 4) تعیین اندازه فیلدها

با استفاده از کلاس‌هایی مانند input-mini، input-small، input-medium، input-large، input-xlarge و input-xxlarge می‌توان اندازه فیلدها را کوچک‌تر از اندازه معمول یا بزرگتر کرد. یا حتی می‌توان از همان کلاس‌های span مانند span12 (اختصاص کل عرض به یک فیلد) و امثال آن برای تعیین اندازه یک فیلد استفاده کرد.
اگر علاقمند هستید که یک textarea کل عرض صفحه را به خود اختصاص دهد، از کلاس input-block-level استفاده کنید.

5) فرم‌های جستجو

 
 
       <form class="search-form">
                <fieldset>
                    <legend>جستجو</legend>
                    <input type="search" class="search-query" />
                    <button type="submit" class="btn" >بیاب</button>
                </fieldset>
       </form>

چند نکته در فرم‌های جستجوی طراحی شده با bootstrap نسبت به بقیه فرم‌ها حائز اهمیت است:
- کلاس فرم بهتر است search-form تعیین شود
- نوع input بهتر است search وارد شود
- کلاس input جستجو نیز search-query انتخاب گردد

همانطور که ملاحظه می‌کنید، در این حالت گوشه‌های جعبه متنی جستجو، نسبت به حالت‌های معمولی آن‌ها گرد شده است. کلاس دکمه نیز btn درنظر گرفته شده است تا حالت ویژه دکمه‌های bootstrap را پیدا کند.

6) فرم‌های افقی

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

 
                <form class="form-horizontal" action="/signup" method="post">
                <fieldset>
                    <legend>ثبت نام</legend>
                    <div class="control-group">
                        <label class="control-label">
                            ایمیل:</label>
                        <div class="controls">
                            <input name="email" type="text" />
                        </div>
                    </div>
                    <div class="control-group">
                        <label class="control-label">
                            نام:</label>
                        <div class="controls">
                            <input name="name" type="text" />
                        </div>
                    </div>
                    <div class="control-group">
                        <div class="controls">
                            <label class="radio inline">
                                <input type="radio" name="isMale" />
                                مذکر</label>
                            <label class="radio inline">
                                <input type="radio" name="isFemale" />
                                مؤنث</label>
                        </div>
                    </div>
                </fieldset>
                </form>

مطابق مثال فوق، خلاصه طراحی فرم‌های افقی با Bootstrap به این نحو است:
- کلاس form-horizontal را به فرم جاری اضافه کنید.
- هر سطر مورد نظر را در div ایی با کلاس control-group محصور نمائید.
- به برچسب‌ها، کلاس control-label را انتساب دهید.
- کنترل‌های مدنظر را در div ایی با کلاس controls محصور کنید.

هر چند این روش نیاز به اندکی HTML نویسی دارد، اما بسیاری به این نوع فرم‌ها بیشتر علاقمند هستند تا فرم‌های عمودی ابتدای بحث.

7) جلب توجه کاربران به فیلدها برای نمایش خطاهای اعتبارسنجی
 

<div class="control-group error">
   <label class="control-label">
                            ایمیل:</label>
    <div class="controls">
           <input name="email" type="text" />
           <span class="help-block">لطفا ایمیل را با فرمت صحیحی وارد نمائید</span>
     </div>
</div>

 
برای تزریق خطاهای اعتبارسنجی ویژه، در اینجا می‌توان از کلاس‌های help-block و یا help-inline به همراه کلاس‌هایی مانند error، info، warning و success استفاده کرد.

8) توسعه فیلدهای استاندارد
 

                <div class="input-prepend input-append">
                    <span dir="ltr" class="add-on">.00</span>
                    <input dir="ltr" type="text" />
                    <span class="add-on">ریال</span>
                </div>

 
توسط ترکیب کلاس‌های input-prepend، input-append و spanهایی با کلاس add-on، می‌توان عناصری بصری خاصی را به عنوان جزئی از فیلد مورد نظر اضافه کرد.

9) HTML Helpers مخصوص ASP.NET MVC برای کار با bootstrap

نکاتی را که در اینجا مطرح شدند، اگر علاقمند بودید که به شکلی strongly typed در ASP.NET MVC اعمال کنید، می‌توان به پروژه‌هایی مانند TwitterBootstrapMvc مراجعه کرد. تعداد این نوع پروژه‌ها هم روز به روز بیشتر می‌شوند:
https://twitterbootstrapmvc.codeplex.com/
https://mvc4bootstaphelper.codeplex.com/
https://github.com/erichexter/twitter.bootstrap.mvc
http://bootstraphelpers.codeplex.com/



تنظیمات خاص دکمه‌ها در حین استفاده از Twitter Bootstrap

در مثال ذیل، کلاس‌های مرتبط با تزئین دکمه‌ها را توسط bootstrap، ملاحظه می‌کنید:
    <div class="container-fluid">
        <div class="row-fluid">
            <div class="span12">
                <table
 class="table table-striped table-hover table-bordered table-condensed">
                    <thead>
                        <tr>
                            <th>
                                دکمه
                            </th>
                            <th>
                                لینک
                            </th>
                            <th>
                                کلاس بکار گرفته شده
                            </th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>
                                <button class="btn">
                                    default</button>
                            </td>
                            <td>
                                <a href="#" class="btn">default</a>
                            </td>
                            <td>
                                <code>btn</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-primary">
                                    primary</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-primary">primary</a>
                            </td>
                            <td>
                                <code>btn btn-primary</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-info">
                                    info</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-info">info</a>
                            </td>
                            <td>
                                <code>btn btn-info</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-success">
                                    success</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-success">success</a>
                            </td>
                            <td>
                                <code>btn btn-success</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-warning">
                                    warning</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-warning">warning</a>
                            </td>
                            <td>
                                <code>btn btn-warning</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-danger">
                                    danger</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-danger">danger</a>
                            </td>
                            <td>
                                <code>btn btn-danger</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-inverse">
                                    inverse</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-inverse">inverse</a>
                            </td>
                            <td>
                                <code>btn btn-inverse</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-link">
                                    link</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-link">link</a>
                            </td>
                            <td>
                                <code>btn btn-link</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-primary btn-large">
                                    large</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-primary btn-large">large</a>
                            </td>
                            <td>
                                <code>btn btn-primary btn-large</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-primary btn-small">
                                    small</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-primary btn-small">small</a>
                            </td>
                            <td>
                                <code>btn btn-primary btn-small</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-primary btn-mini">
                                    mini</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-primary btn-mini">mini</a>
                            </td>
                            <td>
                                <code>btn btn-primary btn-mini</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-primary btn-block">
                                    block</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-primary btn-block">block</a>
                            </td>
                            <td>
                                <code>btn btn-primary btn-block</code>
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <button class="btn btn-primary disabled">
                                    disabled</button>
                            </td>
                            <td>
                                <a href="#" class="btn btn-primary disabled">disabled</a>
                            </td>
                            <td>
                                <code>btn btn-primary disabled</code>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>

همانطور که ملاحظه کردید، الزامی ندارد که این کلاس‌ها را حتما به دکمه‌ها اعمال کرد. برای نمونه می‌توان از یک span یا لینک نیز برای تعریف دکمه‌ها بهره جست. برای یکپارچه سازی چنین دکمه‌هایی (که در اصل دکمه نیستند) با ASP.NET MVC می‌توان به مطلب تکمیلی «استفاده از دکمه‌های CSS توئیتر در ASP.NET MVC» مراجعه نمود.

یک نکته: اگر علاقمند هستید که تعدادی دکمه را به شکل یک toolbar نمایش دهید، آن‌ها را در یک div محصور کرده و کلاس btn-group را به آن div اعمال نمائید.


کار با تصاویر و آیکون‌ها در Twitter Bootstrap

کلاس‌هایی مانند img-rounded، img-circle، img-polaroid با اعمال به یک تصویر، سبب گردن شدن گوشه‌های آن، نمایش دایره‌ای و یا نمایش به همراه حاشیه یک تصویر خواهند شد.
Twitter Bootstrap به همراه صدها آیکون ارائه شده است. این آیکون‌ها توسط glyphicons.com ایجاد شده‌اند. روشی که برای استفاده از آن‌ها توصیه شده است، استفاده از تگ i می‌باشد. برای مثال:
<i class="icon-music"></i>icon-music
البته بدیهی است که محدودیتی در اینجا وجود نداشته و می‌توان این کلاس‌ها را به یک span نیز اعمال کرد.
برای مشاهده لیست کلاس‌های قابل استفاده، کلمه icon-glass را در فایل bootstrap.css جستجو نمائید؛ تا شروع مدخل مرتبط با آیکون‌ها را بتوانید مشاهده نمائید.
رنگ پیش فرض این آیکون‌ها مشکی است. اگر علاقمند بودید که آن‌ها را برای مثال با رنگ سفید نمایش دهید فقط کافی است کلاس icon-white را پس از کلاس آیکون مدنظر،ذکر کرد:
<i class="icon-music icon-white"></i>icon-music
از این نمونه قلم‌های سازگار با Twitter Bootstrap در آدرس fontawesome.github.com نیز قابل دریافت هستند.
امکان اعمال این آیکون‌ها به دکمه‌ها نیز وجود دارد. برای مثال:
    <button class="btn">
        <i class="icon-music"></i>دکمه</button>
کاربرد دیگر این آیکون‌ها در بحث توسعه فیلدهای استاندارد است که پیشتر بحث شد. برای مثال نمایش آیکون نامه در کنار فیلد دریافت ایمیل:
 

 
    <div class="input-prepend">
        <span class="add-on"><i class="icon-envelope"></i></span>
        <input type="email" dir="ltr" />
    </div>


اشتراک‌ها
14 قابلیت بهبود یافته برتر در VB 14

1. 50 درصد سریعتر شدن زمان کامپایل. نسخه فعلی کامپایلر VB در ++C نوشته شده است, ولی تیم VB کامپایلر جدید VB.NET 14 را کاملا در VB.NET بازنویسی کرده اند.نتایج دو مقایسه :

   * زمان Build یک Solution بزرگ(Huge) با 1.3 میلیون خط کد, از 68 ثانیه رسید به 41 ثانیه.

   * زمان Load یک Cold Solution (یک پروژه Win Store) از 6.7 ثانیه رسید به 4.6 ثانیه.

2. به اشتراک گذاری یک پروژه(یک سری ار سورس کد ها) بین چند تا Application

3. نمایش Expression‌های Lambda و LINQ در پنجره Watch و Immediate در زمان Debug

4. قرار دادن کامنت در لا به لای عبارات LINQ

5. استفاده از اپراتور جدید ?. جهت بررسی Null بودن برای تسریع در حین کد نویسی

و ...

14 قابلیت بهبود یافته برتر در VB 14
نظرات مطالب
AngularJS #4
با سلام؛
۱- مفهوم این عبارت رو لطفا توضیح بدید:
«در متد addComment وقتی که دیدگاه مورد نظر اضافه شد، به آرایه‌ی کامنت‌ها یک کامنت جدید می‌افزاییم و چون انقیاد داده دو طرفه است، بالافاصله دیدگاه جدید نیز در view به نمایش در می‌آید.»
این بلافاصله نشون میده از چی استفاده میکنه؟

۲- من تابع  Remvoe رو نوشتم ولی کار نمی‌کنه. یه تغییراتی دادم که آیدی رو  درست بفرست ولی به تابع اصلا وارد نمیشه.
    <button type="button" style="float:right;cursor:pointer;" ng-click="remove({{comment.id}},$Index);">X</button>
خطا :
"Error: [$parse:syntax] Syntax Error: Token '{' invalid key at column 9 of the expression [remove({{comment.id}},$Index);] starting at [{comment.id}},$Index);].
مطالب
MVC Scaffolding #1
پیشنیازها
کل سری ASP.NET MVC
به همراه کل سری EF Code First


MVC Scaffolding چیست؟

MVC Scaffolding ابزاری است برای تولید خودکار کدهای «اولیه» برنامه، جهت بالا بردن سرعت تولید برنامه‌های ASP.NET MVC مبتنی بر EF Code First.


بررسی مقدماتی MVC Scaffolding

امکان اجرای ابزار MVC Scaffolding از دو طریق دستورات خط فرمان Powershell و یا صفحه دیالوگ افزودن یک کنترلر در پروژه‌های ASP.NET MVC وجود دارد. در ابتدا حالت ساده و ابتدایی استفاده از صفحه دیالوگ افزودن یک کنترلر را بررسی خواهیم کرد تا با کلیات این فرآیند آشنا شویم. سپس در ادامه به خط فرمان Powershell که اصل توانمندی‌ها و قابلیت‌های سفارشی MVC Scaffolding در آن قرار دارد، خواهیم پرداخت.
برای این منظور یک پروژه جدید MVC را آغاز کنید؛ ابزارهای مقدماتی MVC Scaffolding از اولین به روز رسانی ASP.NET MVC3 به بعد با VS.NET یکپارچه هستند.
ابتدا کلاس زیر را به پوشه مدل‌های برنامه اضافه کنید:
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace MvcApplication1.Models
{
    public class Task
    {
        public int Id { set; get; }

        [Required]
        public string Name { set; get; }

        [DisplayName("Due Date")]
        public DateTime? DueDate { set; get; }

        [DisplayName("Is Complete")]
        public bool IsComplete { set; get; }

        [StringLength(450)]
        public string Description { set; get; }
    }
}
سپس بر روی پوشه Controllers کلیک راست کرده و گزینه Add controller را انتخاب کنید. تنظیمات صفحه ظاهر شده را مطابق شکل زیر تغییر دهید:


همانطور که ملاحظه می‌کنید در قسمت قالب‌ها، تولید کنترلرهایی با اکشن متد‌های ثبت و نمایش اطلاعات مبتنی بر EF Code First انتخاب شده است. کلاس مدل نیز به کلاس Task فوق تنظیم گردیده و در زمان انتخاب DbContext مرتبط، گزینه new data context را انتخاب کرده و نام پیش فرض آن‌را پذیرفته‌ایم. زمانیکه بر روی دکمه Add کلیک کنیم، اتفاقات ذیل رخ خواهند داد:


الف) کنترلر جدید TasksController.cs به همراه تمام کدهای Insert/Update/Delete/Display مرتبط تولید خواهد شد.
ب) کلاس DbContext خودکاری به نام MvcApplication1Context.cs در پوشه مدل‌های برنامه ایجاد می‌گردد تا کلاس Task را در معرض دید EF Code first قرار دهد. (همانطور که عنوان شد یکی از پیشنیازهای بحث Scaffolding آشنایی با EF Code first است)
ج) در پوشه Views\Tasks، پنج View جدید را جهت مدیریت فرآیندهای نمایش صفحات Insert، حذف، ویرایش، نمایش و غیره تهیه می‌کند.
د) فایل وب کانفیگ برنامه جهت درج رشته اتصالی به بانک اطلاعاتی تغییر کرده است. حالت پیش فرض آن استفاده از SQL CE است و برای استفاده از آن نیاز است قسمت 15 سری EF سایت جاری را پیشتر مطالعه کرده باشید (به چه اسمبلی‌های دیگری مانند System.Data.SqlServerCe.dll برای اجرا نیاز است و چطور باید اتصال به بانک اطلاعاتی را تنظیم کرد)

معایب:
کیفیت کد تولیدی پیش فرض قابل قبول نیست:
- DbContext در سطح یک کنترلر وهله سازی شده و الگوی Context Per Request در اینجا بکارگرفته نشده است. واقعیت یک برنامه ASP.NET MVC کامل، داشتن چندین Partial View تغدیه شونده از کنترلرهای مختلف در یک صفحه واحد است. اگر قرار باشد به ازای هر کدام یکبار DbContext وهله سازی شود یعنی به ازای هر صفحه چندین بار اتصال به بانک اطلاعاتی باید برقرار شود که سربار زیادی را به همراه دارد. (قسمت 12 سری EF سایت جاری)
- اکشن متدها حاوی منطق پیاده سازی اعمال CRUD یا همان Create/Update/Delete هستند. به عبارتی از یک لایه سرویس برای خلوت کردن اکشن متدها استفاده نشده است.
- از ViewModel تعریف شده‌ای به نام Task هم به عنوان Domain model و هم ViewModel استفاده شده است. یک کلاس متناظر با جداول بانک اطلاعاتی می‌تواند شامل فیلدهای بیشتری باشد و نباید آن‌را مستقیما در معرض دید یک View قرار داد (خصوصا از لحاظ مسایل امنیتی).

مزیت‌ها:
قسمت عمده‌ای از کارهای «اولیه» تهیه یک کنترلر و همچنین Viewهای مرتبط به صورت خودکار انجام شده‌اند. کارهای اولیه‌ای که با هر روش و الگوی شناخته شده‌ای قصد پیاده سازی آن‌ها را داشته باشید، وقت زیادی را به خود اختصاص داده و نهایتا آنچنان تفاوت عمده‌ای هم با کدهای تولیدی در اینجا نخواهند داشت. حداکثر فرم‌های آن‌را بخواهید با jQuery Ajax پیاده سازی کنید یا کنترل‌های پیش فرض را با افزونه‌های jQuery غنی سازی نمائید. اما شروع کار و کدهای اولیه چیزی بیشتر از این نیست.


نصب بسته اصلی MVC Scaffolding توسط NuGet

بسته اصلی MVC Scaffolding را با استفاده از دستور خط فرمان Powershell ذیل، از طریق منوی Tools، گزینه Library package manager و انتخاب Package manager console می‌توان به پروژه خود اضافه کرد:
Install-Package MvcScaffolding
اگر به مراحل نصب آن دقت کنید یک سری وابستگی را نیز به صورت خودکار دریافت کرده و نصب می‌کند:
Attempting to resolve dependency 'T4Scaffolding'.
Attempting to resolve dependency 'T4Scaffolding.Core'.
Attempting to resolve dependency 'EntityFramework'.
Successfully installed 'T4Scaffolding.Core 1.0.0'.
Successfully installed 'T4Scaffolding 1.0.8'.
Successfully installed 'MvcScaffolding 1.0.9'.
Successfully added 'T4Scaffolding.Core 1.0.0' to MvcApplication1.
Successfully added 'T4Scaffolding 1.0.8' to MvcApplication1.
Successfully added 'MvcScaffolding 1.0.9' to MvcApplication1.
از مواردی که با T4 آغاز شده‌اند در قسمت‌های بعدی برای سفارشی سازی کدهای تولیدی استفاده خواهیم کرد.
پس از اینکه بسته MvcScaffolding به پروژه جاری اضافه شد، همان مراحل قبل را که توسط صفحه دیالوگ افزودن یک کنترلر انجام دادیم، اینبار به کمک دستور ذیل نیز می‌توان پیاده سازی کرد:
Scaffold Controller Task
نوشتن این دستور نیز ساده است. حروف sca را تایپ کرده و دکمه tab را فشار دهید. منویی ظاهر خواهد شد که امکان انتخاب دستور Scaffold را می‌دهد. یا برای نوشتن Controller نیز به همین نحو می‌توان عمل کرد.
نکته و مزیت مهم دیگری که در اینجا در دسترس می‌باشد، سوئیچ‌های خط فرمانی است که به همراه صفحه دیالوگ افزودن یک کنترلر وجود ندارند. برای مثال دستور Scaffold Controller را تایپ کرده و سپس یک خط تیره را اضافه کنید. اکنون دکمه tab را مجددا بفشارید. منویی ظاهر خواهد شد که بیانگر سوئیچ‌های قابل استفاده است.


برای مثال اگر بخواهیم دستور Scaffold Controller Task را با جزئیات اولیه کاملتری ذکر کنیم، مانند تعیین نام دقیق کلاس مدل و کنترلر تولیدی به همراه نام دیگری برای DbContext مرتبط، خواهیم داشت:
Scaffold Controller -ModelType Task -ControllerName TasksController -DbContextType TasksDbContext
اگر این دستور را اجرا کنیم به همان نتیجه حاصل از مراحل توضیح داده شده قبل خواهیم رسید؛ البته یا یک تفاوت: یک Partial View اضافه‌تر نیز به نام CreateOrEdit در پوشه Views\Tasks ایجاد شده است. این Partial View بر اساس بازخورد برنامه نویس‌ها مبنی بر اینکه Viewهای Edit و Create بسیار شبیه به هم هستند، ایجاد شده است.


بهبود مقدماتی کیفیت کد تولیدی MVC Scaffolding

در همان کنسول پاروشل NuGet، کلید up arrow را فشار دهید تا مجددا دستور قبلی اجرا شده ظاهر شود. اینبار دستور قبلی را با سوئیچ جدید Repository (استفاده از الگوی مخزن) اجرا کنید:
Scaffold Controller -ModelType Task -ControllerName TasksController -DbContextType TasksDbContext -Repository
البته اگر دستور فوق را به همین نحو اجرا کنید با یک سری خطای Skipping مواجه خواهید شد مبنی بر اینکه فایل‌های قبلی موجود هستند و این دستور قصد بازنویسی آن‌ها را ندارد. برای اجبار به تولید مجدد کدهای موجود می‌توان از سوئیچ Force استفاده کرد:
Scaffold Controller -ModelType Task -ControllerName TasksController -DbContextType TasksDbContext -Repository -Force
اتفاقی که در اینجا رخ خواهد داد، بازنویسی کد بی‌کیفت ابتدایی همراه با وهله سازی مستقیم DbContext در کنترلر، به نمونه بهتری که از الگوی مخزن استفاده می‌کند می‌باشد:
    public class TasksController : Controller
    {
        private readonly ITaskRepository taskRepository;

        // If you are using Dependency Injection, you can delete the following constructor
        public TasksController()
            : this(new TaskRepository())
        {
        }

        public TasksController(ITaskRepository taskRepository)
        {
            this.taskRepository = taskRepository;
        }
کیفیت کد تولیدی جدید مبتنی بر الگوی مخزن بد نیست؛ دقیقا همانی است که در هزاران سایت اینترنتی تبلیغ می‌شود؛ اما ... آنچنان مناسب هم نیست و اشکالات زیر را به همراه دارد:
public interface ITaskRepository : IDisposable
{
  IQueryable<Task> All { get; }
  IQueryable<Task> AllIncluding(params Expression<Func<Task, object>>[] includeProperties);
  Task Find(int id);
  void InsertOrUpdate(Task task);
  void Delete(int id);
  void Save();
}
اگر به ITaskRepository تولیدی دقت کنیم دارای خروجی IQueryable است؛ به این حالت leaky abstraction گفته می‌شود. زیرا امکان تغییر کلی یک خروجی IQueryable در لایه‌های دیگر برنامه وجود دارد و حد و مرز سیستم توسط آن مشخص نخواهد شد. بهتر است خروجی‌های لایه سرویس یا لایه مخزن در اینجا از نوع‌های IList یا IEnumerable باشند که درون آن‌ها از IQueryable‌ها برای پیاده سازی منطق مورد نظر کمک گرفته شده است.
پیاده سازی این اینترفیس در حالت متد Save آن شامل فراخوانی context.SaveChanges است. این مورد باید به الگوی واحد کار (که در اینجا تعریف نشده) منتقل شود. زیرا در یک دنیای واقعی حاصل کار بر روی چندین موجودیت باید در یک تراکنش ذخیره شوند و قرارگیری متد Save داخل کلاس مخزن یا سرویس برنامه، مخزن‌های تعریف شده را تک موجودیتی می‌کند.
اما در کل با توجه به اینکه پیاده سازی منطق کار با موجودیت‌ها به کلاس‌های مخزن واگذار شده‌اند و کنترلرها به این نحو خلوت‌تر گردیده‌اند، یک مرحله پیشرفت محسوب می‌شود.
مطالب
استفاده از EF در اپلیکیشن های N-Tier : قسمت ششم
در قسمت قبل رویکرد‌های مختلف برای حذف موجودیت‌های منفصل را بررسی کردیم. در این قسمت مدیریت همزمانی یا Concurrency را بررسی خواهیم کرد.


فرض کنید می‌خواهیم مطمئن شویم که موجودیتی که توسط یک کلاینت WCF تغییر کرده است، تنها در صورتی بروز رسانی شود که شناسه (token) همزمانی آن تغییر نکرده باشد. به بیان دیگر شناسه ای که هنگام دریافت موجودیت بدست می‌آید، هنگام بروز رسانی باید مقداری یکسان داشته باشد.

مدل زیر را در نظر بگیرید.


می‌خواهیم یک سفارش (order) را توسط یک سرویس WCF بروز رسانی کنیم در حالی که اطمینان حاصل می‌کنیم موجودیت سفارش از زمانی که دریافت شده تغییری نکرده است. برای مدیریت این وضعیت دو رویکرد تقریبا متفاوت را بررسی می‌کنیم. در هر دو رویکرد از یک ستون همزمانی استفاده می‌کنیم، در این مثال فیلد TimeStamp.

  • در ویژوال استودیو پروژه جدیدی از نوع WCF Service Library بسازید و نام آن را به Recipe6 تغییر دهید.
  • روی نام پروژه کلیک راست کنید و گزینه Add New Item را انتخاب کنید. سپس گزینه‌های Data -> Entity Data Model را برگزینید. از ویزارد ویژوال استودیو برای اضافه کردن مدل جاری و جدول Orders استفاده کنید. در EF Designer روی فیلد TimeStamp کلیک راست کنید و گزینه Properties را انتخاب کنید. سپس مقدار CuncurrencyMode آنرا به Fixed تغییر دهید.
  • فایل IService1.cs را باز کنید و تعریف سرویس را مطابق لیست زیر بروز رسانی کنید.
[ServiceContract]
public interface IService1
{
    [OperationContract]
    Order InsertOrder();
    [OperationContract]
    void UpdateOrderWithoutRetrieving(Order order);
    [OperationContract]
    void UpdateOrderByRetrieving(Order order);
}

  • فایل Service1.cs را باز کنید و پیاده سازی سرویس را مطابق لیست زیر تکمیل کنید.
public class Service1 : IService1
{
    public Order InsertOrder()
    {
        using (var context = new EFRecipesEntities())
        {
            // remove previous test data
            context.Database.ExecuteSqlCommand("delete from [orders]");
            var order = new Order
            {
                Product = "Camping Tent",
                Quantity = 3,
                Status = "Received"
            };
            context.Orders.Add(order);
            context.SaveChanges();
            return order;
        }
    }

    public void UpdateOrderWithoutRetrieving(Order order)
    {
        using (var context = new EFRecipesEntities())
        {
            try
            {
                context.Orders.Attach(order);
                if (order.Status == "Received")
                {
                    context.Entry(order).Property(x => x.Quantity).IsModified = true;
                    context.SaveChanges();
                }
            }
            catch (OptimisticConcurrencyException ex)
            {
                // Handle OptimisticConcurrencyException
            }
        }
    }

    public void UpdateOrderByRetrieving(Order order)
    {
        using (var context = new EFRecipesEntities())
        {
            // fetch current entity from database
            var dbOrder = context.Orders
            .Single(o => o.OrderId == order.OrderId);
            if (dbOrder != null &&
                // execute concurrency check
                StructuralComparisons.StructuralEqualityComparer.Equals(order.TimeStamp, dbOrder.TimeStamp))
            {
                dbOrder.Quantity = order.Quantity;
                context.SaveChanges();
            }
            else
            {
                // Add code to handle concurrency issue
            }
        }
    }
}


  • برای تست این سرویس به یک کلاینت نیاز داریم. پروژه جدیدی از نوع Console Application به راه حل جاری اضافه کنید و کد آن را مطابق لیست زیر تکمیل کنید. با کلیک راست روی نام پروژه و انتخاب گزینه Add Service Reference سرویس پروژه را هم ارجاع کنید. دقت کنید که ممکن است پیش از آنکه بتوانید سرویس را ارجاع کنید نیاز باشد روی آن کلیک راست کرده و از منوی Debug گزینه Start Instance را انتخاب کنید تا وهله از سرویس به اجرا در بیاید.
class Program
{
    static void Main(string[] args)
    {
        var service = new Service1Client();
        var order = service.InsertOrder();
        order.Quantity = 5;
        service.UpdateOrderWithoutRetrieving(order);
        order = service.InsertOrder();
        order.Quantity = 3;
        service.UpdateOrderByRetrieving(order);
    }
}
اگر به خط اول متد ()Main یک breakpoint اضافه کنید و اپلیکیشن را اجرا کنید می‌توانید افزودن و بروز رسانی یک Order با هر دو رویکرد را بررسی کنید.


شرح مثال جاری

متد ()InsertOrder داده‌های پیشین را حذف می‌کند، سفارش جدیدی می‌سازد و آن را در دیتابیس ثبت می‌کند. در آخر موجودیت جدید به کلاینت باز می‌گردد. موجودیت بازگشتی هر دو مقدار OrderId و TimeStamp را دارا است که توسط دیتابیس تولید شده اند. سپس در کلاینت از دو رویکرد نسبتا متفاوت برای بروز رسانی موجودیت استفاده می‌کنیم.

در رویکرد نخست، متد ()UpdateOrderWithoutRetrieving موجودیت دریافت شده از کلاینت را Attach می‌کند و چک می‌کند که مقدار فیلد Status چیست. اگر مقدار این فیلد "Received" باشد، فیلد Quantity را با EntityState.Modified علامت گذاری می‌کنیم و متد ()SaveChanges را فراخوانی می‌کنیم. EF دستورات لازم برای بروز رسانی را تولید می‌کند، که فیلد quantity را مقدار دهی کرده و یک عبارت where هم دارد که فیلدهای OrderId و TimeStamp را چک می‌کند. اگر مقدار TimeStamp توسط یک دستور بروز رسانی تغییر کرده باشد، بروز رسانی جاری با خطا مواجه خواهد شد. برای مدیریت این خطا ما بدنه کد را در یک بلاک try/catch قرار می‌دهیم، و استثنای OptimisticConcurrencyException را مهار می‌کنیم. این کار باعث می‌شود اطمینان داشته باشیم که موجودیت Order دریافت شده از متد ()InsertOrder تاکنون تغییری نکرده است. دقت کنید که در مثال جاری تمام خواص موجودیت بروز رسانی می‌شوند، صرفنظر از اینکه تغییر کرده باشند یا خیر.

رویکرد دوم نشان می‌دهد که چگونه می‌توان وضعیت همزمانی موجودیت را پیش از بروز رسانی مشخصا دریافت و بررسی کرد. در اینجا می‌توانید مقدار TimeStamp موجودیت را از دیتابیس بگیرید و آن را با مقدار موجودیت کلاینت مقایسه کنید تا وجود تغییرات مشخص شود. این رویکرد در متد ()UpdateOrderByRetrieving نمایش داده شده است. گرچه این رویکرد برای تشخیص تغییرات خواص موجودیت‌ها و یا روابط شان مفید و کارآمد است، اما بهترین روش هم نیست. مثلا ممکن است از زمانی که موجودیت را از دیتابیس دریافت می‌کنید، تا زمانی که مقدار TimeStamp آن را مقایسه می‌کنید و نهایتا متد ()SaveChanges را صدا میزنید، موجودیت شما توسط کلاینت دیگری بروز رسانی شده باشد.

مسلما رویکرد دوم هزینه بر‌تر از رویکرد اولی است، چرا که برای مقایسه مقادیر همزمانی موجودیت ها، یکبار موجودیت را از دیتابیس دریافت می‌کنید. اما این رویکرد در مواقعی که Object graph‌‌های بزرگ یا پیچیده (complex) دارید بهتر است، چون پیش از ارسال موجودیت‌ها به context در صورت برابر نبودن مقادیر همزمانی پروسس را لغو می‌کنید.

مطالب
آشنایی با WPF قسمت چهارم: کنترل ها
WPF همانند Windows Form شامل ابزارها یا کنترل‌های داخلی است که می‌توانند در تهیه‌ی یک برنامه بسیار کارآمد باشند. در این بخش به بررسی تعدادی از این کنترل‌ها می‌پردازیم و مابقی آن‌ها را در قسمت‌های آینده بررسی خواهیم کرد. در این نوشتار سعی بر این است که یک فرم ساده را با آن ایجاد کرده و مورد استفاده قرار دهیم.
این فرم دارای اطلاعاتی شامل : نام، جنسیت ، زمینه‌های کاری، کشور، تاریخ تولد و تصویر می‌باشد.

TextBlock

همان Label قدیمی خودمان است که برای نمایش متون کاربر دارد. متن داخل آن بین دو تگ قرار می‌گیرد و یا از خاصیت Text آن کمک گرفته خواهد شد. حتما از خاصیت Width و height آن برای مقداردهی کمک بگیرید، زیرا در غیر آن صورت کل Container خود را خواهد پوشاند. در صورتی که متنی در مکان خود جا نشود می‌توان از دو ویژگی استفاده کرد. آن را برش داد یا به خطوط بعدی شکست. برای حذف یا برش باقی مانده متن می‌توان از خصوصیت TextTrimming استفاده کرد که سه مقدار می‌گیرد:

None مقدار پیش فرض

CharacterEllipsis با نزدیک شدن به آخر پهنای کار از ... استفاده می‌نماید. در صورتی که لیستی یا مورد مشابهی دارید میتواند بسیار کاربردی باشد.

WordEllipsis این گزینه هم مانند مورد بالاست با این تفاوت که سعی دارد تا آنجا که ممکن است خود را به آخرین حرف کلمه برساند تا شکستگی در وسط کلمه اتفاق نیفتد و آخرین کلمه کامل دیده شود و بعد ... قرار بگیرد؛ هر چند در تست‌های خودم تفاوتی مشاهده نکردم.

گزینه TextWrapping جهت شکستن یک خط به خطوط است؛ موقعی که متن شما به انتهای صفحه می‌رسد، این ویژگی باعث می‌شود متن به بیرون از پنجره نرفته و یک خط به سمت پایین حرکت کند. این گزینه سه مقدار را دارد:

تصویر زیر حالت اصلی نمایش بدون نیاز به Wrap شدن است:

None: مقدار پیش فرض که خصوصیت Wrap را به همراه ندارد.

Wrap: فعال سازی ویژگی TextWrapping

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

خصوصیت LineStackingStrategy:

این خصوصیت فاصله‌ی بین خطوط را با استفاده از یک واحد منطقی dp مشخص می‌کند. هر چند دو گزینه دیگر هم دارد که دو تصویر زیر را در این صفحه به شما نمایش می‌دهد:

برای ساخت فرم از یک گرید با سه ستون و 6 سطر استفاده می‌کنم.

<Grid Margin="5">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        
        </Grid.RowDefinitions>
</Grid>
در ستون اول نام فیلدهای مورد نظر را می‌نویسیم و در ستون دوم هم کنترل‌های مد نظر هر فیلد را قرار خواهیم داد. در صورتی که دوست دارید کار از راست به چپ پشتیبانی کند از گزینه OverflowDirection در تگ پنجره Window استفاده نمایید.
در داخل گرید بعد از تعریف سطر و ستون، همانطور که قبلا توضیح دادیم کنترل‌های TextBlock را اضافه می‌کنیم:
<TextBlock Grid.Column="0"  Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" >Name</TextBlock>
        <TextBlock Grid.Column="0"  Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Left" >Gender</TextBlock>
        <TextBlock Grid.Column="0"  Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" >Field Of Work</TextBlock>
        <TextBlock Grid.Column="0"  Grid.Row="3" VerticalAlignment="Center" HorizontalAlignment="Left" >Country</TextBlock>
        <TextBlock Grid.Column="0"  Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" >Birth Date</TextBlock>

<TextBox Grid.Row="0" Grid.Column="1" Name="Txtname" HorizontalAlignment="Left" Margin="5" Width="200" ></TextBox>
برای فیلد نام، از کنترل TextBox استفاده کردم که با محدود کردن Width آن اندازه ثابت به آن دادم. در صورتی که width ذکر نشود یا به Auto ذکر شود، در صورتی که متنی که کاربر تایپ می‌کند، بیش از اندازه تعیین شده کنترل Textbox باشد، کنترل هم همراه متن بزرگتر خواهد شد و تا پایان محدوده سلولی اش در گرید کش خواهد آمد.

Buttons 
برای فیلد جنسیت Gender هم از RadioButton کمک گرفتم که با استفاده از خاصیت GroupName می‌توان دسته‌ای از این کنترل‌ها را با هم مرتبط ساخت تا با انتخاب یک آیتم جدید از همان گروه، آیتم قبلی که انتخاب شده بود از حالت انتخاب خارج شده و آیتم جدیدی انتخاب شود. از خاصیت IsChecked می‌توان برای انتخاب یک آیتم بهره برد.

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

  • Button
  • ToggleButton
  • CheckBox
  • RadioButton

که همگی این عناصر از کلاسی به نام ButtonBase مشتق شده اند. کد زیر RadioButton‌ها را به صورت عمودی چینش کرده است:

<StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="1" Margin="10">
            <RadioButton GroupName="Gender" Name="RdoMale" IsChecked="True" >Male</RadioButton>
            <RadioButton GroupName="Gender" Name="RdoFemale" Margin="0 5 0 0" >Female</RadioButton>
        </StackPanel>
برای فیلد زمینه کاری ، لیست کشورها و تاریخ تولد از کدهای زیر کمک گرفتم:
<StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="1" Margin="10">
            <CheckBox Name="ChkActor" >Actor/Actress</CheckBox>
            <CheckBox Name="ChkDirector" >Director</CheckBox>
            <CheckBox Name="ChkProducer" >Producer</CheckBox>
        </StackPanel>

        <ListBox Grid.Row="3" Grid.Column="1" Margin="10"  Height="80">
        <ListBoxItem>
                <TextBlock>UnitedStates</TextBlock>
            </ListBoxItem>
            <ListBoxItem>
                <TextBlock >UK</TextBlock>
            </ListBoxItem>
            <ListBoxItem>
                <TextBlock >France</TextBlock>
            </ListBoxItem>
            <ListBoxItem>
                <TextBlock >Japan</TextBlock>
            </ListBoxItem>
        </ListBox>

        <Calendar Grid.Row="4" Grid.Column="1" HorizontalAlignment="Left" Margin="10"></Calendar>
برای لیست کشورها می‌توان از یک ListBox یا ComboBox استفاده کرده که هر آیتم داخل آنها در یک تگ ListBoxItem یا ComboBoxItem قرار می‌گیرد. اگر از حالت ListBox استفاده می‌کنید، در صورتی که آیتم‌ها از ارتفاع لیست بیشتر شود به طور خودکار یک Scrollbar برای آن‌ها در نظر گرفته خواهد شد و نیازی نیست که آن را دستی اضافه کنید.
برای تصویر شخص، قصد دارم آن را در گوشه‌ی سمت راست و بالا قرار دهم. برای همین محل ستون آن را ستون سوم یا اندیس دوم انتخاب کرده و از آنجا که این عکس حالت پرسنلی دارد، می‌تواند چند سطر را به خود اختصاص دهد که با کمک خاصیت Rowspan، چهار سطر، کنترل را ادامه دادم. برای ستون‌ها هم می‌توان از خاصیت ColumnSpan استفاده کرد. همچنین دوست دارم یک دکمه هم روی تصویر در گوشه‌ی سمت چپ و پایین قرار داده که کاربر با انتخاب آن به انتخاب عکس یا تغییر آن بپردازد. برای همین از یک پنل گرید استفاده کردم و کنترل دکمه را روی تصویر قرار دادم. همپوشانی کنترل‌ها در اینجا صورت گرفته است.

 <Grid Grid.Row="0" Grid.Column="2" Grid.RowSpan="4">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Image HorizontalAlignment="Right" Source="man.jpg" Stretch="UniformToFill" VerticalAlignment="Top" Width="100" Height="150"></Image>
            <Button Width="25" Height="15"    Padding="0"  HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="0,0,0,83">
                 <TextBlock VerticalAlignment="Center" Margin="0 -7 0 0">...</TextBlock>
            </Button>
        </Grid>
خاصیت Stretch کنترل Image در بالا، نحوه‌ی نمایش تصویر را نشان می‌دهد که چهار مقدار دارد:
None: تصویر، اندازه‌ی اصلی خود را حفظ کرده و هر مقدار آن که در کنترل جا شود، نمایش می‌یابد و بسته به سایز تصویر ممکن است گوشه هایی از تصویر نمایش نیابد.
Fill: تصویر را داخل کنترل به زور جا داده تا پهنا و ارتفاع عکس، هم اندازه کنترل می‌شود.
Uniform: تصویر بزرگ را با در نظر گرفتن نسبت پهنا و ارتفاع تصویر، با یکدیگر در کنترل جا می‌دهد.
UniformToFill: تصویر، کل کنترل را می‌گیرد ولی نسبت پهنا و عرض را حفظ کرده ولی قسمت هایی از تصویر در کنترل دیده نمی‌شود.

همانطور که قبلا هم گفتیم، خود کنترل دکمه شامل زیر کنترل‌هایی می‌شود که یکی از آن‌ها TextBlock است و از طریق خصوصیت *.TextBlock دیگر خصوصیات آن قابل تنظیم است و البته برای خصوصی سازی بیشتر هم می‌توان یک TextBlock را به صورت Nested یعنی داخل تگ Button تعریف کنید که ما همین کار را کرده ایم.
فرم نهایی ما به صورت زیر است:


در صورتی که دوست دارید جهت ListBox را از عمودی به افقی تغییر دهید می‌توانید از پنل‌های Stack یا Wrap استفاده کنید که تعریف آن به شکل زیر است:
<ListBox>
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

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



و در صورتی که می‌خواهید Scroll حذف شود و از Wrap استفاده کنید، کد را به شکل زیر تعریف کنید. فراموش نکنید که اسکرول افقی را غیرفعال کنید؛ وگرنه نتیجه کار به شکل بالا خواهد بود.
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>
نتیجه:

Calendar
تقویم یکی دیگر از کنترل‌های موجود است که شامل خصوصیات زیر است:
DisplayDate: تاریخ پیش فرض و اولیه تقویم را مشخص می‌کند؛ در صورتی که ذکر نشود تاریخ جاری درج می‌شود.
<Calendar DisplayDate="01.01.2010" />
از خصوصیات دیگر در این زمینه می‌توان به DisplayDateStart و DisplayDateEnd اشاره کرد که محدوه‌ی نمایش تاریخ تقویم را مشخص می‌کند. کد زیر تنها تاریخ‌های روز اول ماه ابتدای سال 2015، تا روز اول ماه پنجم 2015 را نمایش می‌دهد:
<Calendar DisplayDateStart="01.01.2015" DisplayDateEnd="05.01.2015" />


SelectionMode: نحوه‌ی انتخاب تاریخ را مشخص می‌کند:
SingleDate: فقط یک تاریخ قابل انتخاب است.
SingleRange: می‌توانید از یک تاریخ تا تاریخ دیگر را انتخاب کنید. ولی نمی‌توانید مجددا چند انتخاب دیگر را در جای جای تقویم داشته باشید. مثلا از تاریخ 5 آپریل تا 10 آپریل را انتخاب کرده‌اید؛ ولی دیگر نمی‌توانید تاریخ 15 آپریل یا محدوده‌ی 15 آپریل تا 20 آپریل را انتخاب کنید. چون تنها قادر به انتخاب یک رنج یا محدوده تاریخی هستید.
MultipleRanges: بر خلاف گزینه‌ی بالایی هر محدوده تاریخی قابل انتخاب است.
<Calendar SelectionMode="MultipleRange" />

نکته بعدی در مورد غیرفعال کردن بعضی از تاریخ هاست که شما قصد ندارید به کاربر اجازه دهید آن‌ها را انتخاب کند. برای مثال تاریخ‌های 1 آپریل تا 10 آپریل را از دسترس خارج کنید. برای همین از خصوصیت BlackoutDates استفاده می‌کنیم که نحوه‌ی تعریف آن به شرح زیر است که در این کد دو محدوده‌ی تاریخی غیر فعال شده اند:
<Calendar>
    <Calendar.BlackoutDates>
        <CalendarDateRange Start="01/01/2010" End="01/06/2010" />
        <CalendarDateRange Start="05/01/2010" End="05/03/2010" />
    </Calendar.BlackoutDates>
</Calendar>



DisplayMode
: به طور پیش فرض، تقویم ماه‌ها را نشان می‌دهد ولی میتوانید آن را توسط این خصوصیت روی سال یا دهه و ماه هم تنظیم کنید.
با انتخاب سال Year، تقویم ماه‌های یک سال را نمایش می‌دهد.
با انتخاب دهه Decades سال‌های یک دهه‌ی تعیین شده را نشان می‌دهد و با انتخاب ماه Month روز‌های هر ماه در آن نمایش داده می‌شود.
در هنگام انتخاب این گزینه، به داخل تقویم نگاه نکنید، بلکه به سر تیتر آن نگاه کنید.
<Calendar DisplayMode="Year" />



مطالب
فقط به خاطر یک نیم فاصله!
نسخه‌ی 64 بیتی ویندوز 7 را نصب کرده‌ام و اولین مشکل، نبود صفحه کلید مطابق استاندارد 2091 برای نسخه‌های 64 بیتی ویندوز است. پروژه وب فارسی دانشگاه صنعتی شریف، سال‌ها قبل فقط یک نسخه‌ی 32 بیتی از آن را تهیه کرده و نسخه‌های 64 بیتی موجود، مطابق استاندارد 9147 هستند و من به دلایل ذیل حاضر به استفاده از آن نیستم!
  1. در استاندارد 9147 ، جای ژ و پ مطابق صفحه کلیدی که در بازار ایران فروخته می‌شود نیست (و باید به همه پاسخگو باشید که چرا اینطوری است).
  2. ی و ک در آن اصلاح شده و دیگر عربی نیست که چقدر هم خوب، اما من تعداد زیادی برنامه و همچنین تعداد قابل توجهی فایل word دارم که مطابق استاندارد 2091 تهیه شده‌اند. مشکلات ی و ک فارسی و عربی را هم در اینجا ذکر کرده‌ام و به دنبال باگ‌های جدید در برنامه‌ها نمی‌گردم.
  3. با ی و ک فارسی اگر در گوگل جستجو کنید تعداد پاسخ‌های مرتبط یافت شده بسیار بسیار کمتر از حالتی خواهد بود که با ی و ک عربی جستجو کنید.
  4. در یک سازمان باید رویه‌ا‌ی واحد در این مورد برقرار باشد. یا همه باید از 2091 استفاده کنند و یا همه از 9147.

نسخه‌ی کامل استاندارد 9147 را از سایت آقای اخگری می‌توانید دریافت نمائید:

به همین دلایل خصوصا قسمت دوم (هر چند ممکن است با آن موافق نباشید)، نیاز به صفحه کلید مطابق استاندارد 2091 نسخه‌ی 64 بیتی داشتم.

برای تهیه صفحه کلید فارسی از برنامه Microsoft Keyboard Layout Creator استفاده می‌شود که نسخه‌ی 1.4 آن‌را از آدرس زیر می‌توانید دریافت نمائید. این نسخه قابلیت تولید فایل‌های dll مرتبط 64 بیتی را هم دارد:


یکی از قابلیت‌های این برنامه بارگذاری صفحه کلید فارسی جاری سیستم است:



صفحه کلید استاندارد 2091 پروژه وب فارسی را اگر با آن باز کرده و سپس از منوی Project گزینه‌ی Build DLL and setup package را انتخاب نمائید، با خطای زیر متوقف خواهید شد:
ERROR: 'VK_SPACE' in Shift State 'Shift' must be made up of white space character(s), but is defined as '‌' (U+200c) instead.
که دقیقا مربوطه به این سطر در تعاریف صفحه کلید است (صفحه کلید را می‌شود به صورت فایلی با پسوند klc هم save as کرد):
39 SPACE  0 0020 200c 0020 -1  // SPACE, ZERO WIDTH NON-JOINER, SPACE, <none>
مفاهیم این ستون‌ها هم به شرح زیر هستند:
0 //Column 4
1 //Column 5 : Shft
2 //Column 6 :       Ctrl
3 //Column 7 : Shft  Ctrl
یعنی جهت نمایش نیم فاصله حاصل از ترکیب shift space مطابق استاندارد تایپ ایران، بجای 0x0020 یا همان فاصله، از 0x200C استفاده شده است (مطابق استاندارد تایپ ایران باید نوشت "می‌روم" و نه "می روم". به نیم فاصله و فاصله دقت بفرمائید).
اما این برنامه‌ی محترم دقیقا همین مورد را غلط گرفته و فایل dll نهایی را تولید نمی‌کند (مطابق خطایی که ذکر شد).
برنامه‌ی Microsoft Keyboard Layout Creator هم با دات نت فریم ورک نوشته شده است. اگر کمی با reflector به آنالیز آن بپردازیم به کلاس Accept و متد زیر خواهیم رسید:
private bool VerifySpaceBarIntegrity(ShiftState ss, bool fMustBeDefined)
در این متد جایی که خطای ذکر شده صادر می‌شود، مربوط به چند سطر زیر است:
if (!Utilities.IsSpacing(ss.Characters))
{
    this.WriteErrorToLogFile("SpaceKeyNeedsWhiteSpaceCharacters", new string[] { "VK_" + Utilities.VkStringOfIvk(ss.VK), this.m_stStateLabel[ss.State], ss.Characters, Utilities.FromCharacterToUPlusForm(ss.Characters) });
    flag = false; /*اینجا باید اصلاح شود!*/
}
خوب! به نظر شما ایرادی دارد که این flag همیشه true باشد؟! برای همین منظور، فایل MSKLC.exe را پچ کرده‌ام که از آدرس زیر قابل دریافت است:

  دریافت پچ شده نگارش 1.4.6000.2 : MSKLC.Patched.7z  

با استفاده از این نسخه (ابتدا برنامه اصلی را نصب کرده و سپس فایل exe را جایگزین نمائید)، به راحتی می‌توان نسخه‌ی استاندارد و اصلی 2091 را بارگذاری و مجددا کامپایل کرد (بدون توقف کامپایل به خاطر فقط یک نیم فاصله‌ی غیرمعتبر از دیدگاه نویسندگان اصلی برنامه). به این صورت فایل‌های 64 بیتی لازم هم تولید می‌شوند ( ممکن است در حین کار با برنامه‌ی patch شده، نمایش خطای کار با نیم فاصله را مجددا دریافت کنید؛ اما مهم نیست . نمونه‌ی وصله شده، بدون مشکل حاصل را کامپایل می‌کند که در نمونه‌ی اصلی اینطور نیست. یعنی پس از overwrite کردن فایل exe موجود، با نمونه patch شده، برنامه کار کامپایل را کامل می‌کند) که حاصل نهایی را از آدرس زیر می‌توانید دریافت نمائید:


این فایل‌ها دقیقا بر مبنای همان فایل‌های پروژه وب فارسی استاندارد 2091 هستند؛ با این تفاوت که نسخه‌‌های غیر 32 بیتی هم در آن لحاظ شده‌اند.

نصب این dll‌ها هم از ویندوز ویستا به بعد داستان خودش را پیدا کرده؛ ابتدا باید take ownership شود، سپس می‌توان فایل اصلی را به سادگی جایگزین کرد و سپس reboot .
برای این منظور ابتدا به پوشه‌ی system32 ویندوز مراجعه کرده و فایل KBDFA.DLL را پیدا کنید.
در ادامه به پنجره خواص آن (کلیک راست و انتخاب properties) مراجعه و برگه‌ی Security آن‌را انتخاب کنید.
در این قسمت بر روی دکمه‌ی Advanced کلیک نمائید.
در صفحه‌ی باز شده به برگه‌ی Owner مراجعه کنید.
در این قسمت بر روی دکمه‌ی Edit کلیک نموده و کاربر خودتان را اضافه نمائید.
پس از طی این مرحله (یا همان take ownership) به برگه security مراجعه کرده و به کاربر خودتان دسترسی full control بدهید.
اکنون مجوز تغییر این فایل را بدون هیچ مشکلی خواهید یافت.
در پایان reboot را فراموش نکنید.

راه دوم:
یا برنامه نصاب حاصل از برنامه‌ی Microsoft Keyboard Layout Creator، مدخل جدیدی را به صفحه کلیدهای قابل انتخاب ویندوز در کنترل پنل اضافه می‌کند که نیازی به reboot ندارد.