چگونه در یک پروژه سورس باز مشارکت کنیم؟
میتونید مشارکت کنید، مقاله در موردشون بنویسید، مستندات درست کنید و موارد دیگری که در بحث عنوان شده.
اگر دقت کرده باشید در کنار هر لینک خارجی (هر لینک ختم شده به خارج از سایت) در این وبلاگ، آیکون آن سایت هم به صورت خودکار نمایش داده میشود. از نظر من جالب بوده (خصوصا جهت مشخص کردن وجود یک لینک در میان انبوهی متن، یا برای نمایش لیستی از لینکها)، نظر شما رو نمیدونم!
اینکار در ادامهی مطلبی است که در مورد نوشتن اسکریپتهای گریس مانکی چندی قبل منتشر کردم. البته بهبود یافتهی آن است. برای ایجاد یک چنین قابلیتی در سایت فقط کافی است چند سطر اسکریپت زیر را به هدر سایت خود اضافه کنید.
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js' type='text/javascript' />
<script type="text/javascript">
$(document).ready(function(){
$("a").each(function(){
var $a = $(this);
var href = $a.attr("href");
// see if the link is external
if (href && href.match(/^http/))
if (!href.match(document.domain)) {
var domain = href.replace(/<\S[^><]*>/g, "").split('/')[2];
var image = '<img src="http://' + domain +
'/favicon.ico" width="0" ' +
' onload="this.width=16;this.height=16;this.style.paddingLeft=\'3px\';this.style.paddingRight=\'1px\';" ' +
' style="border:0" ' +
' onerror="this.src=\'http://vahid.nasiri.googlepages.com/weblink.gif\';" />';
$(this).prepend(image);
}
});
});
</script>
با استفاده از jQuery ، زمانیکه document ما ready شد ( document.ready )، تمام لینکهای موجود در صفحه را پیدا میکنیم (یک به یک). سپس مقدار href آنها را میخوانیم (ببینید با jQuery انجام این نوع کارها چقدر ساده شده است). اکنون روی لینک دریافت شده باید پردازش صورت گیرد و نام دومین آن جدا شود (اگر ختم به خارج از سایت بود). سپس بر اساس این دومین ، یک تگ img منتهی به آیکون آن سایت طراحی و نمایش داده خواهد شد (به قبل از لینک اضافه میشود).
عموما هر پروژهای هر چند کوچک و به ظاهر کم اهمیت، نکات خاصی را به همراه دارد.
برای مثال، در ابتدای کار width=0 در نظر گرفته نشد. مشکلی را که ایجاد کرد این بود که یک سایت ممکن است اصلا favicon.ico نداشته باشد. فایرفاکس محترم اصلا به روی مبارک هم نخواهد آورد و شما متوجه نخواهید شد که در صفحه کمبود تصویری وجود دارد. اما در IE حتما جای خالی آیکون و تصویر به نحوه واضحی گوشزد میشود. بنابراین در ابتدای کار قرار نیست چیزی را نمایش دهیم (width=0). سپس در رخداد onload تگ img، اگر تصویر واقعا وجود داشت و بارگذاری شد، طول و عرض آنرا 16 در 16 قرار خواهیم داد (این مورد هم لازم است. چون بعضی از سایتها اندازههای بسیار بزرگی را برای آیکون خود در نظر میگیرند که اصلا مقصود ما را برآورده نخواهند کرد).
این مورد (عدم نمایش تصاویری که وجود ندارند) مشکلی را که در ادامه ایجاد خواهد کرد، عدم یکنواختی در سایت است. یک سری از لینکهای خارجی آیکون دارند و یک سری خیر. نکته جالبی که در مورد تگ img وجود دارد رخداد onerror آن است. اگر مرورگر نتواند تصویر مورد نظر را پیدا یا بارگذاری کند، این روال رخداد گردان فراخوانی میشود. همینجا از موقعیت استفاده شده و src تصویر جاری به یک آیکون مشخص و از قبل تعیین شده تنظیم میشود.
مواردی را که در این ویدیو مشاهده خواهید کرد:
- Introduction to LINQ
- C# 3.0 Language Features
- LINQ to Objects
- Lambda Expressions
- LINQ to DataSets
- Getting Started with LINQ to SQL
- Additional LINQ to SQL Features
- LINQ to XML
- LINQ to Entities and the Entity Framework
دریافت فایل
ماخذ
معرفی سرویسهای ارائه شده توسط شرکتهای گوگل، آمازون و مایکروسافت در قالب رایانش ابری - قسمت اول
رایانش ابری مفهوم نسبتا جدیدی در عرصهی فناوری اطلاعات است و در حال گسترش میباشد. به طور خلاصه رایانش ابری به همه چیز اعم از برنامه کاربردی( Application )، سکو ی ( Platform ) توسعه نرم افزار، سخت افزار و زیرساخت، به عنوان سرویس نگاه میکند. زیرساخت های موجود در مراکز داده( Data Center ) به انضمام نرمافزارهایی که در آن قرار دارند، مجموعههایی را تشکیل میدهند که ابر نامیده میشود. به عبارت سادهتر رایانش ابری یعنی استفاده اشتراکی از برنامهها و منابع یک محیط شبکهای برای انجام یک کار، بدون این که مالکیت، مدیریت منابع شبکه و سخت افزار و برنامهها، برای استفاده کننده مهم باشد. در رایانش ابری منابع کامپیوترها، برای انجام یک کار استفاده میشوند و دادههای مربوط به پردازش، در هیچ کدام از کامپیوترهای شخصی ذخیره نمیشوند، بلکه در جای دیگری در داخل همان منابع شبکه، ذخیره میشوند تا در زمان و مکان دیگری قابل دسترسی باشند.
بر همین اساس شرکت های پیشرو در زمینه فناوری اطلاعات به ارائه سرویس هایی تحت عنوان خدمات رایانش ابری پرداخته اند و هدف از این سری مطالب ارائه شده، شرح مختصری بر سرویسهای ارائه شده می باشد. در قسمت اول به معرفی سرویسهای شرکت گوگل پرداخته می شود و در قسمتهای بعدی، سرویسهای شرکتهای مایکروسافت و آمازون معرفی میگردد.
سرویسهای رایانش ابری گوگل، در زیر دو چتر قرار دارند. گروه اول شامل مجموعه گستردهای از برنامههای محبوب گوگل مانند Google Doc ، Google Health ، Google Mail ، Google Earth هستند که با کلیک بر روی گزینه More و Even More که در بالای صفحه اصلی گوگل قرار دارند، میتوان به آنها دسترسی پیدا کرد.
دومین محصول مبتنی بر ابر گوگل، ابزار توسعه PaaS گوگل است. این سکو در سال 2008 برای توسعه برنامههای تحت وب، با استفاده از زیرساخت گوگل به نام موتور Google App معرفی شد. هدف از آن قادر ساختن توسعه دهندگان برای ساخت و استقرار برنامههای وب بدون نگرانی از زیرساختی است که برنامه بر رویش اجرا میشود. برنامههای این موتور، با زبانهای سطح بالا به ویژه جاوا و پایتون و در چارچوب GAE نوشته میشوند. گوگل به منظور گسترش این نوع برنامهها یک سطح رایگان مشخص از سرویس را ارائه میدهد و زمانی که برنامه از سطح مشخصی از بار پردازشی، ذخیرهسازی و پهنای باند شبکه فراتر رفت، آنگاه شارژها بر مبنای میزان استفاده محاسبه میشود.
برنامههای GAE را باید به گونهای نوشت که با زیرساخت گوگل وفق یابند. این مسئله، باعث محدودیت برنامههای قابل اجرا در GAE میگردد و علاوه بر آن، انتقال برنامهها به سکوی GAE و یا انتقال از این سکو به سایر سکوهای موجود دشوار میشود.
از میان سرویس های ابری رایگان ارائه شده از سوی گوگل، به معرفی سرویس آنالیز گوگل بسنده کرده و تمرکز اصلی بر روی سکوی توسعه نرمافزاری این شرکت ( GAE ) میباشد.
Google Analytics
به اختصار GA نامیده میشود و یک ابزار آماری است که تعداد و انواع بازدیدکنندگان وبسایت و نحوه استفاده از وبسایت را اندازهگیری میکند. این محصول بر روی بسته تحلیلی Urchin 5 که گوگل در سال 2006 آن را خریداری نمود، ساخته شده است. این سرویس رایگان عرضه میشود و فرآیند تحلیل را با استفاده از یک قطعه کد جاوا اسکریپت به نام Google Analytics Tracking Code با پیادهسازی در تگ صفحه وب انجام میشود.
این کد با اولین بارگذاری صفحه در سیستم کاربران، به جمع آوری اطلاعات مورد نیاز پرداخته و برای پردازش به سرورهای GA باز پس میفرستد. این کد با کمک Cookie مرورگر اطلاعات مورد نیاز را جمع آوری مینماید.
آشنایی با Google App Engine
GAE یک سکو به عنوان سرویس میباشد و مبتنی بر ابر گوگل است و بر روی زیر ساخت گوگل مستقر شده است.
این سرویس توسعه دهندگان را قادر میسازد تا برنامههای وب ایجاد کرده و بر روی سرورهای گوگل مستقر سازند و گوگل مدیریت زیرساخت را بر عهده گیرد و اعمالی مانند نظارت، برطرف کردن اشکالات احتمالی، خوشه بندی، مدیریت وهلهسازی ماشینهای مجازی و غیره را انجام دهد. برای اجرای یک برنامه در GAE ابتدا باید استانداردهای سکوی گوگل رعایت شود. این استانداردها دامنه برنامههایی که قابل اجرا میباشند را بسیار محدود مینماید و قابلیت حمل آنها را کاهش میدهد.
محدودیتهایی
که این سکو ایجاد میکند، با خود مزایایی را به همراه میآورد که در زیر به آنها
اشاره میگردد:
- وب سرویسهای پویا بر مبنای استانداردهای رایج
- توسعه خودکار و توازن بار بین ماشینهای وهلهسازی شده که
مورد استفاده وب سرویس است.
- اعتبارسنجی با استفاده از API
موجود در گوگل.
- فضای ذخیره سازی ماندگار با قابلیت جستجو، مرتب سازی و
مدیریت تراکنش.
- صف کاری و زمان بندی کاری
- محیط توسعه سمت مشتری( توسعه دهندگان ) برای شبیه سازی GAE
در سیستم محلی.
- پشتیبانی از محیط اجرا جاوا و پایتون.
هنگامی که یک برنامه در GAE مستقر گردید، با استفاده از نام دامنه دلخواه یا با استفاده از آدرس تجاری Google Apps قابل دستیابی است. موتور Google Apps در حال حاضر برنامههایی که در جاوا و پایتون نوشته شده است را پشتیبانی میکند و علاوه بر آن از زبانهای ماشین مجازی جاوا و چندین چارچوب تحت وب پایتون که WSGI و CGI را پشتیبانی میکنند نیز با محیط GAE سازگاری دارند.
برنامههایی که در GAE اجرا میشوند از سیستم عامل مستقل هستند یا به گفته گوگل بر روی Sand Box اجرا میشوند. این ویژگی GAE را قادر میسازد، سیستم را بهینه کند تا تقاضاهای وب، با بار ترافیکی فعلی منطبق شوند. همچنین برنامهها را قادر میسازد با امنیت بالاتری کار کنند، زیرا تنها میتوانند به کامپیوترهایی متصل شوند که آدرسهای مشخصی دارند و سرویسها را با استفاده از پروتکل Http و یا Https از پورتهای شناخته شده پاسخ دهند. از طرف دیگر برنامهها نیز به این میزان محدود شده که تنها فایلها را بخوانند. آنها حق نوشتن فایل به صورت مستقیم بر روی سیستمها را ندارند و برای دستیابی به داده، باید از ذخیره داده در Cache یا سرویس ماندگار دیگری استفاده نمایند.
GAE یک سیستم انبار داده توزیع شده دارد که از پرس و جوها و تراکنشها پشتیبانی مینماید. این انبار داده غیر رابطهای است، اما اشیاء داده یا موجودیتهایی که خصوصیات لازم را دارند، ذخیره مینماید. به همین علت در پرس و جوها میتوان از فیلتر نوع موجودیت بهره برد و آنها را به ترتیب خصوصیات مرتب نمود.
در نهایت توجه به مدل قیمتگذاری گوگل قابل توجه است. گوگل برای تشویق توسعه دهندگان در نوشتن برنامه با استفاده از GAE ، استقرار و توسعه برنامه را تا میزان مشخصی از منابع رایگان کرده است و با عبور از مقدار رایگان باید هزینه را به ازای مصرف پرداخت نمود. بر اساس جدول ارائه شده در سایت شرکت گوگل به ازای تجاوز از میزان مصرف رایگان، سیستم هزینه گذاری بر اساس تعرفههای زیر، اقدام به محاسبه حق شارژ مینماید و بدیهی است برای آگاهی از آخرین تعرفهها و کسب اطلاعات بیشتر، مراجعه به صفحه سایت شرکت گوگل توصیه میشود:
- مبلغ به ازای هر یک ساعت استفاده از CPU
معادل 0.08 دلار
- داده ذخیره شده به ازای هر گیگابایت در ماه
معادل 0.18 دلار
- پهنای باند خروجی به ازای هر گیگابایت معادل
0.12 دلار
- پهنای باند ورودی رایگان
- هزینه دریافت هر ایمیل معادل 0.0001 دلار
به منظور ذخیره اطلاعات در منبع داده پایدار، از API استفاده میگردد که به ازای تعداد تراکنشهایی که تبادل میگردد، هزینه پرداخت میشود. از آنجایی که بنا به تعداد تبادلات و نوع حافظه پایداری که استفاده میگردد، هزینه متغیر است، خواننده محترم برای رویت لیست مذکور به منبع ذکر شده، ارجاع داده میشود.
منبع سهمیه | سهمیه پیش فرض رایگان به ازای هر برنامه |
مصرف CPU | 28 ساعت به ازای هر برنامه در روز |
منبع ذخیره پایدار داده | 1 گیگابایت به ازای هر برنامه در ماه |
پهنای باند ورودی | 1 گیگابایت به ازای هر برنامه در روز |
پهنای باند خروجی | 1 گیگابایت به ازای هر برنامه در روز |
تراکنش با منبع داده Datastore | 50 هزار تراکنش برای خواندن و نوشتن به ازای هر برنامه در ماه |
تراکنش با منبع داده Blobstore | 5 گیگابایت به ازای هر برنامه در روز |
ایمیل دریافتی | 100 دریافت به ازای هر برنامه در روز |
dotnet tool install --global dotnet-outdated
dotnet tool update --global dotnet-outdated
dotnet outdated -u
قسمت 5ام از سری ویدیوهای کانکارنسی داریم کم کم به انتهای ویدیوها میرسیم و در این ویدیو درمورد بکگراند تردها و فرگراند تردها صحبت کردیم، به طور کامل فضای تسک و ترد پول رو بررسی و باز کردیم و در انتها یه نگاهی هم به فضای async, await انداختیم که در ادامه ویدیوها بیشتر صحبت میکنیم.
0:00 last session
03:00 Background and foreground thread
06:50 CLR
07:19 Thread Pool
11:00 Task
13:30 Task Result
16:40 Long Running Tasks
وضعیت Blazor WebAssembly را چطور ارزیابی میکنید؟
تا صحبت از گزارشگیری به میان بیاید احتمالا معرفی ابزارهای تجاری مانند Reporting services ، کریستال ریپورت، stimulsoft.com ، fast-report.com و امثال آن درصدر لیست توصیه کنندگان و مشاوران قرار خواهند داشت. اما خوب برای ایجاد یک گزارشگیری ساده حتما نیازی نیست تا به این نوع ابزارهای تجاری مراجعه کرد. ابزار رایگان و سورس باز جالبی هم در این باره جهت پروژههای WPF در دسترس است:
در ادامه در طی یک مثال قصد داریم از این کتابخانه استفاده کنیم:
1) تنظیم وابستگیها
پس از دریافت کتابخانه فوق، ارجاعات زیر باید به پروژه شما اضافه شوند:
CodeReason.Reports.dll (از پروژه فوق) و ReachFramework.dll (جزو اسمبلیهای استاندارد دات نت است)
2) تهیه منبع داده گزارش
کتابخانهی فوق به صورت پیش فرض با DataTable کار میکند. بنابراین کوئریهای شما یا باید خروجی DataTable داشته باشد یا باید از یک سری extension methods برای تبدیل IEnumerable به DataTable استفاده کرد (در پروژه پیوست شده در پایان مطلب، این موارد موجود است).
برای مثال فرض کنید میخواهیم رکوردهایی را از نوع کلاس Product زیر در گزارش نمایش دهیم:
namespace WpfRptTests.Model
{
public class Product
{
public string Name { set; get; }
public int Price { set; get; }
}
}
الف) اضافه کردن فایل تشکیل دهنده ساختار و ظاهر گزارش
گزارشهای این کتابخانه مبتنی است بر اشیاء FlowDocument استاندارد WPF . بنابراین از منوی پروژه گزینهی Add new item در قسمت WPF آن یک FlowDocument جدید را به پروژه اضافه کنید ( باید دقت داشت که Build action این فایل باید به Content تنظیم گردد). ساختار ابتدایی این FlowDocument به صورت زیر خواهد بود که به آن FlowDirection و FontFamily مناسب جهت گزارشات فارسی اضافه شده است. همچنین فضای نام مربوط به کتابخانهی گزارشگیری CodeReason.Reports نیز باید اضافه گردد.
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FlowDirection="RightToLeft" FontFamily="Tahoma"
xmlns:xrd="clr-namespace:CodeReason.Reports.Document;assembly=CodeReason.Reports"
PageHeight="29.7cm" PageWidth="21cm" ColumnWidth="21cm">
</FlowDocument>
مواردی که در ادامه ذکر خواهند شد محتوای این گزارش را تشکیل میدهند:
ب) مشخص سازی خواص گزارش
<xrd:ReportProperties>
<xrd:ReportProperties.ReportName>SimpleReport</xrd:ReportProperties.ReportName>
<xrd:ReportProperties.ReportTitle>گزارش از محصولات</xrd:ReportProperties.ReportTitle>
</xrd:ReportProperties>
ج) مشخص سازی Page Header و Page Footer
اگر میخواهید عباراتی در بالا و پایین تمام صفحات گزارش تکرار شوند میتوان از SectionReportHeader و SectionReportFooter این کتابخانه به صورت زیر استفاده کرد:
<xrd:SectionReportHeader PageHeaderHeight="2" Padding="10,10,10,0" FontSize="12">
<Table CellSpacing="0">
<Table.Columns>
<TableColumn Width="*" />
<TableColumn Width="*" />
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell>
<Paragraph>
<xrd:InlineContextValue PropertyName="ReportTitle" />
</Paragraph>
</TableCell>
<TableCell>
<Paragraph TextAlignment="Right">
<xrd:InlineDocumentValue PropertyName="PrintDate" Format="dd.MM.yyyy HH:mm:ss" />
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</xrd:SectionReportHeader>
<xrd:SectionReportFooter PageFooterHeight="2" Padding="10,0,10,10" FontSize="12">
<Table CellSpacing="0">
<Table.Columns>
<TableColumn Width="*" />
<TableColumn Width="*" />
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell>
<Paragraph>
نام کاربر:
<xrd:InlineDocumentValue PropertyName="RptBy" Format="dd.MM.yyyy HH:mm:ss" />
</Paragraph>
</TableCell>
<TableCell>
<Paragraph TextAlignment="Right">
صفحه
<xrd:InlineContextValue PropertyName="PageNumber" FontWeight="Bold" /> از
<xrd:InlineContextValue PropertyName="PageCount" FontWeight="Bold" />
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</xrd:SectionReportFooter>
دو نکته در اینجا حائز اهمیت هستند: xrd:InlineDocumentValue و xrd:InlineContextValue
InlineDocumentValue را میتوان در کدهای برنامه به صورت سفارشی اضافه کرد. بنابراین هر جایی که نیاز بود مقدار ثابتی از طریق کد نویسی به گزارش تزریق و اضافه شود میتوان از InlineDocumentValue استفاده کرد. برای مثال در کدهای ViewModel برنامه که در ادامه ذکر خواهد شد دو مقدار PrintDate و RptBy به صورت زیر تعریف و مقدار دهی شدهاند:
data.ReportDocumentValues.Add("PrintDate", DateTime.Now);
data.ReportDocumentValues.Add("RptBy", "وحید");
د) مشخص سازی ساختار تولیدی گزارش
<Section Padding="80,10,40,10" FontSize="12">
<Paragraph FontSize="24" TextAlignment="Center" FontWeight="Bold">
<xrd:InlineContextValue PropertyName="ReportTitle" />
</Paragraph>
<Paragraph TextAlignment="Center">
گزارش از لیست محصولات در تاریخ:
<xrd:InlineDocumentValue PropertyName="PrintDate" Format="dd.MM.yyyy HH:mm:ss" />
توسط:
<xrd:InlineDocumentValue PropertyName="RptBy" Format="dd.MM.yyyy HH:mm:ss" />
</Paragraph>
<xrd:SectionDataGroup DataGroupName="ItemList">
<Table CellSpacing="0" BorderBrush="Black" BorderThickness="0.02cm">
<Table.Resources>
<!-- Style for header/footer rows. -->
<Style x:Key="headerFooterRowStyle" TargetType="{x:Type TableRowGroup}">
<Setter Property="FontWeight" Value="DemiBold"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Background" Value="LightGray"/>
</Style>
<!-- Style for data rows. -->
<Style x:Key="dataRowStyle" TargetType="{x:Type TableRowGroup}">
<Setter Property="FontSize" Value="12"/>
</Style>
<!-- Style for data cells. -->
<Style TargetType="{x:Type TableCell}">
<Setter Property="Padding" Value="0.1cm"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="0.01cm"/>
</Style>
</Table.Resources>
<Table.Columns>
<TableColumn Width="0.8*" />
<TableColumn Width="0.2*" />
</Table.Columns>
<TableRowGroup Style="{StaticResource headerFooterRowStyle}">
<TableRow>
<TableCell>
<Paragraph TextAlignment="Center">
<Bold>نام محصول</Bold>
</Paragraph>
</TableCell>
<TableCell>
<Paragraph TextAlignment="Center">
<Bold>قیمت</Bold>
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
<TableRowGroup Style="{StaticResource dataRowStyle}">
<xrd:TableRowForDataTable TableName="Product">
<TableCell>
<Paragraph>
<xrd:InlineTableCellValue PropertyName="Name" />
</Paragraph>
</TableCell>
<TableCell>
<Paragraph TextAlignment="Center">
<xrd:InlineTableCellValue PropertyName="Price" AggregateGroup="Group1" />
</Paragraph>
</TableCell>
</xrd:TableRowForDataTable>
</TableRowGroup>
<TableRowGroup Style="{StaticResource headerFooterRowStyle}">
<TableRow>
<TableCell>
<Paragraph TextAlignment="Right">
<Bold>جمع کل</Bold>
</Paragraph>
</TableCell>
<TableCell>
<Paragraph TextAlignment="Center">
<Bold>
<xrd:InlineAggregateValue AggregateGroup="Group1"
AggregateValueType="Sum"
EmptyValue="0"
FontWeight="Bold" />
</Bold>
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
<Paragraph TextAlignment="Center" Margin="5">
در این گزارش
<xrd:InlineAggregateValue AggregateGroup="Group1"
AggregateValueType="Count"
EmptyValue="هیچ"
FontWeight="Bold" /> محصول با جمع کل قیمت
<xrd:InlineAggregateValue AggregateGroup="Group1"
AggregateValueType="Sum"
EmptyValue="0"
FontWeight="Bold" /> وجود دارند.
</Paragraph>
</xrd:SectionDataGroup>
</Section>
در ابتدا توسط دو پاراگراف، عنوان گزارش و یک سطر زیر آن نمایش داده شدهاند. بدیهی است هر نوع شیء و فرمت مجاز در FlowDocument را میتوان در این قسمت نیز قرار داد.
سپس یک SectionDataGroup جهت نمایش لیست آیتمها اضافه شده و داخل آن یک جدول که بیانگر ساختار جدول نمایش رکوردهای گزارش میباشد، ایجاد گردیده است.
سه TableRowGroup در این جدول تعریف شدهاند.
TableRowGroup های اولی و آخری دو سطر اول و آخر جدول گزارش را مشخص میکنند (سطر عناوین ستونها در ابتدا و سطر جمع کل در پایان گزارش)
از TableRowGroup میانی برای نمایش رکوردهای مرتبط با نام جدول مورد گزارشگیری استفاده شده است. توسط TableRowForDataTable آن نام این جدول باید مشخص شود که در اینجا همان نام کلاس مدل برنامه است. به کمک InlineTableCellValue، خاصیتهایی از این کلاس را که نیاز است در گزارش حضور داشته باشند، ذکر خواهیم کرد. نکتهی مهم آن AggregateGroup ذکر شده است. توسط آن میتوان اعمال جمع، محاسبه تعداد، حداقل و حداکثر و امثال آنرا که در فایل InlineAggregateValue.cs سورس کتابخانه ذکر شدهاند، به فیلدهای مورد نظر اعمال کرد. برای مثال میخواهیم جمع کل قیمت را در پایان گزارش نمایش دهیم به همین جهت نیاز بود تا یک AggregateGroup را برای این منظور تعریف کنیم.
از این AggregateGroup در سومین TableRowGroup تعریف شده به کمک xrd:InlineAggregateValue جهت نمایش جمع نهایی استفاده شده است.
همچنین اگر نیاز بود در پایان گزارش اطلاعات بیشتری نیز نمایش داده شود به سادگی میتوان با تعریف یک پاراگراف جدید، اطلاعات مورد نظر را نمایش داد.
4) نمایش گزارش تهیه شده
نمایش این گزارش بسیار ساده است. View برنامه به صورت زیر خواهد بود:
<Window x:Class="WpfRptTests.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:CodeReason.Reports.Controls;assembly=CodeReason.Reports"
xmlns:vm="clr-namespace:WpfRptTests.ViewModel"
Title="MainWindow" WindowState="Maximized" Height="350" Width="525">
<Window.Resources>
<vm:ProductViewModel x:Key="vmProductViewModel" />
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource vmProductViewModel}}">
<c:BusyDecorator IsBusyIndicatorHidden="{Binding RptGuiModel.IsBusyIndicatorHidden}">
<DocumentViewer Document="{Binding RptGuiModel.Document}" />
</c:BusyDecorator>
</Grid>
</Window>
تعریف ابتدایی RptGuiModel به صورت زیر است (جهت مشخص سازی مقادیر IsBusyIndicatorHidden و Document در حین بایندینگ اطلاعات):
using System.ComponentModel;
using System.Windows.Documents;
namespace WpfRptTests.Model
{
public class RptGuiModel
{
public IDocumentPaginatorSource Document { get; set; }
public bool IsBusyIndicatorHidden { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using CodeReason.Reports;
using WpfRptTests.Helper;
using WpfRptTests.Model;
namespace WpfRptTests.ViewModel
{
public class ProductViewModel
{
#region Constructors (1)
public ProductViewModel()
{
RptGuiModel = new RptGuiModel();
if (Stat.IsInDesignMode) return;
//انجام عملیات نمایش گزارش در یک ترد دیگر جهت قفل نشدن ترد اصلی برنامه
showReportAsync();
}
#endregion Constructors
#region Properties (1)
public RptGuiModel RptGuiModel { set; get; }
#endregion Properties
#region Methods (3)
// Private Methods (3)
private static List<Product> getProducts()
{
var products = new List<Product>();
for (var i = 0; i < 100; i++)
products.Add(new Product { Name = string.Format("Product{0}", i), Price = i });
return products;
}
private void showReport()
{
try
{
//Show BusyIndicator
RptGuiModel.IsBusyIndicatorHidden = false;
var reportDocument =
new ReportDocument
{
XamlData = File.ReadAllText(@"Report\SimpleReport.xaml"),
XamlImagePath = Path.Combine(Environment.CurrentDirectory, @"Report\")
};
var data = new ReportData();
// تعریف متغیرهای دلخواه و مقدار دهی آنها
data.ReportDocumentValues.Add("PrintDate", DateTime.Now);
data.ReportDocumentValues.Add("RptBy", "وحید");
// استفاده از یک سری اطلاعات آزمایشی به عنوان منبع داده
data.DataTables.Add(getProducts().ToDataTable());
var xps = reportDocument.CreateXpsDocument(data);
//انقیاد آن به صورت غیر همزمان در ترد اصلی برنامه
DispatcherHelper.DispatchAction(
() => RptGuiModel.Document = xps.GetFixedDocumentSequence()
);
}
catch (Exception ex)
{
//وجود این مورد ضروری است زیرا بروز استثناء در یک ترد به معنای خاتمه آنی برنامه است
//todo: log errors
}
finally
{
//Hide BusyIndicator
RptGuiModel.IsBusyIndicatorHidden = true;
}
}
private void showReportAsync()
{
var thread = new Thread(showReport);
thread.SetApartmentState(ApartmentState.STA); //for DocumentViewer
thread.Start();
}
#endregion Methods
}
}
توضیحات:
برای اینکه حین نمایش گزارش، ترد اصلی برنامه قفل نشود، از ترد استفاده شد و استفاده ترد به همراه DocumentViewer کمی نکته دار است:
- ترد تعریف شده باید از نوع STA باشد که در متد showReportAsync مشخص شده است.
- حین بایندیگ Document تولید شده توسط کتابخانهی گزارشگیری به خاصیت Document کنترل، حتما باید کل عملیات در ترد اصلی برنامه صورت گیرد که سورس کلاس DispatcherHelper را در فایل پیوست خواهید یافت.
کل عملیات این ViewModel در متد showReport رخ میدهد، ابتدا فایل گزارش بارگذاری میشود، سپس متغیرهای سفارشی مورد نظر تعریف و مقدار دهی خواهند شد. در ادامه یک سری داده آزمایشی تولید و به DataTables گزارش ساز اضافه میشوند. در پایان XPS Document متناظر آن تولید شده و به کنترل نمایشی برنامه بایند خواهد شد.
دریافت سورس این مثال
public class ApplicationUser : IdentityUser { public string Email { get; set; } public string ConfirmationToken { get; set; } public bool IsConfirmed { get; set; } }
private string CreateConfirmationToken() { return ShortGuid.NewGuid(); } private void SendEmailConfirmation(string to, string username, string confirmationToken) { dynamic email = new Email("RegEmail"); email.To = to; email.UserName = username; email.ConfirmationToken = confirmationToken; email.Send(); } // // POST: /Account/Register [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { string confirmationToken = CreateConfirmationToken(); var user = new ApplicationUser() { UserName = model.UserName, Email = model.Email, ConfirmationToken = confirmationToken, IsConfirmed = false }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { SendEmailConfirmation(model.Email, model.UserName, confirmationToken); return RedirectToAction("RegisterStepTwo", "Account"); } else { AddErrors(result); } } // If we got this far, something failed, redisplay form return View(model); }
private bool ConfirmAccount(string confirmationToken) { ApplicationDbContext context = new ApplicationDbContext(); ApplicationUser user = context.Users.SingleOrDefault(u => u.ConfirmationToken == confirmationToken); if (user != null) { user.IsConfirmed = true; DbSet<ApplicationUser> dbSet = context.Set<ApplicationUser>(); dbSet.Attach(user); context.Entry(user).State = EntityState.Modified; context.SaveChanges(); return true; } return false; } [AllowAnonymous] public ActionResult RegisterConfirmation(string Id) { if (ConfirmAccount(Id)) { return RedirectToAction("ConfirmationSuccess"); } return RedirectToAction("ConfirmationFailure"); }
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (ModelState.IsValid) { var user = await UserManager.FindAsync(model.UserName, model.Password); if (user != null && user.IsConfirmed) { await SignInAsync(user, model.RememberMe); return RedirectToLocal(returnUrl); } else { ModelState.AddModelError("", "Invalid username or password."); } } // If we got this far, something failed, redisplay form return View(model); }
توضیحاتی درباره کار با Postal
To: @ViewBag.To From: YOURNAME@gmail.com Subject: Confirm your registration Hello @ViewBag.UserName, Please confirm your registration by following the link bellow. @Html.ActionLink(Url.Action("RegisterConfirmation", "Account", new { id = @ViewBag.ConfirmationToken }), "RegisterConfirmation", "Account", new { id = @ViewBag.ConfirmationToken }, null)
- ViewBag.To آدرس ایمیل گیرنده را نشان میدهد.
- ViewBag.UserName نام کاربر جاری را نمایش میدهد.
- ViewBag.ConfirmationToken شناسه تولید شده برای تایید کاربر است.
@{ Layout = null; /* Overrides the Layout set for regular page views. */ }