مطالب
مبانی TypeScript؛ متغیرها و نوع‌ها
روش‌های مختلف تعریف متغیرها در TypeScript

تمام توسعه دهنده‌های JavaScript با واژه‌ی کلیدی var آشنایی دارند؛ اما TypeScript واژه‌های کلیدی let و const را نیز اضافه کرده‌است (که جزئی از ES 6 نیز می‌باشند). تفاوت مهم بین var و let، در میدان دید متغیرهای تعریف شده‌ی توسط آن‌ها خلاصه می‌شود. پیشتر در سری مباحث بررسی ES 6، مطلب «متغیرها در ES 6» را نیز بررسی کردیم که در TypeScript نیز صادق می‌باشند؛ با این تفاوت که TypeScript را می‌توان به ES 5 نیز کامپایل کرد و بدون مشکل با تمام مرورگرهای موجود، اجرا نمود.
- متغیرهایی که با var تعریف می‌شوند، به صورت سراسری در متدی که تعریف شده‌اند، قابل دسترسی هستند؛ حتی اگر 5 سطح داخل ifهای تو در تو تعریف شده باشند. اما let و const تنها در block و قطعه‌ای که معرفی شده‌اند، معتبر بوده و خارج از آن تعریف نشده‌اند. در اینجا یک block توسط {} معرفی می‌شود.
- متغیرهای از نوع var به دلیل مفهومی به نام hoisting توسط runtime جاوا اسکریپت، به بالاترین سطح متد منتقل می‌شوند. به همین دلیل عمق تعریف آن‌ها، اثری در دسترسی به این متغیرها ندارد. اما hoisting در مورد let و const اعمال نمی‌شود.
- متغیرهای var را می‌توان چندبار مجددا تعریف کرد (هرچند این روش توصیه نمی‌شود؛ اما مجاز است). یک چنین تعریف مجددی با متغیرهای از نوع let و const مجاز نیست.
برای توضیحات بیشتر به مثال ذیل دقت کنید:
function ScopeTest() {
    if (true) {
        var foo = 'use anywhere';
        let bar = 'use in this block';
    }
    console.log(foo); // works!
    console.log(bar); // error!
}
در اینجا داخل قطعه‌ی if تعریف شده، یک متغیر، از نوع var و متغیر دیگری از نوع let تعریف شده‌است. خارج از بدنه‌ی این متد، متغیر foo هنوز قابل دسترسی است، اما متغیر bar خیر.


نوع‌های پایه‌ی TypeScript

نوع‌های پایه‌ی TypeScript شامل موارد ذیل هستند:
Boolean: برای ذخیره سازی true یا false.
let isDone: boolean = false;
Number: معرف مقادیر عددی اعشاری هستند.
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
String: مقادیر رشته‌ای را ذخیره می‌کند.
let name: string = "bob";
name = 'smith';
Array: روش‌های متفاوتی برای تعریف آرایه‌ها در TypeScript وجود دارند که در ادامه آن‌ها را بیشتر بررسی خواهیم کرد.
let list: number[] = [1, 2, 3];
Enum: نوع‌های شمارشی؛ جهت دادن نام‌هایی بهتر به مجموعه‌ی مشخصی از مقادیر.
enum Color {Red, Green, Blue};
let c: Color = Color.Green;
Any: به این معنا که یک متغیر می‌تواند به هر نوع دلخواهی اشاره کند. هدف از وجود این نوع، امکان استفاده‌ی از کتابخانه‌های فعلی جاوا اسکریپتی است که نوعی برای متغیرهای آن‌ها تعریف نشده‌اند و در اساس هر نوعی می‌توانند باشند. برای مثال در جاوا اسکریپت مجاز است در سطر اول متغیری را تعریف کرد و در سطر دوم به آن یک رشته و در سطر سوم به آن یک عدد را انتساب داد.
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
Void: به معنای فقدان یک نوع است. برای مثال مشخص کردن اینکه متدی، خروجی ندارد.
 function warnUser(): void {
        alert("This is my warning message");
}

یک نکته: قابلیت Template string در ES 6 نیز در TypeScript پشتیبانی می‌شود.



مفهوم Type Inference در TypeScript

در TypeScript الزاما نیازی نیست تا نوع متغیری را صریحا مشخص کرد. در اینجا اگر نوع متغیری را در ابتدای کار تعریف نکنید، نوع آن در اولین باری که مقدار دهی می‌شود، مشخص خواهد شد که به آن Type Inference نیز می‌گویند.
let myString= 'this is a string';
myString= 42; // error!
در مثال فوق، نوع متغیر myString در زمان تعریف آن مشخص نشده‌است؛ اما با یک رشته، مقدار دهی و آغاز شده‌است. بر این اساس، TypeScript نوع این متغیر را رشته‌ای در نظر می‌گیرد و در سطر بعدی، از انتساب یک مقدار عددی به آن جلوگیری خواهد کرد.
و یا در مثال ذیل، نوع خروجی متد ReturnNumber به صورت صریح مشخص نشده‌است:
function ReturnNumber() {
   return 42;
}
let anotherString = 'this is also a string';
anotherString = ReturnNumber(); // error!
اما با توجه به اینکه خروجی آن عددی است، نوع آن نیز عددی درنظر گرفته شده و از انتساب آن به یک متغیر رشته‌ای جلوگیری می‌شود.


تعریف صریح نوع‌ها در TypeScript با استفاده از Type Annotations

برای لغو Type Inference و تعیین صریح نوع‌ها در TypeScript می‌توان به صورت زیر عمل کرد:
let myString : string = 'this is a string';
myString = 42; // error!

function ReturnNumber() : number {
   return 42;
}
let anotherString : string = 'this is also a string';
anotherString = ReturnNumber(); // error!
با قراردادن یک کولن پس از نام متغیر و سپس تعریف نوع داده‌ی مدنظر، می‌توان نوع‌ها را در TypeScript به صورت صریحی تعریف کرد. در مورد متدها نیز به همین صورت است. کولن پس از پایان بسته شدن پرانترها قرار می‌گیرد و سپس نوع بازگشتی متد مشخص می‌گردد.


نوع‌های شمارشی در TypeScript

Enums در بسیاری از زبان‌های برنامه نویسی متداول وجود دارند و هدف از آن‌ها، دادن نام‌هایی بهتر و مشخص، به مجموعه‌ای از مقادیر است:
 enum Category { Biography, Poetry, Fiction }; // 0, 1, 2
در مثال فوق یک enum جهت تعریف گروه‌های کتاب‌ها تعریف شده‌است. در اینجا بجای استفاده از مقادیر نامفهوم 0 تا 2، نام‌هایی مشخص و بهتر، جهت معرفی آن‌ها ارائه شده‌اند. به این ترتیب می‌توان در نهایت به کدهایی خواناتر رسید.
اگر می‌خواهید این مقادیر با اعداد دیگری شروع شوند (بجای صفر پیش فرض)، می‌توان مقدار اولین نام را به صورت صریحی مشخص کرد:
 enum Category { Biography = 1, Poetry, Fiction }; // 1, 2, 3
و یا الزامی به استفاده از مقادیر افزایش یابنده‌ای در اینجا نیست. در صورت نیاز می‌توان مقدار هر المان را جداگانه تعریف کرد:
 enum Category{ Biography = 5, Poetry = 8, Fiction = 9 }; // 5, 8, 9
پس از اینکه نوع enum تعریف شده، استفاده از آن همانند سایر نوع‌های پایه‌ی TypeScript است:
 let favoriteCategory: Category = Category.Biography;
در اینجا متغیر favoriteCategory از نوع enum گروه کتاب‌ها تعیین شده‌است؛ با مقدار اولیه‌ی Category.Biography.
در این حالت اگر مقدار favoriteCategory را چاپ کنیم، خروجی عددی 5 نمایش داده می‌شود:
 console.log(favoriteCategory); // 5
اگر نیاز به بازگشت مقدار رشته‌ای این آیتم است، می‌توان از ایندکس‌های یک enum استفاده کرد:
let categoryString= Category[favoriteCategory]; // Biography


آرایه‌ها در TypeScript

در حالت عمومی، آرایه‌ها در TypeScript همانند جاوا اسکریپت تعریف می‌شوند؛ البته به همراه تعدادی استثناء. در TypeScript سه روش برای تعریف آرایه‌ها وجود دارند:
الف) در مثال زیر آرایه‌ای از رشته‌ها تعریف شده‌است. در اینجا نوع آرایه به همراه [] مشخص می‌شود:
let strArray1: string[] = ['here', 'are', 'strings'];
ب) روش دوم تعریف آرایه‌ها در TypeScript با استفاده از مفهوم Generics است که در بحثی جداگانه به آن خواهیم پرداخت. در اینجا از واژه‌ی کلیدی Array به همراه مشخص سازی نوع آن در داخل <> استفاده شده‌است:
let strArray2: Array<string> = ['more', 'strings', 'here'];
ج) اگر نیاز به آرایه‌هایی شبیه به جاوا اسکریپت دارید که می‌توانند حاوی انواع و اقسام المان‌هایی با نوع‌های مختلف باشند، نوع آرایه را []any تعریف کنید:
let anyArray: any[] = [42, true, 'banana'];


نوع Tuples در TypeScript

Tuples در TypeScript نوع خاصی از آرایه‌ها هستند که نوع مقادیر اعضای آن‌ها به صورت صریح مشخص می‌شوند:
 let myTuple: [number, string] = [25, 'truck'];
برای مثال در اینجا نوع متغیر myTuple به صورت آرایه‌ای از دو عنصر عددی و رشته‌ای تعریف شده‌است.
اکنون برای دسترسی به مقادیر این المان‌ها، همانند کار با آرایه‌های معمولی، از ایندکس‌های آرایه‌ی تعریف شده استفاده می‌شود:
 let firstElement= myTuple[0]; // 25
let secondElement= myTuple[1]; // truck

یک نکته: می‌توان به آرایه‌ی تعریف شده، عناصر جدیدی را نیز افزود؛ با این شرط که نوع آن‌ها، یکی از نوع‌های مشخص شده‌ی در تعریف Tuple باشند:
 // other elements can have numbers or strings
myTuple[2] = 100;
myTuple[2] = 'this works!';


مفهوم Type assertions در TypeScript

حتما با مفهوم cast و تبدیل نوع‌های مختلف به یکدیگر، در زبان‌های دیگر برنامه نویسی آشنا هستید. در TypeScript نیز این مفهوم تحت عنوان Type assertions پشتیبانی می‌شود و دو روش برای تعریف آن وجود دارد:
الف) تعریف cast توسط angle-bracket syntax که در آن نوع مدنظر داخل یک <> قرار می‌گیرد:
 let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
در اینجا نوع نامشخص any به string تبدیل شده و سپس امکان دسترسی به خاصیت طول آن که تحت کنترل کامپایلر است و قابل انتساب به یک مقدار عددی، میسر شده‌است.
ب) تعریف cast توسط as syntax به نحو ذیل:
 let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
هر دو حالت تعریف شده معادل هستند. فقط باید دقت داشت در حین کار با ReactJS توسط TypeScript، فقط حالت as syntax پشتیبانی می‌شود.
مطالب دوره‌ها
بوت استرپ (نگارش 3) چیست؟
بوت استرپ یک فریم ورک CSS واکنشگرا (responsive) است، که جهت ساخت سریع برنامه‌های استاتیک و همچنین پویای وب کاربرد دارد. در حال حاضر این پروژه جزو محبوب‌ترین و فعال‌ترین پروژه‌های سایت Github است. اگر علاقمند هستید که لیستی از سایت‌های استفاده کننده از بوت استرپ را مشاهده کنید، به آدرس‌های ذیل مراجعه نمائید:


تازه‌های بوت استرپ 3 کدامند؟

- بوت استرپ 3 جهت کار با صفحه‌های نمایش کوچک دستگاه‌های موبایل به شدت بهینه سازی شده است و به همین جهت به آن mobile-first CSS framework نیز می‌گویند.
- در نگارش 2 بوت استرپ، حداقل دو نوع گرید واکنشگرا و غیر واکنشگرا قابل تعریف بودند. در نگارش سوم آن، تنها یک نوع گرید جدید واکنشگرا در این فریم ورک وجود دارد که می‌تواند چهار نوع سایز از بزرگ تا کوچک را شامل شود.
- بوت استرپ 3 با IE7 به قبل و همچنین فایرفاکس 3.6 و پایین‌تر دیگر سازگار نیست. البته برای پشتیبانی از IE8، نیاز به اندکی تغییرات نیز وجود خواهد داشت که در قسمت‌های بعد این جزئیات را بیشتر بررسی خواهیم کرد. به عبارت دیگر بدون این تغییرات، بوت استرپ 3 در حالت پیش فرض با IE9 به بعد سازگار است.
- در بوت استرپ 3 برخلاف نگارش قبلی آن که لیستی از آیکن‌های خود را در قالب چند فایل PNG image sprite که آیکن‌ها را به صورت فشرده در کنار هم قرار داده بود، اینبار تنها از Font icons استفاده می‌کند. به این ترتیب تغییر اندازه این آیکن‌ها با توجه به برداری بودن نمایش قلم‌ها و همچنین قابلیت اعمال رنگ به آن‌ها نیز بسیار ساده‌تر می‌گردد.


سؤال: آیا نیاز است از یک فریم ورک CSS واکنشگرا استفاده شود؟

در سال‌های قبل، عموما طراحی وب بر اساس تهیه یا خرید یک سری قالب‌های از پیش آماده شده، شکیل صورت می‌گرفته‌است. این قالب‌ها به سرعت با برنامه، یکپارچه شده و حداکثر قلم یا رنگ‌های آن‌ها‌را اندکی تغییر می‌دادیم و یا اینکه خودمان کل این مسیر را از صفر طی می‌کردیم. این پروسه سفارشی، بسیار سنگین بوده و مشکل مهم آن، عدم امکان استفاده مجدد از طراحی‌های انجام شده می‌باشد که نهایتا در دراز مدت هزینه‌ی بالایی را برای ما به همراه خواهند داشت. اما با استفاده از فریم ورک‌های CSS واکنشگرا به این مزایا خواهیم رسید:
- قسمت عمده‌ای از کار پیشتر برای شما انجام شده است.
برای مثال نیازی نیست تا حتما برای طرحبندی صفحه، سیستم گرید خاص خودتان را طراحی کنید و یا اینکه مانند سال‌های دور، به استفاده از HTML tables پناه ببرید.
- قابلیت سفارشی سازی بسیار بالایی دارند.
برای مثال با استفاده از فناوری‌هایی مانند less می‌توان بوت استرپ را تا حد بسیار زیادی سفارشی سازی کرد. به این ترتیب دیگر یک سایت بوت استرپ، شبیه به بوت استرپ به نظر نخواهد رسید! شاید عده‌ای عنوان کنند که تمام سایت‌های بوت استرپ یک شکل هستند، اما واقعیت این است که این سایت‌ها تنها از قابلیت‌های سفارشی سازی بوت استرپ و less استفاده نکرده‌اند.
 

دریافت بوت استرپ 3

سایت رسمی دریافت بوت استرپ، آدرس ذیل می‌باشد:

البته ما از این نگارش خام استفاده نخواهیم کرد و نیاز است برای کارهای سایت‌های فارسی، از نگارش راست به چپ آن استفاده کنیم. بنابراین اگر از ویژوال استودیو استفاده می‌کنید، می‌توانید به یکی از دو بسته نیوگت ذیل مراجعه نمائید:
و اگر می‌خواهید صرفا به فایل‌های درون این بسته‌ها دسترسی پیدا کنید، از دو آدرس ذیل استفاده کنید:
فایل‌های دریافت شده با پسوند nupkg، در حقیقت یک فایل zip استاندارد هستند.

اگر بوت استرپ اصل را از سایت اصلی آن دریافت کنید، شامل تعداد فایل‌ها و پوشه‌های بسیار بیشتری است نسبت به نمونه RTL فوق. اما فایل‌های نهایی آن که مورد استفاده قرار خواهند گرفت، درون پوشه dist یا توزیع آن قرار گرفته‌اند و آنچنان تفاوتی با نگارش RTL ندارند. فقط در نگارش اصل، فایل‌های min و فشرده شده نیز همراه این بسته هستند که در نگارش RTL لحاظ نشده‌اند. این موضوع در آینده به نفع ما خواهد بود. از این لحاظ که اگر از سیستم bundling & minification مربوط بهASP.NET  استفاده کنید (جهت تولید خودکار فایل‌های min در زمان اجرا)، این سیستم به صورت پیش فرض از فایل‌های min موجود استفاده می‌کند و ممکن است مدتی سردرگم باشید که چرا تغییراتی را که به فایل CSS بوت استرپ اعمال کرده‌ام، در سایت اعمال نمی‌شوند. به علاوه امکان اعمال تغییرات و حتی دیباگ فایل‌های غیرفشرده خصوصا جاوا اسکریپتی آن نیز بسیار ساده‌تر و مفهوم‌تر است.

جهت مطالعه مباحث تکمیلی در مورد نحوه فشرده سازی فایل‌های CSS یا JS می‌توانید به مقالات ذیل، در سایت جاری مراجعه نمائید:

علاوه بر این‌ها در نگارش سوم بوت استرپ، تعدادی فایل CSS جدید به نام قالب یا theme نیز اضافه شده‌اند که همراه نسخه RTL نیست. برای مثال اگر به پوشه bootstrap-3.0.0.zip\bootstrap-3.0.0\dist\css مراجعه کنید، فایل bootstrap-theme.css نیز قابل مشاهده است. به این ترتیب قالبی و لایه‌ای بر روی مقادیر پیش فرض موجود در فایل bootstrap.css اعمال خواهند شد؛ برای مثال اعمال طراحی تخت یا flat مدرن آن به دکمه‌ها و عناصر دیگر این مجموعه.


شروع یک فایل HTML با بوت استرپ

تا اینجا فرض بر این است که فایل‌های بوت استرپ را دریافت کرده‌اید. در ادامه قصد داریم، نحوه معرفی این فایل‌ها را در یک فایل ساده HTML بررسی کنیم.
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Website</title>
    <link href="Content/css/bootstrap-rtl.css" rel="stylesheet">    
<link href="Content/css/custom.css" rel="stylesheet">    
</head>
<body>


</body>
</html>
صفحه آغازین کار با بوت استرپ 3 یک چنین شکلی را خواهد داشت و می‌تواند پایه تشکیل فایل masterpage یا layout برنامه‌های ASP.NET قرار گیرد. متا تگ viewport اضافه شده، جهت طراحی‌های واکنشگرا اضافه شده است و در ادامه لینک شدن فایل CSS بوت استرپ 3 را ملاحظه می‌کنید.
اگر سایت شما از تعاریف CSS سفارشی دیگری نیز استفاده می‌کند، تعاریف آن‌ها باید پس از بوت استرپ، ذکر گردند.


افزودن اسکریپت‌های بوت استرپ 3

برای کار با اسکریپت‌های بوت استرپ 3 نیاز است ابتدا jQuery را به صورت جداگانه دریافت کنیم. در حال حاضر اگر به سایت جی‌کوئری مراجعه کنید با دو نگارش 1.x و 2.x این کتابخانه مواجه خواهید شد. اگر نیاز به پشتیبانی از IE 8 را در محل کار خود دارید، باید از نگارش 1.x استفاده کنید. نگارش آخر 1.x کتابخانه جی‌کوئری را از طریق CDN آن همواره می‌توان مورد استفاده قرار داد:
 <script src="http://code.jquery.com/jquery-latest.min.js"></script>
بهتر است تعاریف فایل‌های جاوا اسکریپت را پیش از بسته شدن تگ body قرار دهید. یکی از مزایای مهم آن مشاهده نشدن یک فلش کوتاه مدت سفید رنگ در ابتدای بارگذاری صفحاتی با پس زمینه غیر روشن است. از این جهت که هر المانی که در head صفحه تعریف شود، حتما باید پیش از بارگذاری کل صفحه دریافت گردد. به این ترتیب با سرعت‌های دریافت کمتر، این مساله سبب خالی ماندن صفحه برای مدتی کوتاه خواهد شد و همان فلش سفید رنگ عنوان شده را پدید می‌آورد؛ چون هنوز مابقی صفحه بارگذاری نشده و خالی است.
پس از تعریف جی‌کوئری، تعریف اسکریپت‌های بوت استرپ قرار می‌گیرد (چون وابسته است به جی‌کوئری). فایل bootstrap-rtl.js شامل تمام زیر فایل‌های مورد نیاز نیز می‌باشد:
 <script src="Scripts/bootstrap-rtl.js"></script>
برای سازگار سازی بوت استرپ 3 با IE8 نیاز به یک فایل اسکریپت دیگر نیز داریم. این فایل را از آدرس ذیل دریافت نمائید:
این فایل 4 کیلوبایتی را نیز باید به تعاریف اسکریپت‌های مورد نیاز، اضافه کرد:
 <script src="Scripts/respond.min.js"></script>
البته این اسکریپت خاص، مطابق توضیحات آن باید به head صفحه اضافه شود تا با IE8 بهتر کار کند.
تا اینجا ساختار صفحه HTML تهیه شده جهت استفاده از امکانات بوت استرپ 3، شکل زیر را خواهد داشت:
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Website</title>

    <link href="Content/css/bootstrap-rtl.css" rel="stylesheet">    
<link href="Content/css/custom.css" rel="stylesheet">       
<script src="Scripts/respond.min.js"></script>
</head>
<body>


<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script src="Scripts/bootstrap-rtl.js"></script>
</body>
</html>

فایل‌های نهایی این قسمت را از اینجا نیز می‌توانید دریافت کنید:
bs3-sample01.zip
 
بازخوردهای پروژه‌ها
مشکل در جمع کل
سلام،تشکر از راهنمایی‌های قبلی
گزارشی دارم، که در آن از تابع جمعی Sum استفاده کرده ام در 3 ستون.
حال متوجه نمیشم چرا نتیجه تابع تجمعی صفر می‌شوند، در گزارشات دیگر نیز از Sum استفاده کردم ولی مشکلی نداشتم، مشکل کارم را متوجه نمیشوم.
خروجی گزارش :

کد گزارش : 
 new PdfReport().DocumentPreferences(doc =>
            {
                doc.RunDirection(PdfRunDirection.RightToLeft);
                doc.Orientation(PageOrientation.Portrait);
                doc.PageSize(PdfPageSize.A4);
                doc.DocumentMetadata(new DocumentMetadata { Author = _company, Application = "نرم افزار ", Keywords = "سود فاکتورها", Subject = "سود فاکتورها", Title = "سود فاکتورها" });
            })
           .DefaultFonts(fonts =>
           {
               fonts.Path(Path.Combine(Environment.CurrentDirectory, @"fonts\irsans.ttf"),
                           Path.Combine(Environment.CurrentDirectory, @"fonts\verdana.ttf"));
               fonts.Size(8);
           })
           .PagesFooter(footer =>
           {
            footer.DefaultFooter(DateTimeHelper.ToPersianShortDateString(DateTime.Now,true,true));
           })
           .PagesHeader(header =>
           {
               header.HtmlHeader(rptHeader =>
               {
                   // Register fonts and styles
                   var styleSheet = new iTextSharp.text.html.simpleparser.StyleSheet();

                   iTextSharp.text.FontFactory.Register(Path.Combine(Environment.CurrentDirectory, @"fonts\BFARNAZ.TTF"), "Farnaz");
                   styleSheet.LoadStyle("report-header", "size", "12pt");
                   styleSheet.LoadStyle("report-header", "font-family", "Farnaz");

                   iTextSharp.text.FontFactory.Register(Path.Combine(Environment.CurrentDirectory, @"fonts\BNAZANIN.TTF"), "Bnazanin");
                   styleSheet.LoadStyle("report-desc", "size", "12pt");
                   styleSheet.LoadStyle("report-desc", "font-family", "Bnazanin");

                   rptHeader.PageHeaderProperties(new HeaderBasicProperties
                   {
                       RunDirection = PdfRunDirection.RightToLeft,
                       HorizontalAlignment = PdfRpt.Core.Contracts.HorizontalAlignment.Center,
                       ShowBorder = false,
                       PdfFont = header.PdfFont,
                       StyleSheet = styleSheet
                   });

                   rptHeader.AddPageHeader(pageHeader =>
                   {
                       var title = "سود فاکتورها";
                       var companyName = string.Concat("شرکت / فروشگاه ", _company);
                       var financialYear = string.Concat("سال مالی ", _financialPeriod.GetCurrentFinancialPeriodTitle());
                       return string.Format(@"    
                                                    <table cellpadding='0' cellspacing='0' class='report-header'>
                                                        <tr>
                                                            <td>{0}</td>
                                                        </tr>
                                                        <tr>
                                                            <td>{1}</td>
                                                        </tr> 
                                                        <tr>
                                                            <td>{2}</td>
                                                        </tr>
                                                   </table>
                                                    <table cellpadding='0' cellspacing='0' class='report-desc'> 
                                                        <tr>
                                                            <td align='left' width='10%'>{3}</td><td align='left' width='10%'>از تاریخ:</td>
                                                            <td align='left' width='65%'>{4}</td><td align='left' width='15%'>از شماره:</td> 
                                                        </tr>
                                                        <tr>
                                                           <td align='left' width='10%'>{5}</td> <td align='left' width='10%'>تا تاریخ:</td> 
                                                            <td align='left' width='65%'>{6}</td> <td align='left' width='15%'>تا شماره:</td> 
                                                        </tr>
                                                    </table>
                                             "
                                                          , title, companyName,
                                                         financialYear,
                                                         DateTimeHelper.ToPersianShortDateString(_fromDate),
                                                         _fromNumber,
                                                         DateTimeHelper.ToPersianShortDateString(_toDate),
                                                         _toNumber
                                                         );
                   });
               });
           })
           .MainTableTemplate(template =>
           {
               template.CustomTemplate(new GrayTemplate());
           })
           .MainTablePreferences(table =>
           {
               table.ColumnsWidthsType(TableColumnWidthType.Relative);
               table.NumberOfDataRowsPerPage(0);
           })
           .MainTableDataSource(dataSource =>
           {
               var factorsProfitItems = FactorsProfitItems.Select(g => new
               {
                   Number = g.Number,
                   SaleDate = g.SaleDate,
                   Customer = g.Customer,
                   Description = g.Description,
                   FactorProfit = g.FactorProfit,
                   Discount = g.Discount,
                   RealProfit = g.RealProfit
               });
               dataSource.StronglyTypedList(factorsProfitItems);
           })
           .MainTableColumns(columns =>
           {
               columns.AddColumn(column =>
               {
                   column.PropertyName<FactorsProfitItemPrintViewModel>(x => x.Number);
                   column.CellsHorizontalAlignment(PdfRpt.Core.Contracts.HorizontalAlignment.Center);
                   column.IsVisible(true);
                   column.Order(0);
                   column.Width(1);
                   column.HeaderCell("ش فاکتور");
               });
               columns.AddColumn(column =>
               {
                   column.PropertyName<FactorsProfitItemPrintViewModel>(x => x.SaleDate);
                   column.CellsHorizontalAlignment(PdfRpt.Core.Contracts.HorizontalAlignment.Left);
                   column.IsVisible(true);
                   column.Order(1);
                   column.Width(1);
                   column.ColumnItemsTemplate(template =>
                   {
                       template.TextBlock();
                       template.DisplayFormatFormula(obj => DateTimeHelper.ToPersianShortDateString((DateTime)obj));
                   });
                   column.HeaderCell("تاریخ");
               });
               columns.AddColumn(column =>
               {
                   column.PropertyName<FactorsProfitItemPrintViewModel>(x => x.Customer);
                   column.CellsHorizontalAlignment(PdfRpt.Core.Contracts.HorizontalAlignment.Left);
                   column.IsVisible(true);
                   column.Order(2);
                   column.Width(1.5f);
                   column.HeaderCell("مشتری");
               });
               columns.AddColumn(column =>
               {
                   column.PropertyName<FactorsProfitItemPrintViewModel>(x => x.Description);
                   column.CellsHorizontalAlignment(PdfRpt.Core.Contracts.HorizontalAlignment.Center);
                   column.IsVisible(true);
                   column.Order(3);
                   column.Width(2);
                   column.HeaderCell("شرح");
               });
               columns.AddColumn(column =>
               {
                   column.PropertyName<FactorsProfitItemPrintViewModel>(x => x.FactorProfit);
                   column.CellsHorizontalAlignment(PdfRpt.Core.Contracts.HorizontalAlignment.Right);
                   column.IsVisible(true);
                   column.Order(4);
                   column.Width(1);
                   column.ColumnItemsTemplate(template =>
                   {
                       template.TextBlock();
                       template.DisplayFormatFormula(obj => string.Format("{0:n0}", obj));
                   });
                   column.AggregateFunction(aggregateFunction =>
                   {
                       aggregateFunction.NumericAggregateFunction(AggregateFunction.Sum);
                       aggregateFunction.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj));
                   });
                   column.HeaderCell("سود فاکتور");
               });
               columns.AddColumn(column =>
               {
                   column.PropertyName<FactorsProfitItemPrintViewModel>(x => x.Discount);
                   column.CellsHorizontalAlignment(PdfRpt.Core.Contracts.HorizontalAlignment.Right);
                   column.IsVisible(true);
                   column.Order(5);
                   column.Width(1);
                   column.ColumnItemsTemplate(template =>
                   {
                       template.TextBlock();
                       template.DisplayFormatFormula(obj => string.Format("{0:n0}", obj));
                   });
                   column.AggregateFunction(aggregateFunction =>
                   {
                       aggregateFunction.NumericAggregateFunction(AggregateFunction.Sum);
                       aggregateFunction.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj));
                   });
                   column.HeaderCell("تخفیف");
               });
               columns.AddColumn(column =>
               {
                   column.PropertyName<FactorsProfitItemPrintViewModel>(x => x.RealProfit);
                   column.CellsHorizontalAlignment(PdfRpt.Core.Contracts.HorizontalAlignment.Right);
                   column.IsVisible(true);
                   column.Order(6);
                   column.Width(1);
                   column.ColumnItemsTemplate(template =>
                   {
                       template.TextBlock();
                       template.DisplayFormatFormula(obj => string.Format("{0:n0}", obj));
                   });
                   column.AggregateFunction(aggregateFunction =>
                   {
                       aggregateFunction.NumericAggregateFunction(AggregateFunction.Sum);
                       aggregateFunction.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj));
                   });
                   column.HeaderCell("سود خالص");
               });
           })
            .MainTableSummarySettings(summarySettings =>
            {
                summarySettings.OverallSummarySettings("جمع کل");
                summarySettings.PreviousPageSummarySettings("نقل از صفحه قبل");
                summarySettings.PageSummarySettings("جمع کل صفحه");
            })
           .MainTableEvents(events =>
           {
               events.DataSourceIsEmpty(message: "داده ای جهت نمایش وجود ندارد.");
               events.CellCreated(args =>
               {
                   args.Cell.BasicProperties.CellPadding = 4f;
               });
               events.MainTableAdded(args =>
               {
                   var taxTable = new PdfGrid(3);  // Create a clone of the MainTable's structure  
                   taxTable.RunDirection = 3;
                   taxTable.SetWidths(new float[] { 3, 3, 3 });
                   taxTable.WidthPercentage = 100f;
                   taxTable.SpacingBefore = 60f;

                   taxTable.AddSimpleRow(
                       (data, cellProperties) =>
                       {
                           data.Value = "امضاء تنظیم کننده";
                           cellProperties.ShowBorder = false;
                           cellProperties.PdfFont = args.PdfFont;
                       },
                       (data, cellProperties) =>
                       {
                           data.Value = "امضاء حسابدار";
                           cellProperties.ShowBorder = false;
                           cellProperties.PdfFont = args.PdfFont;
                       },
                       (data, cellProperties) =>
                       {
                           data.Value = "امضاء مدیرعامل";
                           cellProperties.ShowBorder = false;
                           cellProperties.PdfFont = args.PdfFont;
                       });
                   args.PdfDoc.Add(taxTable);
               });
           })
           .Export(export =>
           {
               export.ToExcel("خروجی اکسل");
               export.ToCsv("خروجی CSV");
               export.ToXml("خروجی XML");
           })
           .Generate(data => data.AsPdfFile(_documentSource));

نظرات مطالب
بارگزاری PartialView با استفاده از jQuery در زمان اجرا

سلام

مشکلی که من دارم این است که در صفحه دوتا PartialView دارم که هر کدام با استفاده jquery همان طور که شما توضیح داده اید لود می‌شوند ، اما برای رفرش کردن اونها مشکل دارم و نمی‌تونم به هر کدام شماره Page و سایر اطلاعات WebGrid چطوری ارسال کنم؟

ممنون

نظرات مطالب
نحوه‌ی محاسبه‌ی هش کلمات عبور کاربران در ASP.NET Identity
روش تغییر «تعداد بار تکرار» الگوریتم هش کردن اطلاعات در ASP.NET Core Identity

کلیات مطلب عنوان شده‌ی در اینجا در ASP.NET Core Identity هم صادق است؛ اما به همراه امکانات تنظیمی بیشتر، مانند امکان تنظیم تعداد بار تکرار الگوریتم هش کردن کلمات عبور:
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<PasswordHasherOptions>(options => options.IterationCount = 100_000);
که البته مقدار پیش‌فرض آن همان 100 هزار بار است که هرچقدر مقدار آن بیشتر باشد، کار brute force آن مشکل‌تر می‌شود.

نکته 1: تغییر این مقدار، مشکلی را برای کاربران فعلی ایجاد نمی‌کند؛ از این جهت که این تعداد بار نیز جزو اطلاعاتی است که به همراه هش نهایی در بانک اطلاعاتی ذخیره می‌شود و اگر مقدار آن‌را تغییر دادید، صرفا به کاربران جدید و یا کاربرانی که کلمه‌ی عبور خود را تغییر می‌دهند، اعمال خواهد شد.
نکته 2: این تغییر، زمانی مؤثر واقع خواهد شد که مقدار تعداد تکرار جدید، بیشتر از مقدار قبلی باشد. یعنی اگر مقدار جدیدی را مساوی 200 هزار اعمال کردید و بر اساس آن هش کلمات عبور تغییر یافت و سپس این مقدار را به 100 هزار تغییر دادید، چون عدد جدید کمتر است از عدد قبلی، ندید گرفته می‌شود.
نکته 3: بهتر است این عدد را بیش از اندازه بزرگ انتخاب نکنید؛ چون کار سرور را بیشتر کرده و همچنین پروسه‌ی لاگین را کند می‌کنید. زمان پیشنهادی برای اینکار، 1 ثانیه به ازای هر کلمه‌ی عبور است. یعنی عددی را انتخاب کنید که پس از انجام تمام تکرارها برای محاسبه‌ی هش، بیش از 1 ثانیه طول نکشد و بر این اساس، عدد 500 هزار تکرار، شاید انتخاب بهتری باشد.
اشتراک‌ها
گزارش سراسری میزان افزایش حقوق، سال 1402

انتهای سال 1401 با نظرسنجی از 74000 شاغل در سراسر کشور گزارش جامعی از میزان حقوق و مقدار افزایش آن در سال جدید ارائه دادیم؛ گزارشی که در آن حقوق کارکنان گروه‌های شغلی مختلف با سابقه کاری مختلف و در شهرهای مختلف بررسی شده است. این گزارش در فروردین 1402 منتشر شده است.

 
گزارش سراسری میزان افزایش حقوق، سال 1402
اشتراک‌ها
گزارش سراسری میزان افزایش حقوق، سال 1401

انتهای سال 1400 با نظرسنجی از 50000 شاغل در سراسر کشور گزارش جامعی از میزان حقوق و مقدار افزایش آن در سال جدید ارائه دادیم؛ گزارشی که در آن حقوق کارکنان گروه‌های شغلی مختلف با سابقه کاری مختلف و در شهرهای مختلف بررسی شده است. این گزارش در فروردین 1401 منتشر شده است.

گزارش سراسری میزان افزایش حقوق، سال 1401
نظرات مطالب
طراحی گزارش در Stimulsoft Reports.Net – بخش 2
سلام.
اگر امکانش هست فایل طراحی گزارش را جهت بررسی ارسال نمایید.
خطایی که شما فرمودید مربوط به نوع ساختار دیکشنری گزارش می‌باشد.
برای رفع آن باید level ارتباط entity‌ها را مشخص نمایید.
اگر از Business object استفاده کنید ساختار طراحی برای پیاده سازی master-detail مقداری تغییر خواهد کرد.
نظرات مطالب
طراحی گزارش در Stimulsoft Reports.Net – بخش 2
سلام
تفاوتی در طراحی گزارش وجود نداره.
شما باید اطلاعات را توسط report.RegBusinessObject برای استیمول بفرستید.
تنها تفاوت طراحی برای این حالت این است که بعد رجیستر کردن اطلاعات برای اولین بار شما باید از متد design استفاده کنید تا پوکو شما به دیکشنری گزارش ساز اضافه بشه تا بتونی طراحی کنی. بقیه کار رو هم که میدونید.
موفق باشید.