A 9-Hour Go Course for Beginners
⭐️ Contents ⭐️
(0:00:00) Intro
(0:03:17) Ch 1. Why write Go?
(0:27:39) Ch 2. Variables
(0:51:11) Ch 3. Functions
(1:16:58) Ch 4. Structs
(1:34:36) Ch 5. Interfaces
(2:00:26) Ch 6. Errors
(2:22:01) Ch 7. Loops
(2:48:21) Ch 8. Slices
(3:39:54) Ch 9. Maps
(4:06:19) Ch 10. Advanced functions
(4:31:03) Ch 11. Pointers
(4:48:02) Ch 12. Local development
(5:31:43) Ch 13. Channels & concurrency
(6:07:38) Ch 14. Mutexes
(6:30:56) Ch 15. Generics
(6:38:38) Ch 16. Quiz
(6:43:13) P1. RSS aggregator project
(6:53:43) P2. Chi router
(7:11:37) P3. Postgres database
(7:39:10) P4. Authentication w/ API keys
(8:18:28) P5. Many to many relationships
(8:39:13) P6. Aggregation worker
(9:05:28) P7. Viewing blog posts
protected void Application_Start(object sender, EventArgs e) { Interface1 myTask = new HelloSchedule(); myTask.Run(); }
Message from HelloJob 6/19/2014 10:40:15 AM Message from HelloJob 6/19/2014 10:40:25 AM Message from HelloJob 6/19/2014 10:40:35 AM Message from HelloJob 6/19/2014 10:40:45 AM Message from HelloJob 6/19/2014 10:40:55 AM Message from HelloJob 6/19/2014 11:24:36 AM Message from HelloJob 6/19/2014 11:24:45 AM Message from HelloJob 6/19/2014 11:24:55 AM
ولی هدف من از اعمال زمانبندی اینه که بی نهایت بار وظیفه اجرا بشه، به طور مثال در یک سایت آگهی شبیه ایستگاه، مثلاً دو روز قبل از انقضای آگهی به فرد اطلاع داده بشه که آگهی شما داره منقضی میشه.
البته من در لوکال تست کردم.
من بهتر از
Application_Start
لطفاً راهنمایی کنید.
متدی برای بررسی صحت کد ملی وارد شده
من از یک مبدل آنلاین استفاده کردم به این نتیجه رسیدم.
Namespace ConsoleApplicationTest Class Program Private Shared Sub Main(args As String()) Console.WriteLine("0172942284 => {0}", "0172942284".IsValidNationalCode()) Console.WriteLine("1000000001 => {0}", "1000000001".IsValidNationalCode()) End Sub End Class Public NotInheritable Class Helpers Private Sub New() End Sub <System.Runtime.CompilerServices.Extension> _ Public Shared Function IsValidNationalCode(nationalCode As [String]) As [Boolean] If [String].IsNullOrEmpty(nationalCode) Then Throw New Exception("لطفا کد ملی را صحیح وارد نمایید") End If If nationalCode.Length <> 10 Then Throw New Exception("طول کد ملی باید ده کاراکتر باشد") End If Dim regex__1 = New Regex("[^0-9]<span> </span>") If Not regex__1.IsMatch(nationalCode) Then Throw New Exception("کد ملی تشکیل شده از ده رقم عددی میباشد؛ لطفا کد ملی را صحیح وارد نمایید") End If If Not Regex.IsMatch(nationalCode, "^(?!(\d)\1{9})\d{10}$") Then Return False End If Dim check = Convert.ToInt32(nationalCode.Substring(9, 1)) Dim result = Enumerable.Range(0, 9).[Select](Function(x) Convert.ToInt32(nationalCode.Substring(x, 1)) * (10 - x)).Sum() Mod 11 Dim remainder As Integer = result Mod 11 Return check = (If(remainder < 2, remainder, 11 - remainder)) End Function End Class End Namespace
متدی برای بررسی صحت کد ملی وارد شده
namespace ConsoleApplicationTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("0172942284 => {0}", "0172942284".IsValidNationalCode());
Console.WriteLine("1000000001 => {0}", "1000000001".IsValidNationalCode());
}
}
public static class Helpers
{
public static Boolean IsValidNationalCode(this String nationalCode)
{
if (String.IsNullOrEmpty(nationalCode))
throw new Exception("لطفا کد ملی را صحیح وارد نمایید");
if (nationalCode.Length != 10)
throw new Exception("طول کد ملی باید ده کاراکتر باشد");
var regex = new Regex(@"[^0-9] ");
if (!regex.IsMatch(nationalCode))
throw new Exception("کد ملی تشکیل شده از ده رقم عددی میباشد؛ لطفا کد ملی را صحیح وارد نمایید");
if (!Regex.IsMatch(nationalCode, @"^(?!(\d)\1{9})\d{10}$"))
return false;
var check = Convert.ToInt32(nationalCode.Substring(9, 1));
var result = Enumerable.Range(0, 9)
.Select(x => Convert.ToInt32(nationalCode.Substring(x, 1)) * (10 - x))
.Sum() % 11;
int remainder = result % 11;
return check == (remainder < 2 ? remainder : 11 - remainder);
}
}
}
پ.ن. لازم به ذکر است از کدهای اقای بیاگوی استفاده شده است.
سیستم ASP.NET Membership بهمراه ASP.NET 2.0 در سال 2005 معرفی شد، و از آن زمان تا بحال تغییرات زیادی در چگونگی مدیریت احزار هویت و اختیارات کاربران توسط اپلیکیشنهای وب بوجود آمده است. ASP.NET Identity نگاهی تازه است به آنچه که سیستم Membership هنگام تولید اپلیکیشنهای مدرن برای وب، موبایل و تبلت باید باشد.
پیش زمینه: سیستم عضویت در ASP.NET
- الگوی پایگاه داده آن برای SQL Server طراحی شده است، و قادر به تغییرش هم نیستید. میتوانید اطلاعات پروفایل را اضافه کنید، اما تمام دادهها در یک جدول دیگر ذخیره میشوند، که دسترسی به آنها نیز مشکلتر است، تنها راه دسترسی Profile Provider API خواهد بود.
- سیستم تامین کننده (Provider System) امکان تغییر منبع دادهها را به شما میدهد، مثلا میتوانید از بانکهای اطلاعاتی MySQL یا Oracle استفاده کنید. اما تمام سیستم بر اساس پیش فرض هایی طراحی شده است که تنها برای بانکهای اطلاعاتی relational درست هستند. میتوانید تامین کننده (Provider) ای بنویسید که دادههای سیستم عضویت را در منبعی به غیر از دیتابیسهای relational ذخیره میکند؛ مثلا Windows Azure Storage Tables. اما در این صورت باید مقادیر زیادی کد بنویسید. مقادیر زیادی هم System.NotImplementedException باید بنویسید، برای متد هایی که به دیتابیسهای NoSQL مربوط نیستند.
- از آنجایی که سیستم ورود/خروج سایت بر اساس مدل Forms Authentication کار میکند، سیستم عضویت نمیتواند از OWIN استفاده کند. OWIN شامل کامپوننت هایی برای احراز هویت است که شامل سرویسهای خارجی هم میشود (مانند Microsoft Accounts, Facebook, Google, Twitter). همچنین امکان ورود به سیستم توسط حسابهای کاربری سازمانی (Organizational Accounts) نیز وجود دارد مانند Active Directory و Windows Azure Active Directory. این کتابخانه از OAuth 2.0، JWT و CORS نیز پشتیبانی میکند.
- ذخیره دادههای سیستم عضویت در بانکهای اطلاعاتی non-relational مشکل است.
- نمی توانید از آن در کنار OWIN استفاده کنید.
- با فراهم کنندههای موجود ASP.NET Membership بخوبی کار نمیکند. توسعه پذیر هم نیست.
ASP.NET Universal Providers
ASP.NET Universal Providers برای ذخیره سازی اطلاعات سیستم عضویت در Windows Azure SQL Database توسعه پیدا کردند. با SQL Server Compact هم بخوبی کار میکنند. این تامین کنندهها بر اساس Entity Framework Code First ساخته شده بودند و بدین معنا بود که دادههای سیستم عضویت را میتوان در هر منبع داده ای که توسط EF پشتیبانی میشود ذخیره کرد. با انتشار این تامین کنندهها الگوی دیتابیس سیستم عضویت نیز بسیار سبکتر و بهتر شد. اما این سیستم بر پایه زیر ساخت ASP.NET Membership نوشته شده است، بنابراین محدودیتهای پیشین مانند محدودیتهای SqlMembershipProvider هنوز وجود دارند. به بیان دیگر، این سیستمها همچنان برای بانکهای اطلاعاتی relational طراحی شده اند، پس سفارشی سازی اطلاعات کاربران و پروفایلها هنوز مشکل است. در آخر آنکه این تامین کنندهها هنوز از مدل احراز هویت فرم استفاده میکنند.
ASP.NET Identity
- یک سیستم هویت واحد (One ASP.NET Identity system)
- سیستم ASP.NET Identity میتواند در تمام فریم ورکهای مشتق از ASP.NET استفاده شود. مانند ASP.NET MVC, Web Forms, Web Pages, Web API و SignalR
- از این سیستم میتوانید در تولید اپلیکیشنهای وب، موبایل، استور (Store) و یا اپلیکیشنهای ترکیبی استفاده کنید.
- سادگی تزریق دادههای پروفایل درباره کاربران
- روی الگوی دیتابیس برای اطلاعات کاربران و پروفایلها کنترل کامل دارید. مثلا میتوانید به سادگی یک فیلد، برای تاریخ تولد در نظر بگیرید که کاربران هنگام ثبت نام در سایت باید آن را وارد کنند.
- کنترل ذخیره سازی/واکشی اطلاعات
- بصورت پیش فرض ASP.NET Identity تمام اطلاعات کاربران را در یک دیتابیس ذخیره میکند. تمام مکانیزمهای دسترسی به دادهها توسط EF Code First کار میکنند.
- از آنجا که روی الگوی دیتابیس، کنترل کامل دارید، تغییر نام جداول و یا نوع داده فیلدهای کلیدی و غیره ساده است.
- استفاده از مکانیزمهای دیگر برای مدیریت دادههای آن ساده است، مانند SharePoint, Windows Azure Storage Table و دیتابیسهای NoSQL.
- تست پذیری
- ASP.NET Identity تست پذیری اپلیکیشن وب شما را بیشتر میکند. میتوانید برای تمام قسمت هایی که از ASP.NET Identity استفاده میکنند تست بنویسید.
- تامین کننده نقش (Role Provider)
- تامین کننده ای وجود دارد که به شما امکان محدود کردن سطوح دسترسی بر اساس نقوش را میدهد. بسادگی میتوانید نقشهای جدید مانند "Admin" بسازید و بخشهای مختلف اپلیکیشن خود را محدود کنید.
- Claims Based
- ASP.NET Identity از امکان احراز هویت بر اساس Claims نیز پشتیبانی میکند. در این مدل، هویت کاربر بر اساس دسته ای از اختیارات او شناسایی میشود. با استفاده از این روش توسعه دهندگان برای تعریف هویت کاربران، آزادی عمل بیشتری نسبت به مدل Roles دارند. مدل نقشها تنها یک مقدار منطقی (bool) است؛ یا عضو یک نقش هستید یا خیر، در حالیکه با استفاده از روش Claims میتوانید اطلاعات بسیار ریز و دقیقی از هویت کاربر در دست داشته باشید.
- تامین کنندگان اجتماعی
- به راحتی میتوانید از تامین کنندگان دیگری مانند Microsoft, Facebook, Twitter, Google و غیره استفاده کنید و اطلاعات مربوط به کاربران را در اپلیکیشن خود ذخیره کنید.
- Windows Azure Active Directory
- برای اطلاعات بیشتر به این لینک مراجعه کنید.
- یکپارچگی با OWIN
- ASP.NET Identity بر اساس OWIN توسعه پیدا کرده است، بنابراین از هر میزبانی که از OWIN پشتیبانی میکند میتوانید استفاده کنید. همچنین هیچ وابستگی ای به System.Web وجود ندارد. ASP.NET Identity یک فریم ورک کامل و مستقل برای OWIN است و میتواند در هر اپلیکیشنی که روی OWIN میزبانی شده استفاده شود.
- ASP.NET Identity از OWIN برای ورود/خروج کاربران در سایت استفاده میکند. این بدین معنا است که بجای استفاده از Forms Authentication برای تولید یک کوکی، از OWIN CookieAuthentication استفاده میشود.
- پکیج NuGet
- ASP.NET Identity در قالب یک بسته NuGet توزیع میشود. این بسته در قالب پروژههای ASP.NET MVC, Web Forms و Web API که با Visual Studio 2013 منتشر شدند گنجانده شده است.
- توزیع این فریم ورک در قالب یک بسته NuGet این امکان را به تیم ASP.NET میدهد تا امکانات جدیدی توسعه دهند، باگها را برطرف کنند و نتیجه را بصورت چابک به توسعه دهندگان عرضه کنند.
ASP.NET Identity در قالب پروژههای ASP.NET MVC, Web Forms, Web API و SPA که بهمراه Visual Studio 2013 منتشر شده اند استفاده میشود. در ادامه به اختصار خواهیم دید که چگونه ASP.NET Identity کار میکند.
- یک پروژه جدید ASP.NET MVC با تنظیمات Individual User Accounts بسازید.
-
پروژه ایجاد شده شامل سه بسته میشود که مربوط به ASP.NET Identity هستند:
- Microsoft.AspNet.Identity.EntityFramework این بسته شامل پیاده سازی ASP.NET Identity با Entity Framework میشود، که تمام دادههای مربوطه را در یک دیتابیس SQL Server ذخیره میکند.
- Microsoft.AspNet.Identity.Core این بسته محتوی تمام interfaceهای ASP.NET Identity است. با استفاده از این بسته میتوانید پیاده سازی دیگری از ASP.NET Identity بسازید که منبع داده متفاوتی را هدف قرار میدهد. مثلا Windows Azure Storage Table و دیتابیسهای NoSQL.
- Microsoft.AspNet.Identity.OWIN این بسته امکان استفاده از احراز هویت OWIN را در اپلیکیشنهای ASP.NET فراهم میکند. هنگام تولید کوکیها از OWIN Cookie Authentication استفاده خواهد شد.
هنگامیکه بر روی دکمهی Register کلیک شود، کنترلر Account، اکشن متد Register را فراخوانی میکند تا حساب کاربری جدیدی با استفاده از ASP.NET Identity API ساخته شود.
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser() { UserName = model.UserName }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { await SignInAsync(user, isPersistent: false); return RedirectToAction("Index", "Home"); } else { AddErrors(result); } } // If we got this far, something failed, redisplay form return View(model); }
اگر حساب کاربری با موفقیت ایجاد شود، کاربر توسط فراخوانی متد SignInAsync به سایت وارد میشود.
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser() { UserName = model.UserName }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { await SignInAsync(user, isPersistent: false); return RedirectToAction("Index", "Home"); } else { AddErrors(result); } } // If we got this far, something failed, redisplay form return View(model); }
private async Task SignInAsync(ApplicationUser user, bool isPersistent) { AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); var identity = await UserManager.CreateIdentityAsync( user, DefaultAuthenticationTypes.ApplicationCookie); AuthenticationManager.SignIn( new AuthenticationProperties() { IsPersistent = isPersistent }, identity); }
از آنجا که ASP.NET Identity و OWIN Cookie Authentication هر دو Claims-based هستند، فریم ورک، انتظار آبجکتی از نوع ClaimsIdentity را خواهد داشت. این آبجکت تمامی اطلاعات لازم برای تشخیص هویت کاربر را در بر دارد. مثلا اینکه کاربر مورد نظر به چه نقش هایی تعلق دارد؟ و اطلاعاتی از این قبیل. در این مرحله میتوانید Claimهای بیشتری را به کاربر بیافزایید.
کلیک کردن روی لینک Log off در سایت، اکشن متد LogOff در کنترلر Account را اجرا میکند.
// POST: /Account/LogOff [HttpPost] [ValidateAntiForgeryToken] public ActionResult LogOff() { AuthenticationManager.SignOut(); return RedirectToAction("Index", "Home"); }
همانطور که مشاهده میکنید برای ورود/خروج کاربران از AuthenticationManager استفاده میشود که متعلق به OWIN است. متد SignOut همتای متد FormsAuthentication.SignOut است.
کامپوننتهای ASP.NET Identity
تصویر زیر اجزای تشکیل دهنده ASP.NET Identity را نمایش میدهد. بسته هایی که با رنگ سبز نشان داده شده اند سیستم کلی ASP.NET Identity را میسازند. مابقی بستهها وابستگی هایی هستند که برای استفاده از ASP.NET Identity در اپلیکیشنهای ASP.NET لازم اند.
دو پکیج دیگر نیز وجود دارند که به آنها اشاره نشد:
- Microsoft.Security.Owin.Cookies این بسته امکان استفاده از مدل احراز هویت مبتنی بر کوکی (Cookie-based Authentication) را فراهم میکند. مدلی مانند سیستم ASP.NET Forms Authentication.
- EntityFramework که نیازی به معرفی ندارد.
مهاجرت از Membership به ASP.NET Identity
قدمهای بعدی
آغاز سادهتر مجموعهها با کمک Collection Expressions
تا پیش از C# 12 برای آغاز یک آرایه میتوان از روش زیر استفاده کرد که در آن نوع آرایه از طریق نوع اعضای آن حدس زده میشود:
var numbers1_CS11 = new[] { 1, 2, 3 };
var numbers1_CS_11 = new int[] { 1, 2, 3 };
int[] numbers1_CS12 = [ 1, 2, 3 ];
error CS9176: There is no target type for the collection expression.
یک collection expression و یا collection literals، به مجموعهای از عناصر گفته میشود که بین دو براکت [] قرار میگیرند.
نمونهی دیگر آن کار با Spanها است که نمونه کد C# 11 آن:
Span<string> span1_CS11 = new string[] { "AC", "AL" };
Span<string> span1_CS12 = [ "AC", "AL" ];
ReadOnlySpan<string> readOnlySpan_CS12 = [ "Africa", "Asia", "Europa"];
مثال دیگر، نحوهی آغاز آرایههای چندبعدی است:
int[][] array2D_CS11 = { new int[] { 2002, 2006, 2010}, new int[] { 2014, 2018}, new int[] { 2022, 2026, 2030} };
int[][] array2D_CS12 = [ [2002, 2006, 2010], [2014, 2018], [2022, 2026, 2030] ];
و یا حتی این مورد را در مورد نحوهی آغاز Listهای پیش از C#12
List<string> list_CS11 = new List<string> { "Item 1", "Item 2" };
List<string> list_CS12 = [ "Item 1", "Item 2" ];
در کل همانطور که مشاهده میکنید، این تغییر، تغییر مثبتی است و حجم قابل ملاحظهای از کدها را کاهش داده و خواندن آنها را نیز سادهتر میکند.
یک نکته: روش ساده شدهی آغاز یک لیست با مجموعهای خالی در C# 12 به صورت زیر است:
// Before C#12 List<User> users = new List<User>(); // or var users = new List<User>(); // or List<User> user = new(); // C#12 List<User> users = [];
اضافه شدن spread operator به زبان #C
اگر پیشتر با زبان JavaScript کار کرده باشید، با spread operator هم آشنایی دارید. کار آن ساده سازی یکی کردن مجموعهها و یا افزودن سادهتر عناصری به آنها است و .. بالاخره به زبان #C هم راه پیدا کردهاست! برای مثال دو آرایهی زیر را درنظر بگیرید:
int[] numbers1_CS12 = [ 1, 2, 3 ]; int[] numbers2_CS12 = [ 4, 5, 6 ];
int[] allItems = [ ..numbers1_CS12, ..numbers2_CS12 ];
اگر در نگارشهای قبلی #C بخواهیم چنین کاری را انجام دهیم، یک روش آن به صورت زیر است:
int[] allItems_CS11 = numbers1_CS12.Concat(numbers2_CS12).ToArray();
همچنین اپراتور پخش کردن، قابلیت قرارگرفتن در کنار سایر اعضای یک آرایه را هم به سادگی و با خوانایی بیشتری به همراه دارد:
int[] join = [..a, ..b, ..c, 6, 5];
به علاوه محدودیتی در مورد نوع مجموعهی بکار گرفته شده نیز در اینجا وجود ندارد. برای نمونه در مثال زیر، یک آرایه، یک Span و یک لیست، با هم یکی شدهاند:
int[] a =[1, 2, 3]; Span<int> b = [2, 4, 5, 4, 4]; List<int> c = [4, 6, 6, 5]; List<int> join = [..a, ..b, ..c, 6, 5];
و مثالی دیگر، نحوهی سادهی تعریف لیستی از tuples است:
List<(string, int)> otherScores = [("Dave", 90), ("Bob", 80)];
(string name, int score)[] scores = [("Alice", 90), ..otherScores, ("Charlie", 70)];
فرض کنید اطلاعات حضور و غیاب کارمندان را به نحو زیر در اختیار دارید:
namespace PdfReportSamples.Models { public class UserWorkedHours { public int Id { set; get; } public string Name { set; get; } public int DayNumber { set; get; } public int Month { set; get; } public int Year { set; get; } public string Description { set; get; } } }
private static List<UserWorkedHours> createUsersWorkedHours() { var usersWorkedHours = new List<UserWorkedHours>(); for (int i = 1; i < 11; i++) { for (int j = 1; j < 28; j++) { usersWorkedHours.Add(new UserWorkedHours { Id = i, Name = "کارمند " + i, Year = 1391, // سال و ماه بر اساس نوع تقویم انتخابی مشخص میشود Month = i, DayNumber = j, Description = i % 2 == 0 ? "05:00" : "08:00" }); } } return usersWorkedHours; }
سلولی که قرار است قالب MonthCalendar را نمایش دهد نیاز به شیءایی از نوع PdfRpt.Calendar.CalendarData دارد که به نحو زیر تعریف شده است:
using System.Collections.Generic; namespace PdfRpt.Calendar { public class CalendarData { public int Month { set; get; } public int Year { set; get; } public IList<DayInfo> MonthDaysInfo { set; get; } } }
namespace PdfRpt.Calendar { public class DayInfo { public int DayNumber { set; get; } public int Month { set; get; } public int Year { set; get; } public string Description { set; get; } public bool ShowDescriptionInFooter { set; get; } } }
اکنون نیاز است تا اطلاعات منبع داده خود را به CalendarData نگاشت کنیم تا بتوان از آن در قالب سلول جدید MonthCalendar استفاده کرد. انجام اینکار با استفاده از امکانات LINQ به نحو زیر است:
public static IList<UserMonthCalendar> CreateDataSource() { var usersWorkedHours = createUsersWorkedHours(); // Mapping a list of normal Users WorkedHours to a list of Users + CalendarData return usersWorkedHours .GroupBy(x => new { Id = x.Id, Name = x.Name }) .Select( x => new UserMonthCalendar { Id = x.Key.Id, Name = x.Key.Name, // Calendar's cell data type should be PdfRpt.Calendar.CalendarData MonthCalendarData = new CalendarData { Year = x.First().Year, Month = x.First().Month, MonthDaysInfo = x.ToList().Select(y => new DayInfo { Description = y.Description, ShowDescriptionInFooter = false, DayNumber = y.DayNumber }).ToList() } }).ToList(); }
using PdfRpt.Calendar; namespace PdfReportSamples.Models { public class UserMonthCalendar { public int Id { set; get; } public string Name { set; get; } // Calendar's cell data type should be CalendarData public CalendarData MonthCalendarData { set; get; } } }
برای نمایش این اطلاعات توسط PdfReport، دو ستون اول یاد شده نکته خاصی ندارند، اما نحوه تعریف ستون تقویم ماهیانه آن به صورت زیر خواهد بود:
columns.AddColumn(column => { // Calendar's cell data type should be PdfRpt.Calendar.CalendarData column.PropertyName<UserMonthCalendar>(x => x.MonthCalendarData); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(3); column.Width(3); column.HeaderCell("تقویم ماهیانه"); column.ColumnItemsTemplate(itemsTemplate => { itemsTemplate.MonthCalendar(new CalendarAttributes { CalendarType = CalendarType.PersianCalendar, UseLongDayNamesOfWeek = true, Padding = 3, DescriptionHorizontalAlignment = HorizontalAlignment.Center, SplitRows = true, CellsCustomizer = info => { if (info.Year == 1391 && info.Month == 1 && info.DayNumber == 1) { info.NumberCell.BackgroundColor = new BaseColor(System.Drawing.Color.LimeGreen); var phrase = info.NumberCell.Phrase; foreach (var chunk in phrase.Chunks) chunk.Font.Color = new BaseColor(System.Drawing.Color.Yellow); } } }); }); });
ListBox
در مورد لیست، ما قبلا نام کشورها را با استفاده از تگ ListBoxItem به طور دستی اضافه میکردیم و هر گونه ویرایش و اضافه کردن عکس و دیگر اشیاء را داخل این تگ برای هر آیتم جداگانه انجام میدادیم؛ مثل تصویر زیر که هر آیتم شامل یک تگ تصویر و دو تگ TextBlock است که یکی از آنها رنگی شده است. کد هر آیتم به طور جداگانه و دستی اضافه شده است.
<ListBox Grid.Row="3" Name="MyListBox" Grid.Column="1" Margin="10" Height="80" > <ListBox.ItemTemplate> <DataTemplate> <WrapPanel> <Image Width="24" Height="24" Source="{Binding Flag}"></Image> <TextBlock Padding="5 5 0 0" Text="{Binding Name}"></TextBlock> </WrapPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
ارائه این نکته ضروری است که همه اشیاء خصوصیت DataContext را دارند و ما در مثال قبلی DataContext ریشه یا والد اشیاء را پر کردیم. اگر مقاله "ساختار سلسله مراتبی " را به یاد بیاورید، گفتیم که هر شیء در صورتیکه خصوصیت وابستهای برایش تعریف نشده باشد، به سمت اشیاء والد حرکت میکند، به این جهت بود که همهی کنترلها به منبع دادهها دسترسی داشتند. پس ما اگر DataContext لیست را پر کنیم، لیست دلیلی برای دسترسی به DataContext اشیاء والد ندارد و خصوصیت پر شدهی خودش را در نظر میگیرد. پس بیایید این مورد را امتحان کنیم:
من کلاس زیر را جهت ارسال لیستی از کشورها به همراه آدرس پرچمشان، بر میگردانم:
دلیل استفاده از کلاس ObservableCollection در کد زیر به جای استفاده از اشیایی چون Ilist و ... این بود که این کلاس به اینترفیس هایی چون INotifyPropertyChanged مزین گشته و هر گونه تغییری در این مجموعه، از قبیل حذف و اضافه را اطلاع رسانی کرده و مدل تغییر یافته را به سمت ویو هدایت میکند.
using System.Collections.ObjectModel; namespace test { public class Country { public string Flag { get { return "Images/flags/" + Name + ".png"; } } public string Name { get; set; } public int Id { get; set; } public ObservableCollection<Country> GetCountries() { var countries = new ObservableCollection<Country>(); countries.Add(new Country(){Id =1,Name = "Afghanistan"}); countries.Add(new Country() { Id = 2, Name = "Albania" }); countries.Add(new Country() { Id = 3, Name = "Angola" }); countries.Add(new Country() { Id = 4, Name = "Bahrain" }); countries.Add(new Country() { Id = 5, Name = "Bermuda" }); countries.Add(new Country() { Id =6, Name = "Iran" }); return countries; } } }
دلیل این مشکل این است که DataContext برای نمایش یک Object تهیه شده است و در مورد دادههای لیستی باید از خصوصیتی به نام ItemsSource استفاده کرد که برای دادههای لیستی IEnumerables، بهینه شده است.
پس به این ترتیب مینویسیم :
public MainWindow() { InitializeComponent(); person = Person.GetPerson(); DataContext = person; //خط جدید MyListBox.ItemsSource = new Country().GetCountries(); }
شکلهای زیر یک نمودار از ارتباط با Object برای واکشی داده هاست:
نمودار زیر هم دسترسی به مجموعه ای از دادههای لیستی است که از طریق ItemsSource خوانده میشوند:
کد زیر همچنین برای اتصال به کار میرود:
public MainWindow() { InitializeComponent(); person = Person.GetPerson(); DataContext = person; //خط جدید MyListBox.DataContext = new Country().GetCountries(); MyListBox.SetBinding(ItemsControl.ItemsSourceProperty, new Binding()); }
پی نوشت : روشهای دیگر بایند کردن همچون استفاده از منابع یا ریسورسها یا استفاده از ViewModelها هم هستند که در آینده در مورد آنها بیشتر صحبت خواهیم کرد.
حال که توانستیم لیست را پر کنیم باید کشوری را که در رکورد واکشی شده آمده است، در لیست انتخاب کنیم.
توجه داشته باشید که باید لیست را از طریق خصوصیت ItemsSource پر کرده باشید و DataContext را دستکاری نکرده باشید.
خصوصیت Country در کلاس Person میتواند به دو صورت زیر باشد:
public int Country { get; set; } public Country Country { get; set; }
<ListBox Grid.Row="3" Name="MyListBox" Grid.Column="1" Margin="10" Height="80" SelectedValuePath="Id" SelectedValue="{Binding Country}" > <ListBox Grid.Row="3" Name="MyListBox" Grid.Column="1" Margin="10" Height="80" SelectedValuePath="Id" SelectedValue="{Binding Country.Id}" >
خصوصیتهای دیگر یک شیء لیستی چون ListBox و ComboBox و ... SelectedIndex است که اندیس یک آیتم انتخابی را بازگردانده یا جهت انتخاب یک آیتم، اندیس آن را دریافت میکند. SelectedItem و SelectedItems هم شیء یا شیءهایی از مدل را (در اینجا Country) که در لیست انتخاب شدهاند، بر میگرداند (فقط خواندنی).
خلاصه نکات SEO
Console Debug EventSource