داخل آن یک پوشهی Samples هست که از برنامههای وب تا EF و دسکتاپ و غیره را پوشش میدهد.
مستندات آن در گروه PdfReport سایت ارائه شده و همچنین در راهنمای آن در سایت.
List<string> scope = newList<string>() { "email", "user_about_me", "user_hometown", "friends_about_me", "friends_photos" }; var x = newFacebookAuthenticationOptions(); x.Scope.Add("email"); x.Scope.Add("friends_about_me"); x.Scope.Add("friends_photos"); x.AppId = "636919159681109"; x.AppSecret = "f3c16511fe95e854cf5885c10f83f26f"; x.Provider = newFacebookAuthenticationProvider() { OnAuthenticated = async context => { //Get the access token from FB and store it in the database and //use FacebookC# SDK to get more information about the user context.Identity.AddClaim( new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken)); } }; x.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie; app.UseFacebookAuthentication(x);
<li> @Html.ActionLink("FacebookInfo", "FacebookInfo","Account") </li>
// // GET: /Account/LinkLoginCallback publicasyncTask<ActionResult> LinkLoginCallback() { var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId()); if (loginInfo == null) { return RedirectToAction("Manage", new { Message = ManageMessageId.Error }); } var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login); if (result.Succeeded) { var currentUser = await UserManager.FindByIdAsync(User.Identity.GetUserId()); //Add the Facebook Claim await StoreFacebookAuthToken(currentUser); return RedirectToAction("Manage"); } return RedirectToAction("Manage", new { Message = ManageMessageId.Error }); }
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl) { if (User.Identity.IsAuthenticated) { return RedirectToAction("Manage"); } if (ModelState.IsValid) { // Get the information about the user from the external login provider var info = await AuthenticationManager.GetExternalLoginInfoAsync(); if (info == null) { return View("ExternalLoginFailure"); } var user = newApplicationUser() { UserName = model.Email }; var result = await UserManager.CreateAsync(user); if (result.Succeeded) { result = await UserManager.AddLoginAsync(user.Id, info.Login); if (result.Succeeded) { await StoreFacebookAuthToken(user); await SignInAsync(user, isPersistent: false); return RedirectToLocal(returnUrl); } } AddErrors(result); } ViewBag.ReturnUrl = returnUrl; return View(model); }
// // GET: /Account/ExternalLoginCallback [AllowAnonymous] publicasyncTask<ActionResult> ExternalLoginCallback(string returnUrl) { var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(); if (loginInfo == null) { return RedirectToAction("Login"); } // Sign in the user with this external login provider if the user already has a login var user = await UserManager.FindAsync(loginInfo.Login); if (user != null) { //Save the FacebookToken in the database if not already there await StoreFacebookAuthToken(user); await SignInAsync(user, isPersistent: false); return RedirectToLocal(returnUrl); } else { // If the user does not have an account, then prompt the user to create an account ViewBag.ReturnUrl = returnUrl; ViewBag.LoginProvider = loginInfo.Login.LoginProvider; return View("ExternalLoginConfirmation", newExternalLoginConfirmationViewModel { Email = loginInfo.Email }); } }
privateasyncTask StoreFacebookAuthToken(ApplicationUser user) { var claimsIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie); if (claimsIdentity != null) { // Retrieve the existing claims for the user and add the FacebookAccessTokenClaim var currentClaims = await UserManager.GetClaimsAsync(user.Id); var facebookAccessToken = claimsIdentity.FindAll("FacebookAccessToken").First(); if (currentClaims.Count() <=0 ) { await UserManager.AddClaimAsync(user.Id, facebookAccessToken); }
public class FacebookViewModel { [Required] [Display(Name = "Friend's name")] public string Name { get; set; } public string ImageURL { get; set; } }
//GET: Account/FacebookInfo [Authorize] publicasyncTask<ActionResult> FacebookInfo() { var claimsforUser = await UserManager.GetClaimsAsync(User.Identity.GetUserId()); var access_token = claimsforUser.FirstOrDefault(x => x.Type == "FacebookAccessToken").Value; var fb = newFacebookClient(access_token); dynamic myInfo = fb.Get("/me/friends"); var friendsList = newList<FacebookViewModel>(); foreach (dynamic friend in myInfo.data) { friendsList.Add(newFacebookViewModel() { Name = friend.name, ImageURL = @"https://graph.facebook.com/" + friend.id + "/picture?type=large" }); } return View(friendsList); }
@model IList<WebApplication96.Models.FacebookViewModel> @if (Model.Count > 0) { <h3>List of friends</h3> <div class="row"> @foreach (var friend in Model) { <div class="col-md-3"> <a href="#" class="thumbnail"> <img src=@friend.ImageURL alt=@friend.Name /> </a> </div> } </div> }
این یک مثال ساده از کار کردن با تامین کنندگان اجتماعی بود. همانطور که مشاهده میکنید، براحتی میتوانید دادههای بیشتری برای کاربر جاری درخواست کنید و تجربه کاربری و امکانات بسیار بهتری را در اپلیکیشن خود فراهم کنید.
<cdk-virtual-scroll-viewport></cdk-virtual-scroll-viewport>
npm install -g @angular/cli
ng new angular7-virtualScrolling
npm install @angular/cdk@latest
title = 'Angular 7 – Virtual Scrolling feature'; scrollItems: number[] = []; constructor() { for (let index = 0; index < 10000; index++) { this.scrollItems.push(index); } }
<div> <h4> {{this.title}} </h4> <cdk-virtual-scroll-viewport itemSize="100"> <div *cdkVirtualFor="let n of scrollItems">Item {{n}}</div> </cdk-virtual-scroll-viewport> </div>
در قسمت قبل با نحوه ساخت تم سفارشی در انگیولار متریال ۲، آشنا شدیم. در این قسمت نحوه ساخت چند تم دیگر در کنار تم اصلی، ساخت تم به ازای هر کامپوننت و نحوه تعویض تم از طریق کد را دنبال خواهیم کرد.
ساخت تم اضافی در انگیولار متریال ۲ بسیار ساده است. شما میتوانید با استفاده مجدد از تابع angular-material-theme داخل یک کلاس CSS، صاحب یک تم اضافی دیگر شوید. برای نمونه در اینجا فایل my-custom-theme.scss را باز کرده و به شکل زیر تغییر میدهیم.
@import '~@angular/material/theming'; @include mat-core(); $my-app-primary: mat-palette($mat-teal); $my-app-accent: mat-palette($mat-amber, 500, A100, A400); $my-app-warn: mat-palette($mat-deep-orange); $my-app-theme: mat-light-theme($my-app-primary, $my-app-accent, $my-app-warn); @include angular-material-theme($my-app-theme); /*تعریف تم اضافی در کنار تم اصلی*/ $alternate-primary: mat-palette($mat-light-blue); $alternate-accent: mat-palette($mat-yellow, 500); $alternate-warn: mat-palette($mat-red, 500); $alternate-theme: mat-dark-theme($alternate-primary, $alternate-accent); .alternate-theme { @include angular-material-theme($alternate-theme); }
با اینکار در کنار تم روشن اصلی، یک تم مشکی به صورت اضافی داخل کلاس CSS به نام alternate-theme تعریف کردهایم. در این حالت تمامی کامپوننتهایی که داخل المنت با کلاس alternate-theme قرار گرفتهاند، از تم مشکی تعریف شده استفاده خواهند کرد.
با تغییر فایل app.component.html به شکل زیر:
<md-card> <md-card-header> <md-card-title>تم اصلی</md-card-title> </md-card-header> <button md-raised-button color="primary"> Primary </button> <button md-raised-button color="accent"> Accent </button> <button md-raised-button color="warn"> Warning </button> </md-card> <div> <md-card> <md-card-header> <md-card-title>تم اضافی</md-card-title> </md-card-header> <md-card-content> <button md-raised-button color="primary"> Primary </button> <button md-raised-button color="accent"> Accent </button> <button md-raised-button color="warn"> Warning </button> </md-card-content> </md-card> </div>
تصویر زیر را در خروجی خواهید داشت.
به همین روش میتوانید تعداد دلخواهی از تمها را بسازید. همچنین میتوانید هر تم اضافی را در یک فایل Sass تعریف کنید و از این طریق تمهای مختلف را از هم جدا کنید. در این حالت به این نکته توجه داشته باشید که نباید mat-core@ در سرتاسر برنامه بیش از یکبار بارگذاری شده باشد.
با استفاده از mixin به نام angular-material-theme خروجی تولید شده بر روی تمامی کامپوننتهای انگیولار متریال ۲ اعمال خواهد شد. اگر از تمامی کامپوننتهای انگیولار متریال ۲ استفاده نمیکنید، میتوانید برای کاهش حجم فایل CSS تولید شده از mixin مخصوص به هر کامپوننت استفاده کنید. همچنین برای ساخت تمهای متفاوت به ازای هر کامپوننت نیز میتوانید از این روش استفاده کنید.
برای این کار تمامی مراحلی که برای ساخت تم مورد نیاز بود، باید طی شود. فقط به جای استفاده از mixin به نام angular-material-theme بایستی به طریق زیر عمل شود.
اول: بارگذاری mixin با نام mat-core-them. این mixin تمامی استایلهای مشترک رفتاری (مانند موج (ripple) در هنگام کلیک) برای کامپوننتها را در بر دارد. این mixin خروجی تابع mat-light-theme یا mat-dark-theme را به عنوان ورودی دریافت میکند.
دوم: بارگذاری mixin مربوط به هر کامپوننت. برای مثال برای دکمه از mixin به نام mat-button-theme و برای checkbox از mixin به نام mat-checkbox-theme میتوانید استفاده کنید. در زیر لیست mixinها به ازای کامپوننتهای مختلف ذکر شده است.
mat-autocomplete-theme mat-button-theme mat-button-toggle-theme mat-card-theme mat-checkbox-theme mat-chips-theme mat-datepicker-theme mat-dialog-theme mat-grid-list-theme mat-icon-theme mat-input-theme mat-list-theme mat-menu-theme mat-progress-bar-theme mat-progress-spinner-theme mat-radio-theme mat-select-theme mat-sidenav-theme mat-slide-toggle-theme mat-slider-theme mat-tabs-theme mat-toolbar-theme mat-tooltip-theme
در مثال زیر میخواهیم تمامی کامپوننتها به جز کامپوننت دکمه، تم سبز(در گروه Primary) و دکمهها نیز تم آبی داشته باشند. کافی است کدهای زیر را در فایل Sass خود وارد کنید.
@import '~@angular/material/theming'; @include mat-core(); $my-app-primary: mat-palette($mat-teal); $my-app-accent: mat-palette($mat-amber, 500, A100, A400); $my-app-warn: mat-palette($mat-deep-orange); $my-app-theme: mat-light-theme($my-app-primary, $my-app-accent, $my-app-warn); @include mat-material-theme($my-app-theme); /* تعریف تم برای دکمه */ $button-primary: mat-palette($mat-light-blue); $button-accent: mat-palette($mat-yellow, 500); $button-warn: mat-palette($mat-red, 500); $button-theme: mat-light-theme($button-primary, $button-accent); @include mat-button-theme($button-theme);
با توجه به اینکه mat-material-theme در داخل خود mat-button-theme را بارگذاری میکند دو نتیجه زیر را میتوان گرفت.
اول: اگر mat-material-theme بعد از هر کدام از mixinهای مربوط به کامپوننتها نوشته شود، تمامی Cssهای تولید شده به ازای کامپوننت را دوباره نویسی کرده و عملا هیچ کدام کارایی نخواهند داشت. برای مثال کافی است فایل Sass خود را به شکل زیر تغییر دهید. در این صورت تم مربوط به دکمه کاریی نخواهد داشت.
@import '~@angular/material/theming'; @include mat-core(); /* تعریف تم برای دکمه */ $button-primary: mat-palette($mat-light-blue); $button-accent: mat-palette($mat-yellow, 500); $button-warn: mat-palette($mat-red, 500); $button-theme: mat-ligth-theme($button-primary, $button-accent); @include mat-button-theme($button-theme); $my-app-primary: mat-palette($mat-teal); $my-app-accent: mat-palette($mat-amber, 500, A100, A400); $my-app-warn: mat-palette($mat-deep-orange); $my-app-theme: mat-light-theme($my-app-primary, $my-app-accent, $my-app-warn); @include mat-material-theme($my-app-theme);
دوم: همانطور که گفتیم mat-button-theme در mat-material-theme قبلا بارگذاری شده است. با بارگذاری دوباره توسط mat-button-theme کدهای CSS که قبلا برای دکمه تولید شدهاند را از نو دوباره مینویسد و این باعث بزرگ شدن حجم فایل Css تولید شده خواهد شد. پس بهتر است هنگام استفاده از mixinهای مختص کامپوننتها از mat-material-theme استفاده نکنیم.
@import '~@angular/material/theming'; @include mat-core(); $my-app-primary: mat-palette($mat-teal); $my-app-accent: mat-palette($mat-amber, 500, A100, A400); $my-app-warn: mat-palette($mat-deep-orange); $my-app-theme: mat-light-theme($my-app-primary, $my-app-accent, $my-app-warn); $button-primary: mat-palette($mat-light-blue); $button-accent: mat-palette($mat-yellow, 500); $button-warn: mat-palette($mat-red, 500); $button-theme: mat-light-theme($button-primary, $button-accent); @include mat-core-theme($my-app-theme); @include mat-autocomplete-theme($my-app-theme); @include mat-button-theme($button-theme); @include mat-button-toggle-theme($my-app-theme); @include mat-card-theme($my-app-theme); @include mat-checkbox-theme($my-app-theme); @include mat-chips-theme($my-app-theme); @include mat-datepicker-theme($my-app-theme); @include mat-dialog-theme($my-app-theme); @include mat-grid-list-theme($my-app-theme); @include mat-icon-theme($my-app-theme); @include mat-input-theme($my-app-theme); @include mat-list-theme($my-app-theme); @include mat-menu-theme($my-app-theme); @include mat-progress-bar-theme($my-app-theme); @include mat-progress-spinner-theme($my-app-theme); @include mat-radio-theme($my-app-theme); @include mat-select-theme($my-app-theme); @include mat-sidenav-theme($my-app-theme); @include mat-slide-toggle-theme($my-app-theme); @include mat-slider-theme($my-app-theme); @include mat-tabs-theme($my-app-theme); @include mat-toolbar-theme($my-app-theme); @include mat-tooltip-theme($my-app-theme);
فرض کنید یک تم پیش فرض و یک تم اضافی به نام alternate-theme دارید. برای تعویض تم از طریق کد کافی است کلاس المنت پدر در صفحه html خود را از طریق [ngClass] با نام تم، مقدار دهی کنید. کدهای داخل app.component.ts را به شکل زیر تغییر میدهیم.
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { themes = [ {value: 'alternate-theme', text: 'تم مشکی'}, {value: '', text: 'تم سفید'}, ]; activeTheme = ''; }
آرایهای جهت نمایش در کامپوننت md-select با دو مقدار تم پیش فرض و تم با نام 'alternate-theme تعریف میکنیم. همچنین متغیری با نام activeTheme را تعریف میکنیم. این متغیر در هر لحظه نام تم اعمال شده را در خود نگهداری میکند. مقدار اولیه این متغیر تم اصلی است.
کامپوننت md-select را به شکل زیر به فایل app.component.html به تگ main اضافه میکنیم.
<md-select dir="rtl" [(ngModel)]="activeTheme" placeholder="تعویض تم"> <md-option *ngFor="let theme of themes" [value]="theme.value"> {{ theme.text }} </md-option> </md-select>
<div [ngClass]="activeTheme">
Event based jQuery element resize
The plugin does not use any kind of timer(s) to detect size changes. It uses the resize event on (invincible) iframe(s) which makes it perform much better than other solutions which use timers to poll element size. The script detects size changes made from JS, CSS, animations etc. and it works on any element able to contain other elements (e.g. div, p, li etc.). To use it on other inline elements (e.g. images) you need to add a wrapper and call the event on it. Demo
public class ApplicationUser : IdentityUser<string, CustomUserLogin, CustomUserRole, CustomUserClaim> { public ApplicationUser() { Id = Guid.NewGuid().ToString(); } // ... }
@page "/"
@page "/" <p>Hello, @name</p> @code { string name = "Vahid N."; }
<p>Hello, @name.ToUpper()</p>
@page "/" <p>Hello, @name.ToUpper()</p> <p>Hello, @CustomToUpper(name)</p> @code { string name = "Vahid N."; string CustomToUpper(string value) => value.ToUpper(); }
<p>Let's add 2 + 2 : @2 + 2 </p>
<p>Let's add 2 + 2 : @(2 + 2) </p>
<button @onclick="@(()=>Console.WriteLine("Test"))">Click me</button>
@page "/" <button @onclick="@WriteLog">Click me 2</button> @code { void WriteLog() { Console.WriteLine("Test"); } }
@page "/" <button @onclick="@(()=>WriteLogWithParam("Test 3"))">Click me 3</button> @code { void WriteLogWithParam(string value) { Console.WriteLine(value); } }
BlazorRazorSample\Client\Pages\Index.razor(12,25): error CS1501: No overload for method 'WriteLog' takes 1 arguments
@page "/" <p>Hello, @StringUtils.MyCustomToUpper(name)</p> @code { public class StringUtils { public static string MyCustomToUpper(string value) => value.ToUpper(); } }
namespace BlazorRazorSample.Shared { public class StringUtils { public static string MyNewCustomToUpper(string value) => value.ToUpper(); } }
@page "/" @using BlazorRazorSample.Shared <p>Hello, @StringUtils.MyNewCustomToUpper(name)</p>
@using BlazorRazorSample.Shared
using System; namespace BlazorRazorSample.Shared.Models { public class MovieDto { public string Title { set; get; } public DateTime ReleaseDate { set; get; } } }
@using BlazorRazorSample.Shared.Models
@page "/" <div> <h3>Movies</h3> @foreach(var movie in movies) { <p>Title: <b>@movie.Title</b></p> <p>ReleaseDate: @movie.ReleaseDate.ToString("dd MMM yyyy")</p> } </div> @code { List<MovieDto> movies = new List<MovieDto> { new MovieDto { Title = "Movie 1", ReleaseDate = DateTime.Now.AddYears(-1) }, new MovieDto { Title = "Movie 2", ReleaseDate = DateTime.Now.AddYears(-2) }, new MovieDto { Title = "Movie 3", ReleaseDate = DateTime.Now.AddYears(-3) } }; }
@for(var i = 0; i < movies.Count; i++) { <div style="background-color: @(i % 2 == 0 ? "blue" : "red")"> <p>Title: <b>@movies[i].Title</b></p> <p>ReleaseDate: @movies[i].ReleaseDate.ToString("dd MMM yyyy")</p> </div> }
@page "/fetchdata" @using BlazorRazorSample.Shared @inject HttpClient Http <h1>Weather forecast</h1> <p>This component demonstrates fetching data from the server.</p> @if (forecasts == null) { <p><em>Loading...</em></p> } else { <table class="table"> <thead> <tr> <th>Date</th> <th>Temp. (C)</th> <th>Temp. (F)</th> <th>Summary</th> </tr> </thead> <tbody> @foreach (var forecast in forecasts) { <tr> <td>@forecast.Date.ToShortDateString()</td> <td>@forecast.TemperatureC</td> <td>@forecast.TemperatureF</td> <td>@forecast.Summary</td> </tr> } </tbody> </table> } @code { private WeatherForecast[] forecasts; protected override async Task OnInitializedAsync() { forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast"); } }
@if (forecasts == null) { <p><em>Loading...</em></p> }
new MovieDto { Title = "<i>Movie 1</i>", ReleaseDate = DateTime.Now.AddYears(-1) },
<p>Title: <b>@((MarkupString)movie.Title)</b></p>
<link rel="stylesheet" href="@Url.Content("~/Content/bootstrap-rtl.css")" type="text/css" /> <script type="text/javascript" src="@Url.Content("~/scripts/jquery-2.0.2.min.js")"></script> <script type="text/javascript" src="@Url.Content("~/scripts/jquery-ui-1.10.3.min.js")"></script> <script type="text/javascript" src="@Url.Content("~/scripts/bootstrap-rtl.js")"></script> <script type="text/javascript" src="@Url.Content("~/scripts/searchboxmvc.js")"></script>
[HttpPost] public virtual ActionResult LoadData(string fieldName, string value, string stringFilterMode = "startWith") { Thread.Sleep(2000); var models = MakePersons(); if (fieldName == "Id") { models = models.Where(p => p.Id == int.Parse(value)).Take(1).ToList(); } else if (fieldName == "FirstName") { models = models.Where(p => p.FirstName.StartsWith(value)).ToList(); } return Json(new { Status = "OK", Records = models }); } private List<Person> MakePersons() { var lst = new List<Person>(); lst.Add(new Person() { Id = 1, Code = "Uytffs-098", FirstName = "احمدرضا", LastName = "عابدزاده" }); lst.Add(new Person() { Id = 2, Code = "fTuuuw-652", FirstName = "کریم", LastName = "باقری" }); lst.Add(new Person() { Id = 3, Code = "Lopapo-123", FirstName = "خداداد", LastName = "عزیزی" }); lst.Add(new Person() { Id = 4, Code = "Utppq-981", FirstName = "علی", LastName = "دایی" }); lst.Add(new Person() { Id = 5, Code = "zttsn-471", FirstName = "علی", LastName = "کریمی" }); lst.Add(new Person() { Id = 6, Code = "poiud-901", FirstName = "مهدی", LastName = "مهدوی کیا" }); lst.Add(new Person() { Id = 7, Code = "wqrPoP-391", FirstName = "علیرضا", LastName = "منصوریان" }); return lst; }
... <div id="div_SearchBoxContainer"> </div> ... @section scripts{ <script type="text/javascript"> $("#div_SearchBoxContainer").searchboxmvc({ loadUrl: '@Url.Action(actionName: "LoadData", controllerName: "Home")', defaultStringFilterMode: "startWith", loadDataOnLeave: true, displayClass: "", displayNoResultClass: "", display: function (element, record) { $(element).html(record.FirstName + " " + record.LastName); }, listItemsDisplay: function (element, record, index) { return record.LastName + " " + record.FirstName + "(" + record.Code + ")"; }, fields: [ { fieldName: "Id", fieldTitle: "شناسه", width: 100, defaultValueField: true }, { fieldName: "FirstName", fieldTitle: "نام", width: 200, defaultDisplayField: true, filter: true, isStringType: true }, { fieldName: "LastName", fieldTitle: "نام خانوادگی", filter: false, isStringType: true } ] }); </script> }