مطالب
تغییرات مهم مقایسه‌‌ی رشته‌ها در NET 5.0.
با توجه به ماهیت چندسکویی NET 5.، در اکثر سیستم‌های ویندوزی، سرویس بومی سازی، بر اساس استاندارد NLS کار می‌کند، اما در سیستم‌های لینوکسی و مبتنی بر یونیکس، این استاندارد از نوع ICU است (و وجود و تنظیم آن‌ها خارج از NET. و توسط سیستم عامل مدیریت می‌شود). جهت یک‌دست سازی این دو نوع سیستم بومی سازی در دات نت، از نگارش 5 آن به بعد، استاندارد ICU که به صورت گسترده‌تری مورد پذیرش قرار گرفته‌است، استاندارد بومی سازی پیش‌فرض دات نت درنظر گرفته می‌شود؛ مگر اینکه سیستم عاملی آن‌را پشتیبانی نکند.


کدام نگارش از ویندوز، از ICU پشتیبانی می‌کند؟

تمام ویندوزهای پس از Windows 10 May 2019 Update، به همراه icu.dll، به عنوان جزء استاندارد سیستم عامل هستند. بنابراین دات نت 5 و نگارش‌های پس از آن، در این سیستم عامل‌ها، از سرویس بومی سازی ICU استفاده خواهند کرد؛ اما اگر از نگارش‌های پیشین ویندوز استفاده می‌کنید، به اجبار به سیستم NLS سوئیچ خواهد شد.


تاثیر ICU بر برنامه‌های دات نت 5 به بعد

قطعه کد زیر را درنظر بگیرید:
string s = "Hello\r\nworld!";
int idx = s.IndexOf("\n");
Console.WriteLine(idx);
در نگارش‌های پیش از 5 دات نت، خروجی کدهای فوق، عدد 6 است؛ اما ... اما ... (!) از زمان دات نت 5 به بعد، خروجی آن «منهای یک» است! البته به شرطی که آخرین به روز رسانی ویندوز 10 را نصب کرده باشید؛ یعنی حداقل  Windows 10 May 2019 Update را داشته باشید.


حالت «پیش‌فرض» جستجو و مقایسه‌ی رشته‌ها در دات نت 5 به بعد، یک مقایسه‌ی مبتنی بر «دستورات زبانی» بر اساس فرهنگ تنظیم شده‌ی در Thread جاری برنامه‌است (یا همان System.Threading.Thread.CurrentThread.CurrentCulture).


چرا متدهای کار بر روی رشته‌ها در دات نت 5 به بعد، نسبت به نگارش‌های قبلی متفاوت عمل می‌کنند؟

زمانیکه متدی مانند IndexOf فراخوانی می‌شود، هدف عمده‌ی برنامه‌نویس‌ها، یک جستجوی Ordinal است (یعنی مقایسه‌ی کاراکتر به کاراکتر؛ بدون درنظر گرفتن نکات زبانی و بومی)؛ اما فراموش می‌کنند که این متدها دارای پارامتر دومی هم هستند که از نوع StringComparison است و سال‌ها است که توصیه می‌شود این پارامتر را هم به صورت صریحی مقدار دهی کنید تا هدف خود را از نوع جستجو دقیقا مشخص نمائید. از زمان دات نت 5 به بعد، اگر این پارامتر را مشخص نکنید، جستجوی صورت گرفته یک رفتار culture-specific را خواهد داشت و نه Ordinal.  از این لحاظ مقایسه‌ی رشته‌ها توسط استانداردهای ICU و NLS، بر اساس پیاده سازی‌های مختلف زبان‌شناسی، خروجی‌های یکسانی را ارائه نمی‌دهند و به همین جهت است که اینبار خروجی منهای یک را دریافت می‌کنیم.

یک نکته: خروجی قطعه کد فوق در سیستم‌های لینوکسی که از .NET Core 2x - 3x. هم استفاده می‌کنند، دقیقا منهای یک است؛ چون پیش‌فرض بومی سازی آن‌ها نیز ICU است.


چگونه می‌توان به همان حالت پیشین مقایسه‌ی رشته‌ها در NET. بازگشت؟

مایکروسافت بسته‌ی نیوگت Microsoft.CodeAnalysis.FxCopAnalyzers را جهت گوشزد کردن نکته‌ی ذکر صریح StringComparison، به روز رسانی کرده‌است. بنابراین بهتر است تا آن‌را به پروژه‌ی خود اضافه کنید. در این حالت اخطارهای مناسبی را جهت یافتن قسمت‌های مشکل‌دار برنامه‌ی خود دریافت می‌کنید. برای مثال برای اینکه در قطعه کد فوق به همان پاسخ متداول 6 برسیم، تنها کافی‌است پارامتر دوم StringComparison را ذکر کنیم:
int idx = s.IndexOf("\n", StringComparison.Ordinal);

و یا حتی می‌توانید فایل csproj پروژه‌ی خود را ویرایش کرده و یک سطر زیر را به آن اضافه کنید:
<ItemGroup>
   <RuntimeHostConfigurationOption Include="System.Globalization.UseNls" Value="true" />
</ItemGroup>
در این حالت کل برنامه‌ی شما بدون هیچ تغییری مانند قبل کار کرده و از سیستم NLS استفاده می‌شود.



کدام متدهای کار با رشته‌ها در دات نت 5، تحت تاثیر این تغییرات قرار گرفته‌اند؟

اگر از متدهای زیر در برنامه‌های خود استفاده می‌کنید، نکته‌ی ذکر پارامتر StringComparison.Ordinal را فراموش نکنید:
System.String.Compare
System.String.EndsWith
System.String.IndexOf
System.String.StartsWith
System.String.ToLower
System.String.ToLowerInvariant
System.String.ToUpper
System.String.ToUpperInvariant
System.Globalization.TextInfo (most members)
System.Globalization.CompareInfo (most members)
System.Array.Sort (when sorting arrays of strings)
System.Collections.Generic.List<T>.Sort() (when the list elements are strings)
System.Collections.Generic.SortedDictionary<TKey,TValue> (when the keys are strings)
System.Collections.Generic.SortedList<TKey,TValue> (when the keys are strings)
System.Collections.Generic.SortedSet<T> (when the set contains strings)


سؤال: اگر متدی پارامتر دوم StringComparison را نداشت چطور؟
اگر به ماخذ «Behavior changes when comparing strings on .NET 5» مراجعه کنید، در انتهای آن جدولی را ارائه داده که دو سطر اول آن، به صورت زیر است:
API                Default behavior       Remarks
string.Compare     CurrentCulture
در این جدول، هر متدی که رفتار پیش‌فرض آن از نوع CurrentCulture است، تحت تاثیر قرار گرفته‌است و متدی مانند string.Contains که رفتار پیش‌فرض آن Ordinal است، از این تغییرات مصون است و نیازی به تغییری ندارد.


برای مطالعه‌ی بیشتر:
Behavior changes when comparing strings on .NET 5+
.NET globalization and ICU.
Globalization breaking changes
بحث و گفتگویی در این مورد
مطالب دوره‌ها
تبدیل روش‌های قدیمی کدنویسی غیرهمزمان به async سی شارپ 5
در قسمت اول این سری، با مدل برنامه نویسی Event based asynchronous pattern ارائه شده از دات نت 2 و همچنین APM یا Asynchronous programming model موجود از نگارش یک دات نت، آشنا شدیم (به آن الگوی IAsyncResult هم گفته می‌شود). نکته‌ی مهم این الگوها، استفاده‌ی گسترده از آن‌ها در کدهای کلاس‌های مختلف دات نت فریم ورک است و برای بسیاری از آن‌ها هنوز async API سازگار با نگارش مبتنی بر Taskهای سی‌شارپ 5 ارائه نشده‌است. هرچند دات نت 4.5 سعی کرده‌است این خلاء را پوشش دهد، برای مثال متد الحاقی DownloadStringTaskAsync را به کلاس WebClient اضافه کرده‌است و امثال آن، اما هنوز بسیاری از کلاس‌های دیگر دات نتی هستند که معادل Task based API ایی برای آن‌ها طراحی نشده‌است. در ادامه قصد داریم بررسی کنیم چگونه می‌توان این الگوهای مختلف قدیمی برنامه نویسی غیرهمزمان را با استفاده از روش‌های جدیدتر ارائه شده بکار برد.



نگاشت APM به یک Task

در قسمت اول، نمونه مثالی را از APM، که در آن کار با BeginGetResponse آغاز شده و سپس در callback نهایی توسط EndGetResponse، نتیجه‌ی عملیات به دست می‌آید، مشاهده کردید. در ادامه می‌خواهیم یک محصور کننده‌ی جدید را برای این نوع API قدیمی تهیه کنیم، تا آن‌را به صورت یک Task ارائه دهد.
    public static class ApmWrapper
    {
        public static Task<int> ReadAsync(this Stream stream, byte[] data, int offset, int count)
        {
            return Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, data, offset, count, null);
        }
    }
همانطور که در این مثال مشاهده می‌کنید، یک چنین سناریوهایی در TPL یا کتابخانه‌ی Task parallel library پیش بینی شده‌اند. در اینجا یک محصور کننده برای متدهای BeginRead و EndRead کلاس Stream دات نت ارائه شده‌است. به عمد نیز به صورت یک متد الحاقی تهیه شده‌است تا در حین استفاده از آن اینطور به نظر برسد که واقعا کلاس Stream دارای یک چنین متد Async ایی است. مابقی کار توسط متد Task.Factory.FromAsync انجام می‌شود. متد FromAsync دارای امضاهای متعددی است تا اکثر حالات APM را پوشش دهد.
در مثال فوق BeginRead و EndRead استفاده شده از نوع delegate هستند. چون خروجی EndRead از نوع int است، خروجی متد نیز از نوع Task of int تعیین شده‌است. همچنین سه پارامتر ابتدایی BeginRead ، دقیقا data، offset و count هستند. دو پارامتر آخر آن callback و state نام دارند. پارامتر callback توسط متد FromAsync فراهم می‌شود و state نیز در اینجا null درنظر گرفته شده‌است.
یک مثال استفاده از آن‌را در ادامه مشاهده می‌کنید:
using System;
using System.IO;
using System.Threading.Tasks;

namespace Async06
{
    public static class ApmWrapper
    {
        public static Task<int> ReadAsync(this Stream stream, byte[] data, int offset, int count)
        {
            return Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, data, offset, count, null);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (var stream = File.OpenRead(@"..\..\program.cs"))
            {
                var data = new byte[10000];
                var task = stream.ReadAsync(data, 0, data.Length);
                Console.WriteLine("Read bytes: {0}", task.Result);
            }
        }
    }
}
File.OpenRead، خروجی از نوع استریم دارد. سپس متد الحاقی ReadAsync بر روی آن فراخوانی شده‌است و نهایتا تعداد بایت خوانده شده نمایش داده می‌شود.
البته همانطور که پیشتر نیز عنوان شد، استفاده از خاصیت Result، اجرای کد را بجای غیرهمزمان بودن، به حالت همزمان تبدیل می‌کند.
در اینجا چون خروجی متد ReadAsync یک Task است، می‌توان از متد ContinueWith نیز بر روی آن جهت دریافت نتیجه استفاده کرد:
using (var stream = File.OpenRead(@"..\..\program.cs"))
{
    var data = new byte[10000];
    var task = stream.ReadAsync(data, 0, data.Length);
    task.ContinueWith(t => Console.WriteLine("Read bytes: {0}", t.Result)).Wait();
}


یک نکته
پروژه‌ی سورس بازی به نام Async Generator در GitHub، سعی کرده‌است برای ساده سازی نوشتن محصور کننده‌های مبتنی بر Task روش APM، یک Code generator تولید کند. فایل‌های آن‌را از آدرس ذیل می‌توانید دریافت کنید:

نگاشت EAP به یک Task

نمونه‌ای از Event based asynchronous pattern یا EAP را در قسمت اول، زمانیکه روال رخدادگردان webClient.DownloadStringCompleted را بررسی کردیم، مشاهده نمودید. کار کردن با آن نسبت به APM بسیار ساده‌تر است و نتیجه‌ی نهایی عملیات غیرهمزمان را در یک روال رخدادگران، در اختیار استفاده کننده قرار می‌دهد. همچنین در روش EAP، اطلاعات در همان Synchronization Context ایی که عملیات شروع شده‌است، بازگشت داده می‌شود. به این ترتیب اگر آغاز کار در ترد UI باشد، نتیجه نیز در همان ترد دریافت خواهد شد. به این ترتیب دیگر نگران دسترسی به مقدار آن در کارهای UI نخواهیم بود؛ اما در APM چنین ضمانتی وجود ندارد.
متاسفانه TPL همانند روش FromAsync معرفی شده در ابتدای بحث، راه حل توکاری را برای محصور سازی متدهای روش EAP ارائه نداده‌است. اما با استفاده از امکانات TaskCompletionSource آن می‌توان چنین کاری را انجام داد. در ادامه سعی خواهیم کرد همان متد الحاقی توکار DownloadStringTaskAsync ارائه شده در دات نت 4.5 را از صفر بازنویسی کنیم.
    public static class WebClientExtensions
    {
        public static Task<string> DownloadTextTaskAsync(this WebClient web, string url)
        {
            var tcs = new TaskCompletionSource<string>();

            DownloadStringCompletedEventHandler handler = null;
            handler = (sender, args) =>
            {
                web.DownloadStringCompleted -= handler;

                if (args.Cancelled)
                {
                    tcs.SetCanceled();
                }
                else if(args.Error!=null)
                {
                    tcs.SetException(args.Error);
                }
                else
                {
                    tcs.SetResult(args.Result);
                }
            };

            web.DownloadStringCompleted += handler;
            web.DownloadStringAsync(new Uri(url));

            return tcs.Task;
        }
    }
روش انجام کار را در اینجا ملاحظه می‌کنید. ابتدا باید تعاریف delaget مرتبط با رخدادگردان Completed اضافه شوند. یکبار += را ملاحظه می‌کنید و بار دوم -= را. مورد دوم جهت آزاد سازی منابع و جلوگیری از نشتی حافظه‌ی ‌روال رخدادگردان هنوز متصل، ضروری است.
سپس از TaskCompletionSource برای تبدیل این عملیات به یک Task کمک می‌گیریم. اگر args.Cancelled مساوی true باشد، یعنی عملیات دریافت فایل لغو شده‌است. بنابراین متد SetCanceled منبع Task ایجاد شده را فراخوانی خواهیم کرد. این مورد استثنایی را در کدهای فراخوان سبب می‌شود. به همین دلیل بررسی خطا با یک if else پس از آن انجام شده‌است. برای بازگشت خطای دریافت شده از متد SetException و برای بازگشت نتیجه‌ی واقعی دریافتی، از متد SetResult می‌توان استفاده کرد.
به این ترتیب متد الحاقی غیرهمزمان جدیدی را به نام DownloadTextTaskAsync برای محصور سازی متد EAP ایی به نام DownloadStringAsync و همچنین رخدادگران آن تهیه کردیم.
مطالب
روش بازگشت به قالب‌های کلاسیک پروژه‌ها در دات نت 6
نگارش نهایی دات نت 6، حدود یک ماه دیگر منتشر می‌شود و اگر برای نمونه RC2 آن‌را نصب کرده باشید، با ایجاد یک پروژه‌ی کنسول جدید مبتنی بر آن ... شگفت زده خواهید شد!  شاید انتظار داشته باشید که با چنین فایلی مواجه شوید:
using System; 
 
namespace MyVerboseApp 
{ 
    public class Program 
    { 
        public static void Main(string[] args) 
        { 
            Console.WriteLine("Hello World!"); 
        } 
    } 
}
اما یک چنین خروجی تولید می‌شود:
 // See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
این مورد قابلیتی است که به همراه C# 9.0 به نام «Top Level Programs» ارائه شد و اکنون در تمام قالب‌های پیش‌فرض پروژه‌های مبتنی بر دات نت 6، استفاده شده‌است. این قالب شاید برای تازه‌کارها، جالب باشد و کم حجم و کم سطر، اما «ما آن‌را درخواست نداده بودیم!».


روش بازگشت به قالب‌های قبلی

در حال حاضر و در نگارش فعلی و حتی رسمی دات نت 6، روشی برای بازگشت به حالت قبلی وجود ندارد که به احتمال زیاد در نگارش‌های پس از RTM لحاظ خواهد شد (می‌توانید در اینجا ^ و ^ به آن رای دهید). تنها راه حل موجود، استفاده از دستور زیر است:
dotnet new console --framework net5.0 --target-framework-override net6.0
این دستور در اصل به این معنا است که پروژه‌ی من را بر اساس قالب پروژه‌های NET 5.0. تولید کن؛ اما در فایل csproj آن، بجای net5.0 از net6.0 به عنوان target framework استفاده شود:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
    <OutputType>Exe</OutputType>
-    <TargetFramework>net5.0</TargetFramework>
+    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>
</Project>
در اینجا سطر net5.0 را حذف و با net6.0 جایگزین کنید.
مطالب
نصب یک اسمبلی دات نت در GAC

افزونه فارسی به پارسی را قبل از ارائه در سایت، بر روی یک ماشین مجازی هم تست کردم. برای این منظور از Microsoft virtual pc استفاده شد. البته در مقابل امکانات VMware شاید حرفی برای گفتن نداشته باشد ولی خوب جهت مقاصد تست نرم افزار بر روی یک سیستم عاری از وسایل برنامه نویسی مناسب است. (برای نصب یک سیستم عامل توسط آن برای مثال می‌شود از سی دی آن OS یک فایل ISO تهیه کرد و مسیر این فایل ISO را به ماشین مجازی معرفی کرد . سپس سیستم بوت شده و روال نصب مطابق معمول خواهد بود)
اولین مشکلی که پس از تست بر روی سیستم مجازی رخ داد، پیغام یافت نشدن اسمبلی مربوط به SQLite بود. نرم افزار word هنگام اجرای افزونه‌های دات نت، آنها را در مسیری با یک نامگذاری منحصربفرد کپی می‌کند و تنها هم همان اسمبلی افزونه را کپی می‌کند و نه سایر موارد همراه را. برای پیدا کردن این مسیر می‌شود از روش زیر استفاده کرد:
using System.Reflection;
Assembly.GetExecutingAssembly().Location

در این مسیر اسمبلی SQLite وجود ندارد و به همین دلیل هم بارگذاری نخواهد شد. بهترین راه حل برای رفع این مشکل، نصب اسمبلی مربوطه در GAC یا global assembly cache است.
برای نصب اسمبلی در GAC استفاده از برنامه gacutil توصیه شده است. این برنامه به همراه SDK دات نت فریم ورک ارائه می‌شود و الزامی ندارد که کاربر نهایی این برنامه را داشته باشد. خوشبختانه با استفاده از برنامه نویسی هم می‌شود یک نمونه از برنامه Gacutil را خودمان ایجاد کنیم (برای مثال ایجاد یک برنامه کنسول و دریافت مسیر از طریق آرگومان‌های ارسالی به آن):

new System.EnterpriseServices.Internal.Publish().GacInstall(path);

در اینجا باید ارجاعی از System.EnterpriseServices نیز به برنامه اضافه شود.
این روش در مورد اسمبلی SQLite که دارای امضای دیجیتال است کار خواهد کرد. اما اگر قصد داشته باشید به صورت عمومی از آن استفاده کنید، باید ابتدا بررسی کرد که آیا فایل اسمبلی دارای امضای دیجیتال است یا خیر. برای این منظور می‌توان مقدار عبارت زیر را ارزیابی کرد:
Assembly.LoadFile(path).GetName().GetPublicKey().Length

اگر این طول بزرگتر از صفر بود به این معنا است که فایل اسمبلی دارای امضای دیجیتال است و می‌توان آنرا در GAC نصب کرد.
لازم به ذکر است که متد معرفی شده برای نصب در GAC در صورت عدم موفقیت هیچ پیغام خطا یا exception ایی را در برنامه تولید نخواهد کرد. اما پیغام خطای حاصل را در event log ویندوز می‌توان مشاهده کرد.


نظرات مطالب
اطلاع از بروز رسانی نرم افزار ساخته شده
با تشکر از توجه و راهنمایی شما. نرم افزارهای زیادی برای این کار وجود داره ولی من خیلی وقته از Snagit و Snagit Editor استفاده میکنم. این نرم افزار بیشتر برای فیلم و عکس گرفتن از دسکتاب استفاده میشه ولی امکانات فراوانی دیگری هم در این نرم افزار وجود داره. من خودم نسخه Snagit 11.2.1 را از سایت http://www.softgozar.com  دانلود کردم.
مطالب
قسمت اول - ساخت گزارش در محیط Telerik Reporting
یکی از ضروریات نرم افزارها وجود گزارشات مختلف در قالب لیست‌ها ، نمودارها و ... در آنها می‌باشد.یک نرم افزار خوب باید توانایی ارائه گزارشات خوب و زیبا را نیز داشته باشد.گزارشات در حقیقت نمایشی از داده‌ها هستند که عموما به چاپ می‌رسند. مورد دیگری که در خصوص گزارشات حائز اهمیت می‌باشد ، تبدیل آنها به فرمت‌های مختلف جهت حمل و جابه جایی آسان از سیستمی به سیستم دیگر می‌باشد. برای مثال تبدیل گزارشات به قالب Pdf مزایایی بسیاری از نظر قابل حمل بودن در پی خواهد داشت. در برنامه نویسی دات نت گزارشات را می‌توان توسط دستورات چاپ در دات تهیه ، نمایش و چاپ نمود. اما تهیه گزارش توسط دستورات دات نت کاری مشکل و طاقت فرسا می‌باشد. همچنین امکان تبدیل این گزارشات به فرمت‌های دیگر نظیر Pdf ، به راحتی انجام نمی‌شود و باید از کلاس‌ها و ابزارهای جانبی که برای این کار تهیه شده اند استفاده نمود . از این رو ابزارهای مختلفی در جهت تهیه گزارشات به وجود آمدند.ابزارهایی نظیر :

• Crystal Report
• Stimul Report
• Telerik Reporting
• … 

در ادامه این سری آموزش‌ها قصد داریم Telerik Reporting و نحوه تهیه گزارش با آن را مورد بررسی قرار دهیم. این ابزار امکانات بسیاری در خصوص تهیه گزارش برنامه‌های دات نتی نظیر Windows Form ، Asp.net و ... در اختیار ما قرار می‌دهد.در ادامه و برای شروع ، ساخت یک گزارش ساده در این محیط را بررسی میکنیم.

 
 نکته : گزارشاتی که توسط Telerik Reporting تهیه می‌شوند به وسیله کدهای C# جنریت می‌شوند.بنابراین همیشه توصیه می‌شود گزارشات خود را درون یک یا چند پروژه Class Library قرار دهیم و از این پس ، این گزارشات از درون پروژه‌های دیگر (ویندوزی ، وب و ...) در دسترس هستند.کافی ست پروژه Class Library را به عنوان Reference به پروژه مورد نظر خود اضافه کنیم..  برای شروع می‌توان یک پروژه جدید  از نوع Class Library  ایجاد کرد.پس از آن روی نام پروژه راست کلیک کنید و گزینه Telerik Report را انتخاب نمایید.پس از تعیین نام گزارش کلید Ok را کلیک نمایید.

انتخاب گزینه Telerik Reporting از پنجره New Item


در این حالت فایل گزارش به پروژه افزوده می‌شود. در ادامه می‌توانید توسط ویزاردی که نمایش داده می‌شود کارهای عمومی مربوط به پیاده سازی گزارش (انتخاب منبع داده(Data Source) ، ساخت Query جهت بارگذاری اطلاعات ، فیلدهایی که باید نمایش داده شوند ، گروه بندی داده‌ها و ...) را توسط این ویزارد انجام دهید. برای اینکار در پنجره ای که نمایش داده می‌شود بر روی کلید Next کلیک نمایید.
جهت ایجاد یک گزارش جدید در پنجره  Report Choose Page گزینه New Report را انتخاب نموده و کلید Next را کلیک نمایید.
جهت انتخاب منبع داده گزارش در پنجره Choose Data Source گزینه Add New Data Source را انتخاب نمایید.در این حالت می‌توانید گزینه‌های متفاوتی را به عنوان منبع داده گزارش خود انتخاب نمایید. گزینه‌های نمایش داده شده به شرح ذیل است:
• Sql Data Source : جهت اتصال مستقیم به بانک اطلاعات Microsoft Sql Server
• Object Data Source :  جهت اتصال به کلاس‌های لایه Business و بارگذاری داده از این کلاس ها
• Entity Data Source : جهت اتصال به  Entity Framework
• Open Access Data Source : جهت اتصال به Open Access ORM ساخت شرکت Telerik
• Cube Data Source : جهت اتصال و نمایش داده‌های تحلیل شده
  در ادامه برای اینکه بتوان مستقیما به Sql Server وصل شد و Query‌های مربوط به گزارش را روی آن اجرا نمود؛ می‌توان گزینه Sql Data Source را انتخاب نمود و بر روی کلید Ok کلیک کرد.سپس در پنجره Choose Your Data Connection گزینه New Connection را کلیک کنید و یک اتصال به بانک مورد نظر خود ایجاد کنید.پس ایجاد و تست Connection ساخته شده روی Next  کلیک کنید.در پنجره Save the connection string می‌توان نامی را جهت Connection string انتخاب کرد تا Connection string با همان نام در فایل Config پروژه ذخیره شود.در ادامه کلید Next را کلیک کرده و وارد مرحله بعد شوید. در پنجره Configure Data Source Command گزینه Query Builder را جهت ساخت Query مورد نظر برای بارگذاری داده‌ها انتخاب نمایید.

انتخاب جداول جهت ساخت Query


پنجره ساخت Query

پس از ساخت Query مورد نظر کلید Ok را کلیک نمایید. در پنجره Configure Data Source Command کوئری ساخته شده به شما نمایش داده می‌شود.کلید Next را کلیک کنید. 

سپس وارد مرحله Preview Data Source Result می‌شوید که در آن قادر خواهید بود پیش نمایشی از داده هایی که بعدا توسط Query ساخته شده بارگذاری خواهند شد را مشاهده نمایید. Next را کلیک نموده تا وارد مرحله بعد شوید.مرحله بعد Standard Report Type می‌باشد که در این مرحله شما می‌توانید نوع گزارش خود را انتخاب نمایید و کلید Next را فشار دهید.در بخش Design Data Layout چند فیلد را از بخش سمت چپ (Available Fields) انتخاب نموده و کلید Details را کلیک نمایید.فیلدهای انتخاب شده به بخش Details گزارش اضافه خواهند شد.در ادامه Next را کلیک کنید تا وارد بخش Choose Report Layout شوید.شما می‌توانید در این بخش یک حالت نمایشی را برای گزارش خود انتخاب نمایید و Next را کلیک نمایید.در بخش Choose Report Style یک قالب بندی جهت گزارش خود انتخاب نمایید.در ادامه Next و سپس Finish را کلیک نمایید.کدهای گزارش Generate شده می‌توان در قسمت Designer گزارش را مشاهده نمود. 

در این حالت کارهای زیر توسط Wizard به صورت اتوماتیک انجام خواهد شد:
• بایند شدن اتوماتیک فیلدهای گزارش به ستوان‌های مرتبط
• اعمال قالب بندی انتخاب شده برای صفحه و سر ستونها
• افزودن تاریخ و شماره صفحه به پایین گزارش
در ادامه پروژه را Rebuild کرده و گزینه Preview را در Designer جهت نمایش ، پیش نمایش گزارش کلیک نمایید.

نکته : در هر برنامه‌ی گزارش سازی بخش Designer گزارش به 4 بخش کلی تقسیم می‌شود:
•  Report Header: مواردی که در این بخش از گزارش قرار میگیرند در بالای صفحه اول گزارش نمایش داده می‌شوند.
•  Page Header: مواردی که در این بخش از گزارش قرار میگیرند در بالای همه صفحات گزارش قرار گرفته و تکرار می‌شوند.
•  Details: داده‌های اصلی گزارش که شامل جزئیات و بخش اصلی گزارش می‌باشند و سطر به سطر نیز تکرار می‌شوند در این بخش قرار می‌گیرند.
•  Page Footer: مواردی که در این بخش از گزارش قرار میگیرند در پایین همه صفحات نمایش داده می‌شوند.
•  Report Footer:مواردی که در این بخش قرار می‌گیرند در پایین صفحه آخر گزارش نمایش داده می‌شوند.  

ادامه دارد ...
نظرات اشتراک‌ها
آیا یک توسعه دهنده‌ی وب می‌تواند یک طراح وب هم باشد؟
به نظر تعبیر عبارت "طراح وب"  طی سال‌های اخیر دست خوش تغییراتی شده است و امروزه برای بسیاری از ما بخوبی روشن و واضح نیست.
من معتقدم برداشت شما از عبارت طراح وب در مطلب فوق، باید به دو شکل مجزا و متمایز تعریف شود. اول طراح گرافیک و دوم طراحی رابط کاربری. در طراحی گرافیک هنر و شناخت مخاطب در خلق یک اثر هنری حرف اول و آخر را می‌زند. لطفاً توجه داشته باشید که عبارت شناخت به مسائل مختلفی اشاره دارد. دوم، طراح رابط کاربری. طراحی رابط کاربری موضوع بسیار حساسی است. در یک طراحی رابط کاربری کمتر صحبت از خلق یک اثر هنری است. من معتقدم آن دوران که از وب سایت به عنوان ارائه و تبلیغات استفاده می‌شد رو به پایان است. در واقع این نوع نگرش به وب سایت موجب استفاده حداقلی از ظرفیت آن است.
لذا امروزه شاهد این داستان هستیم که ضمن خلاقیت، بیشتر تمرکز طراحان وب (برنامه‌های کاربردی وب و وب سایت ها) بروی کاربرد پذیری و رقم زدن تجربه مناسبی برای کاربر از کار کردن با برنامه است. در این راستا رابط گرافیکی کاربر تنها بخش کوچکی از فاکتورهایی است که تجارب کاربری را شکل می‌دهد.
من منکر بحث خلاقیت و هنر نیستم اما باید پذیرفت که ما تابع قدرت‌های برتر اینترنت هستیم. برای مثال اگر کاربری بطور روزانه ساعت‌های زیادی را در سرویس‌های متعدد سایت گوگل می‌گذراند و یا بخشی از زندگی اجتماعی خود را در توییتر و فیس بوک سپری می‌کند، چیزی را تجربه می‌کند که ما باید تابع آن باشیم. 
زمانی که شما برنامه ای را برای مشتری آماده می‌کنید درخواست‌های حداقلی او مربوط به همین تجارب روزانه اش است.  نقش Framework هایی مانند Bootstrap در اینجا نمایان می‌شود. در حقیقت Framework ی با عنوان Bootstrap سعی دارد تا تجارب کاربری افراد را تکرار کند و بهبود بخشد.
بنابراین اینگونه نتیجه می‌گیریم که یک توسعه دهنده برنامه‌های تحت وب بهتر است تا توانمندی‌های خود را در خلق یک تجربه کاربری مناسب بهبود بخشد. در این راستا Framework هایی مانند Bootstrap کمک می‌کند تا ضمن حفظ استانداردها به یک طراحی منعطف رسید که امکانات حداقلی سایت‌ها و سرویس دهنده‌های مطرح اینترنت را فراهم می‌کند.
حال اگر بحث طراحی یک وب سایت شکیل و سرشار از خلاقیت است باید از یک طراح گرافیست کمک گرفت که در حوزه وب و نرم افزار فعال باشد. برای مثال اگر حمل بر تبلیغ نشود آقای مصطفی مقدم + یکی از طراحان گرافیکی است که ضمن اشراف کامل به خلق یک اثر هنری و تأثیرگذار، به ASP.NET هم اشراف دارند. وجود چنین فردی در تیم توسعه نرم افزار و استفاده هم زمان از Framework Bootstrap به ایجاد یک ادبیات مشترک بین برنامه نویس و طراح منجر خواهد شد که در نهایت برنامه ای منعطف و مطابق با استاندارد‌های جهانی وب را منتج خواهد شد.
خوب است در تمام علوم مطالعه داشته باشیم اما در علومی باید تخصص کسب کرد. مطالعه و تقویت یک توانمندی خوب است اما معنای تخصص را نمی‌دهد. اخیراً شاهد این امر هستیم که دوستانی بدون حتی یک پروژه عملی قابل قبول در جایگاهی قرار دارند که همایش‌های معتبر جهانی را  در این حوزه در ایران برگزار می‌کنند. من مخالف این همایش‌ها نیستم اما بهتر است به تخصص‌ها احترام بگزاریم و صرفاً بدلیل مطالعه 2 کتاب و چند مقاله ادعای تخصص در علومی نکنیم، آن هم تا جایی که ...
امیدوارم مفید واقع شود.