column.ColumnItemsTemplate(template => { template.ProgressBar(progressBarColor: Color.SkyBlue, showPercentText: true); template.DisplayFormatFormula(obj => obj == null ? string.Format("{0:P2}", 0) : string.Format("{0:P2}", obj)); }); column.AggregateFunction(aggregateFunction => { aggregateFunction.NumericAggregateFunction(AggregateFunction.Average); aggregateFunction.DisplayFormatFormula(obj => obj == null ? string.Format("{0:P2}", 0) : string.Format("{0:P2}", obj)); }); column.CalculatedField( list => { if (list == null) return string.Empty; float sumCountPercent = 0; float count = 1; foreach (var item in IndexData) { sumCountPercent += float.Parse(list.GetValueOf(item.Value).ToString()) * (count++ * 20); } float sumColumnsPercent = float.Parse(list.GetValueOf("SumColumns").ToString()) * 100; return sumCountPercent / sumColumnsPercent; });
تبدیلگر تاریخ شمسی برای AutoMapper
public class User { public int Id { set; get; } public string Name { set; get; } public DateTime RegistrationDate { set; get; } }
public class UserViewModel { public int Id { set; get; } public string Name { set; get; } public string RegistrationDate { set; get; } }
تبدیلگر سفارشی تاریخ میلادی به شمسی مخصوص AutoMapper
در ذیل یک تبدیلگر سفارشی مخصوص AutoMapper را با پیاده سازی اینترفیس ITypeConverter آن ملاحظه میکنید:
public class DateTimeToPersianDateTimeConverter : ITypeConverter<DateTime, string> { private readonly string _separator; private readonly bool _includeHourMinute; public DateTimeToPersianDateTimeConverter(string separator = "/", bool includeHourMinute = true) { _separator = separator; _includeHourMinute = includeHourMinute; } public string Convert(ResolutionContext context) { var objDateTime = context.SourceValue; return objDateTime == null ? string.Empty : toShamsiDateTime((DateTime)context.SourceValue); } private string toShamsiDateTime(DateTime info) { var year = info.Year; var month = info.Month; var day = info.Day; var persianCalendar = new PersianCalendar(); var pYear = persianCalendar.GetYear(new DateTime(year, month, day, new GregorianCalendar())); var pMonth = persianCalendar.GetMonth(new DateTime(year, month, day, new GregorianCalendar())); var pDay = persianCalendar.GetDayOfMonth(new DateTime(year, month, day, new GregorianCalendar())); return _includeHourMinute ? string.Format("{0}{1}{2}{1}{3} {4}:{5}", pYear, _separator, pMonth.ToString("00", CultureInfo.InvariantCulture), pDay.ToString("00", CultureInfo.InvariantCulture), info.Hour.ToString("00"), info.Minute.ToString("00")) : string.Format("{0}{1}{2}{1}{3}", pYear, _separator, pMonth.ToString("00", CultureInfo.InvariantCulture), pDay.ToString("00", CultureInfo.InvariantCulture)); } }
ثبت و معرفی تبدیلگرهای سفارشی AutoMapper
پس از تعریف یک تبدیلگر سفارشی AutoMapper، اکنون نیاز است آنرا به AutoMapper معرفی کنیم:
public class TestProfile1 : Profile { protected override void Configure() { // این تنظیم سراسری هست و به تمام خواص زمانی اعمال میشود this.CreateMap<DateTime, string>().ConvertUsing(new DateTimeToPersianDateTimeConverter()); this.CreateMap<User, UserViewModel>(); } public override string ProfileName { get { return this.GetType().Name; } } }
همانطور که مشاهده میکنید در اینجا دو نگاشت تعریف شدهاند. یکی برای تبدیل User به UserViewModel و دیگری، معرفی نحوهی نگاشت DateTime به string، توسط تبدیلگر سفارشی DateTimeToPersianDateTimeConverter است که به کمک متد الحاقی ConvertUsing صورت گرفتهاست.
باید دقت داشت که تنظیمات تبدیلگرهای سفارشی سراسری هستند و در کل برنامه و به تمام پروفایلها اعمال میشوند.
بررسی خروجی تبدیلگر سفارشی تاریخ
اکنون کار استفاده از تنظیمات AutoMapper با ثبت پروفایل تعریف شده آغاز میشود:
Mapper.Initialize(cfg => // In Application_Start() { cfg.AddProfile<TestProfile1>(); });
var dbUser1 = new User { Id = 1, Name = "Test", RegistrationDate = DateTime.Now.AddDays(-10) }; var uiUser = new UserViewModel(); Mapper.Map(source: dbUser1, destination: uiUser);
نوشتن تبدیلگرهای غیر سراسری
همانطور که عنوان شد، معرفی تبدیلگرها به AutoMapper سراسری است و در کل برنامه اعمال میشود. اگر نیاز است فقط برای یک مدل خاص و یک خاصیت خاص آن تبدیلگر نوشته شود، باید نگاشت مورد نظر را به صورت ذیل تعریف کرد:
this.CreateMap<User, UserViewModel>() .ForMember(userViewModel => userViewModel.RegistrationDate, opt => opt.ResolveUsing(src => { var dt = src.RegistrationDate; return dt.ToShortDateString(); }));
خصوصی سازی تبدیلگرها با تدارک موتورهای نگاشت اختصاصی
اگر میخواهید تنظیمات TestProfile1 به کل برنامه اعمال نشود، نیاز است یک MappingEngine جدید و مجزای از MappingEngine سراسری AutoMapper را ایجاد کرد:
var configurationStore = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers); configurationStore.AddProfile<TestProfile1>(); var mapper = new MappingEngine(configurationStore); mapper.Map(source: dbUser1, destination: uiUser);
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید:
AM_Sample02.zip
public class CustomerInfo { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime BirthDate { get; set; } }
public interface IModelBinder { object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext); }
using System; using System.Web; using System.Web.Mvc; using ModelBinderExample.Models; using Persia; namespace ModelBinderExample.CustomModelBinder { // Article written for www.dotnettips.info public class CustomerInfoModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { HttpRequestBase request = controllerContext.HttpContext.Request; string firstName = request.Form.Get("FirstName"); string lastName = request.Form.Get("LastName"); DateTime birthDate = this.GetMiladiDate(request); return new CustomerInfo() { FirstName = firstName, LastName = lastName, BirthDate = birthDate }; } private DateTime GetMiladiDate(HttpRequestBase request) { int day = int.Parse(request.Form.Get("Day")); int month = int.Parse(request.Form.Get("Month")); int years = int.Parse(request.Form.Get("Years")); //Convert shamsi to miladi return Persia.Calendar.ConvertToGregorian(years, month, day, DateType.Gerigorian); } } }
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); //Register New ModelBinder ModelBinders.Binders.Add(typeof(CustomerInfo), new CustomerInfoModelBinder()); }
[HttpPost] public ActionResult Create([ModelBinder(typeof (CustomerInfoModelBinder))] CustomerInfo customerInfo) { if (ModelState.IsValid) { ViewBag.FirstName = customerInfo.FirstName; ViewBag.LastName = customerInfo.LastName; ViewBag.BirthDate = customerInfo.BirthDate; } return View(); }
پیشنهاد رسمی اضافه شدن type unions به زبان #C
این متد را درنظر بگیرید:
public Receipt PlaceOrder(Order order) { var product = _products.SingleOrDefault(p => p.ProductId == order.ProductId); if (product is null) { throw new Exception("Product doesn't exist"); } if (product.Cost > order.Payment) { throw new Exception("Insufficient funds"); } var receipt = new Receipt(++_receiptId, order.Payment); _receipts.Add(receipt); return receipt; }
برای استفاده کننده دقیقا مشخص نیست که این متد ممکن است چندین استثناء را هم صادر کند. با وجود type unions، میتوان مقصود واضحتری را ارائه داد:
public (Receipt or PlaceOrderError) PlaceOrder(Order order)
هرچند در این لحظه، شبیه به اینکار را با استفاده از کتابخانهی OneOf هم انجام میدهند و ... TypeScript هم که در اساس توسط قسمت مهمی از تیم #C طراحی شده، مدتهاست که به همراه چنین قابلیتی هست.
پیشنهاد اضافه شدن type به JavaScript
Today we’re excited to announce our support and collaboration on a new Stage 0 proposal to bring optional and erasable type syntax to JavaScript. Because this new syntax wouldn’t change how surrounding code runs, it would effectively act as comments. We think this has the potential to make TypeScript easier and faster to use for development at every scale. We’d like to talk about why we’re pursuing this, and how this proposal works at a high level.
TypeScript 4.2 منتشر شد
Let’s take a look at what’s in store for TypeScript 4.2!
- Smarter Type Alias Preservation
- Leading/Middle Rest Elements in Tuple Types
- Stricter Checks For The
in
Operator -
--noPropertyAccessFromIndexSignature
-
abstract
Construct Signatures - The
--explainFiles
Flag - Improved Uncalled Function Checks in Logical Expressions
- Destructured Variables Can Be Explicitly Marked as Unused
- Relaxed Rules Between Optional Properties and String Index Signatures
- Declare Missing Helper Function
- Breaking Changes
localForage is a fast and simple storage library for JavaScript.localForage uses localStorage in browsers with no IndexedDB or WebSQL.
localforage.setItem('key', 'value', function (err) { // if err is non-null, we got an error localforage.getItem('key', function (err, value) { // if err is non-null, we got an error. otherwise, value is the value }); });
:Framework Support
AngularJS
Angular 4 and up
Backbone
Ember
Vue
TypeScript:
import localForage from "localforage";
نوعهای نال نپذیر در TypeScript
در نگارش 2.7 اگر یک چنین تعریفی را داشته باشید:
export class MovieComponent { @Input() movie: Movie; }
Error! Property movie has no initializer and is not assigned directly in the constructor.
@Input() movie: Movie | null = null;
class C { baz: boolean | undefined; }
class C { bar = "hello"; }
class C { foo!: number; ngOnInit() { this.foo = 0; } }
فعالسازی بررسی مشکلات قالبهای کامپوننتها
برای فعالسازی بررسی مشکلات قالبهای کامپوننتها، نیاز است به فایل تنظیمات کامپایلر TypeScript و یا همان tsconfig.json مراجعه کرد و سپس قسمت جدیدی را به آن به نام angularCompilerOptions، افزود:
{ "compilerOptions": { "experimentalDecorators": true, ... }, "angularCompilerOptions": { "fullTemplateTypeCheck": true, "preserveWhiteSpace": false, ... } }
- البته این خاصیت در حین استفادهی از یکی از دستورات ng serve --aot و یا ng build --prod انتخاب میشود.
- مقدار این پرچم در نگارشهای 5x به صورت پیشفرض به false تنظیم شدهاست؛ اما در نگارش 6 آن به true تنظیم خواهد شد. بنابراین بهتر است از هم اکنون کار با آنرا شروع کنید.
یک مثال: بررسی خاصیت fullTemplateTypeCheck
فرض کنید اینترفیس یک مدل را به صورت زیر تعریف کردهاید که فقط دارای خاصیت name است:
export interface PonyModel { name: string; }
import { PonyModel } from "./pony"; @Component({ selector: "app-detect-common-errors-test", templateUrl: "./detect-common-errors-test.component.html", styleUrls: ["./detect-common-errors-test.component.css"] }) export class DetectCommonErrorsTestComponent implements OnInit { ponyModel: PonyModel = { name: "Pony1" };
<p>Hello {{ponyModel.age}}
در این حالت اگر fullTemplateTypeCheck فعال شده باشد و دستور ng build --prod را صادر کنیم، به خروجی ذیل خواهیم رسید:
\detect-common-errors-test.component.html(5,4): : Property 'age' does not exist on type 'PonyModel'.
برای اینکه بتوانید به حداکثر کارآیی این قابلیت برسید، بهتر است گزینهی strict را در تنظیمات کامپایلر TypeScript روشن کنید و خودتان را به کار با نوعهای نال نپذیر عادت دهید. به این ترتیب میتوانید تعداد خطاهای احتمالی بیشتری را پیش از موعد و پیش از وقوع آنها در زمان اجرا، در زمان کامپایل، پیدا و رفع کنید.
یک نکتهی تکمیلی
افزونهی Angular Language service نیز یک چنین قابلیتی را به همراه دارد (و حتی در نگارشهای پیش از 5 نیز قابل استفاده است).
0.Visual Studio 2017 15.9 منتشر شد
Summary of Notable New Features in 15.9
- You can now import and export an installation configuration file that specifies which workloads and components should be installed with an instance of Visual Studio.
- We have improved the debugging experience for NuGet packages using the new symbol package format (.snupkg).
- Step back in debugger is now available in C++ for Enterprise customers.
- C++ IntelliSense now responds to changes in the remote environment for both CMake and MSBuild projects targeting Linux.
- We have made updates to UWP Desktop Bridge framework packages and added support for ARM64 C++ Native Desktop scenarios.
- We added support for the range-v3 library with the MSVC 15.9 compiler.
- We fixed several bugs in the F# compiler and F# tools.
- Language service support for new TypeScript features for semantic file renaming and project references.
- Improved Node.js development by updating Vue.js templates and adding support for unit testing using the Jest framework.
- We added SharePoint 2019 project templates, so you can migrate existing SharePoint 2013 and 2016 projects to SharePoint 2019.
- Visual Studio Tools for Xamarin now supports Xcode 10.
- We made improvements to the Xamarin.Android build performance.
- We have added and improved features for Universal Windows Platform developers, including ARM64 support, the latest preview SDK, better debugging of Desktop Bridge applications, and XAML Designer improvements.
- Substantial improvements were made to the experience of using authenticated package feeds.
- There is now support for lock file to enable repeatable restore for PackageReference based projects.
- We have added support for the new license format for NuGet packages.
- We have introduced NuGet client policies in Visual Studio which enables you to lock down environments such that only trusted packages can be installed.
- We made the use of .NET Core within Visual Studio more predictable.
Top Issues Fixed in 15.9
- No way to change "Find All References" background color.
- "Visual C++ Resource Editor Package" load failed.
- VS2017 v15.8 Build does not start if XAML files are not manually saved first.
- Installation failed - manifest signature verification failed.
- Update 15.8.6 breaks Installer Projects.
- Scrolling up with the arrow key causes Visual Studio to page up.
- After updating to 15.8.1, data tip does not show when debugging.
- System.InvalidProgramException: Common Language Runtime detected an invalid program..
- Solution Explorer does not remain pinned after closing Visual Studio.
- Navigation bar in editor has trouble handling long method names.