میدانید که در پروژه و نرم افزارهایی که توسعه داده میشوند بعضی مواقع مشاهده میکنیم قسمتی از برنامه نیاز به زمان یا پردازش بیشتری دارد تا عملیات خود را به اتمام برساند و رابط کاربری (User Interface) برنامه در این حین منتظر میماند و یا به اصطلاح (Freeze) میشود تا یک پردازش طولانی به اتمام برسد و بعد رابط کاربری به کار خود ادامه میدهد و بعضی مواقع پنجره Windows explorer is not responding را مشاهده کردهاید که با کلیک بر روی Close the program از آن گذر میکنیم. در حالی که برنامه ما باید حالت Responsive داشته باشد و نباید برنامه با یکچنین مواردی روبه رو شود.
ساختمان Thread :
تمامی اشیاء (Objects) در این مدل به دو گروه تقسیم بندی میشوند:
STA شامل فقط یک Thread میباشد و تمامی اشیاء در این ساختمان فقط میتوانند متدی را که در این Thread صدا زده میشود دریافت کنند؛ یا به عبارتی دیگر هنگامیکه شیء به Thread ای متصل میشود دیگر شما قادر نخواهید بود اشیاء UI را به صورت مستقیم و یا از طریق Threadهای دیگر تغییر دهید. لازم به ذکر است WPF از مدل STA پشتیبانی میکند که شامل نکات زیر میباشد:
1. یک Thread در کل برنامه اجرا میشود و شامل همه Objectهای WPF میباشد.
2. عناصر یا المانهای WPF، قابلیت تنظیم Thread Affinity را دارند. منظور این میباشدکه Threadها نمیتوانند با یکدیگر ارتباط برقرار کنند.
3. اشیاء WPF که قابلیت Thread Affinityرا دارند، از یک Object Dispatcher مشتق میشوند.
4. اشیاء WPF متعلق به Thread ای میباشند که توسط آن ایجاد شده است و Thread دیگر قادر به دسترسی مستقیم به این اشیاء نمیباشد.
ساختمان Multi-Threaded Apartment (MTA) :
MTA شامل یک یا چندین Thread میباشد. تمامی اشیاء در این مدل میتوانند از هر Thread ای فراخوانی شوند. در حقیقت رجیسترهای CPU و Ram که در اختیار برنامه قرار داده شده تکه تکه میشوند و برنامه ما تعداد Threadهای مورد نظر را اجرا میکند و یکی از راه حلهای بر طرف کردن اینکه رابط کاربری ما در حالت انتظار باقی نماند استفاده از پردازش کارها بصورت غیر همزمان (Asynchronous) میباشد که در اصطلاح Multithreading نامیده میشود.
WPF Dispatcher :
WPF از مدل STA پشتیبانی میکند. زمانیکه برنامه WPF اجرا میشود، به طور خودکار یک Dispatcher Object ساخته میشود و متد Run صدا زده میشود و از آن برای آماده سازی صف پیامها استفاده میشود که مدیریت یک صف از کارها بر عهده آن است و کارهای UI را در یک صف FIFO اجرا میکند. WPF یک Dispatcher را برای UI Thread ایجاد میکند. بنابراین شما نمیتوانید یک dispatcher دیگر برای آن تعریف کنید.
نکته : دیاگرام زیر نمایش میهد که تمامی اشیاء WPF
از DispatcherObject مشتق شدهاند.
نکته : زمانیکه برنامه WPF اجرا میشود دو Thread ساخته میشود:
1. UI Thread (Main Thread)
2. Render Thread
UI Thread : مسئولیت تمامی ورودیهای کاربر، handle events, paints screen و اجرای کدهای برنامه را بر عهده دارد.
Render Thread : در Background اجرا میشود و برای Render صفحه نمایش WPF استفاده میشود.
نکته: همانطور که آشنا شدیم WPF نمیتواند UI Thread را از طریق یک Thread دیگر به روز رسانی کند و یا به عبارتی دیگر یک Thread نمیتواند بصورت مستقیم به اشیایی که توسط Thread دیگر ایجاد شده، دسترسی داشته باشد.
Dispatcher برای این کار دو متد را در اختیار ما قرار میدهد :
متد Invoke : یک Action یا Delegate را میگیرد و متد آنرا به صورت همزمان اجرا میکند. این مورد به این معنا است که تا زمانی که اجرای متد کامل نگردد، عملیاتی صورت نخواهد گرفت و یا به عبارتی دیگر فراخوان را تا زمانیکه زمانبندی به پایان برسد، در حالت مسدود نگهداری خواهد کرد.
مثال :
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Task.Factory.StartNew(() => { InvokeMethodExample(); }); } private void InvokeMethodExample() { Thread.Sleep(2000); Dispatcher.Invoke(() => { btn1.Content = "By Invoke"; }); } }
مثال :
public MainWindow() { InitializeComponent(); Task.Factory.StartNew(() => { BeginInvokeExample(); }); } private void BeginInvokeExample() { DispatcherOperation op = Dispatcher.BeginInvoke((Action)(() => { btn1.Content = "By BeginInvoke"; })); }
CoffeeScript #12
بخشهای بد
جاوااسکریپت یک زبان پیچیده است که شما برای کار با آن، نیاز است قسمتهایی را که باید از آنها دوری کنید و قسمتهای مهمی را که باید استفاده کنید، بشناسید. همانطور که Sun Tzu گفته "دشمن خود را بشناس"، ما نیز در این قسمت میخواهیم برای شناخت بیشتر قسمتهای تاریک و روشن جاوااسکریپت به آن بپردازیم.
همانطور که در قسمتهای قبل گفته شد، CoffeeScript تنها به یک syntax محدود نمیشود و توانایی برطرف کردن برخی از مشکلات جاوااسکریپت را نیز دارد. با این حال، با توجه به این واقعیت که کدهای CoffeeScript به صورت مستقیم به جاوااسکریپت تبدیل میشوند و نمیتوانند تمامی مشکلاتی را که در جاوااسکریپت وجود دارند، حل کنند، پس برخی از مسائل وجود دارند که شما باید از آنها آگاهی داشته باشید.
اول از قسمتهایی که توسط CoffeeScript حل شدهاند شروع میکنیم.
A JavaScript Subset
with یک دستور بسیار زمانبر است و مضر شناخته شده است و نباید از آن استفاده کنید. with با ایجاد یک ساختار خلاصه نویسی، برای جستجو بر روی خصوصیات اشیاء در نظر گرفته شده بود. برای نمونه به جای نوشتن:
dataObj.users.vahid.email = "info@vmt.ir";
with(dataObj.users.vahid) { email = "info@vmt.ir"; }
همه چیز برای عدم استفاده از with در نظر گرفته شده است. CoffeeScript یک قدم جلوتر از همه برداشته و with را از syntax خود حذف کرده است. به عبارت دیگر در صورتیکه شما از آن استفاده کنید، کامپایلر CoffeeScript خطا صادر میکند.
Global variables
به طور پیش فرض تمامی برنامههای جاوااسکریپت در دامنه global اجرا میشوند و تمامی متغیرهایی که ساخته میشوند به طور پیش فرض در ناحیهی global قرار میگیرند. اگر شما بخواهید متغیری را در ناحیهی local ایجاد کنید، باید از کلمه کلیدی var استفاده کنید.
usersCount = 1; // Global var groupsCount = 2; // Global (function(){ pagesCount = 3; // Global var postsCount = 4; // Local })()
خوشبختانه CoffeeScript به کمک شما میآید و به طور کامل انتساب متغیرهای global را به طور ضمنی از بین میبرد. به عبارت دیگر کلمه کلیدی var در CoffeeScript رزرو شده است و در صورت استفاده خطا صادر میشود.
به صورت پیش فرض به طور ضمنی متغیرها local ایجاد میشوند و خیلی سخت میشود متغیر global ایی را بدون انتساب آن به عنوان خصوصیتی از شیء window ایجاد کرد.
outerScope = true do -> innerScope = true
var outerScope; outerScope = true; (function() { var innerScope; return innerScope = true; })();
package = require('./package') class Test build: -> # Overwrites outer variable! package = @testPackage.compile() testPackage: -> package.create()
class window.Asset constructor: ->
Semicolons
جاوااسکریپت اجباری برای نوشتن ";" ندارد، بنابراین ممکن است یک سری از دستورات از قلم بیافتند. با این حال در پشت صحنهی کامپایلر جاوااسکریپت به ";" احتیاج دارد. به طوری که parser جاوااسکریپت به صورت خودکار هر زمانی که نتواند ارزیابی از دستورات داشته باشد، یک بار دیگر با ";" این کار را انجام میدهد و درصورت موفقیت، پیام خطایی مبنی بر نبود ";" را صادر میکند.متاسفانه این یک ایده بد است. چرا که ممکن است تغییر رفتاری در کد نوشته شده به وجود آید. به مثال زیر توجه کنید. به نظر کد نوشته شده صحیح است؛ درسته؟
function() {} (window.options || {}).property
function() {}(window.options || {}).property
C# 7.1 - async Main
نحوهی کار با متدهای async، در متدهای Main نگارشهای پیش از C# 7.1
برای کار با متدهای Async نیاز است از واژهی کلیدی await استفاده شود و با قید این واژه، ضروری است واژهی کلیدی async نیز به امضای متد دربرگیرندهی عملیات اضافه گردد؛ اما در نگارشهای پیشین زبان #C، امکان async تعریف کردن متد Main وجود نداشت. در این حالت میبایستی به صورت ذیل عمل میشد:
static void Main(string[] args) { MainAsync().GetAwaiter().GetResult(); Console.ReadLine(); } private static async Task MainAsync() { using (StreamReader reader = File.OpenText("Program.cs")) { var message = await reader.ReadToEndAsync().ConfigureAwait(false); Console.Write(message); } }
نحوهی کار با متدهای async در متدهای Main برنامههای مبتنی بر C# 7.1
در زبان سیشارپ، متدهای Main برنامههای کنسول میتوانند خروجیهایی از نوع void و int داشته باشند؛ به همراه آرگومانی از نوع []string و یا بدون آرگومان. اکنون در سیشارپ 7.1، دو امضای دیگر نیز به این مجموعه، جهت کار با اعمال Async اضافه شدهاست: async Task و یا <async Task<int
در این حالت مثال قبل را میتوان به صورت ذیل خلاصه کرد:
static async Task Main(string[] args) { using (StreamReader reader = File.OpenText("Program.cs")) { var message = await reader.ReadToEndAsync().ConfigureAwait(false); Console.Write(message); } Console.ReadLine(); }
نگاهی به پشت صحنهی کامپایل async Task Main در C# 7.1
در عمل، کامپایلر سیشارپ جهت حفظ سازگاری با نگارشهای قبلی، مجددا همان متد static void Main را تولید میکند و عملیاتی را که در مورد نگارشهای پیشین توضیح داده شد، تکرار خواهد کرد:
using System; using System.IO; using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace ConsoleCS71 { internal class Program { private static async Task Main(string[] args) { StreamReader reader = File.OpenText("message.txt"); try { string str = await reader.ReadToEndAsync(); string message = str; str = (string)null; Console.Write(message); message = (string)null; } finally { if (reader != null) reader.Dispose(); } reader = (StreamReader)null; Console.ReadLine(); } [SpecialName] private static void <Main>(string[] args) { Program.Main(args).GetAwaiter().GetResult(); } } }
در یک برنامهی سیشارپ میتوان بیش از یک متد Main داشت
تعریف بیش از یک متد Main در برنامههای سیشارپ مجاز است:
namespace ConsoleApp5 { class Class1 { static void Main(string[] args) { } } class Class2 { static void Main(string[] args) { } } }
اما ... اگر دقت کنید، متد async Task Main در اینجا ایندکس نشدهاست که به نظر کمبود نگارش فعلی VS 2017 است.
در بسیاری از پروژههای دات نت، نیاز به استفاده از فایلهای نرم افزار آفیس، از قبیل ورد و اکسل و ... وجود دارد. برای مثال گاهی لازم است اطلاعات یک گرید، یا هر منبع دادهای، در قالب اکسل به کاربر نمایش داده شود. بدین شکل که این فایلها در زمان اجرا ساخته شده و به کاربر نمایش داده شود .حال فرض کنید شما روی سیستم خودتان Office2007 را نصب کرده اید و به اسمبلیهای این ورژن دسترسی دارید. البته بدون نیاز به نصب آفیس نیز میتوان به این توابع دسترسی داشت و از آنها در برنامه استفاده کرد که همان استفاده از Primary Interop Assemblies میباشد. مشکلی که ممکن است پیش آید این است که در کامپیوترهای کاربران ممکن است ورژنهای مختلفی از آفیس نصب باشد مانند 2003 -2007-2010-2013 و اگر با ورژن اسمبلیهایی که فراخوانیهای فایلهای اکسل از طریق آن انجام شده باشد متفاوت باشد، برنامه اجرا نمیشود .
در حالت معمول برای نمایش یک فایل آفیس مثل اکسل در برنامه، ابتدا اسمبلی مربوطه را (اکسل در این مثال) که به نام Microsoft.Office.Interop.Excel میباشد به اسمبلیهای برنامه اضافه کرده (از طریق add reference) و برای نمایش یک فایل اکسل در زمان اجرا از کدهای زیر استفاده مینماییم :
try { var application = (Microsoft.Office.Interop.Excel.Application)Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application")); Workbook wrkBook; var wbk = application.Workbooks; wrkBook = wbk.Add(); wrkBook.Activate(); application.Visible = true; } catch (Exception ex) { Error(ex.Message); }
حال اگر آفیس 2010 به عنوان مثال در سیستم ما نصب باشد، ورژن این اسمبلی 14 میباشد و اگر این برنامه را در کامپیوتر کلاینتی که آفیس 2007 بر روی آن نصب باشد انتشار دهیم اجرا نمیشود. برای حل این مشکل بنده با استفاده از روش dynamic این موضوع را حل کردم و بنظر میرسد راههای دیگری نیز برای حل آن وجود داشته باشد.
در این روش با توجه به ورژن آفیسی که بر روی سیستم کاربر نصب شده اسمبلی مربوطه را از سیستم کاربر لود کرده و فایلهای آفیس را اجرا مینماییم. در ابتدا تشخیص میدهیم چه ورژنی از آفیس بر روی سیستم کاربر نصب است :
string strVersion = null; dynamic objEApp =Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application")); if (objEApp.Version == "12.0") { strVersion = "2007"; } else if (objEApp.Version == "14.0") { strVersion = "2010"; }
روش دیگر برای انجام اینکار استفاده از اطلاعات رجیستری ویندوز است :
string strEVersionSubKey = "\\Excel.Application\\CurVer"; string strValue = null; //Value Present In Above Key string strVersion = null; //Determines Excel Version RegistryKey rkVersion = null; //Registry Key To Determine Excel Version rkVersion = Registry.ClassesRoot.OpenSubKey(strEVersionSubKey, false); //Open Registry Key if ((rkVersion != null)) //If Key Exists { strValue = (string)rkVersion.GetValue(string.Empty); //Get Value strValue = strValue.Substring(strValue.LastIndexOf(".") + 1); //Store Value switch (strValue) //Determine Version { case "11": strVersion = "2003"; break; case "12": strVersion = "2007"; break; case "14": strVersion = "2010"; break; }
if (strVersion == "2007") { string strAssemblyOff2007 = "Microsoft.Office.Interop.Excel, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"; try { Assembly xslExcelAssembly = Assembly.Load(strAssemblyOff2007); //Load Assembly Type type = xslExcelAssembly.GetTypes().Single(t => t.Name == "ApplicationClass"); dynamic application = Activator.CreateInstance(type); var workbooks = application.Workbooks; var workbook = workbooks.Add(); var worksheet = workbook.Worksheets[1]; workbook.Activate(); application.Visible = true; } catch (Exception ex) { } }
صفحات مودال در بوت استرپ 3
testmodal-(2).html
من خودم اکثر اوقات با json مقادیر مورد نظر رو در مودال نشون میدم ، چیزی شبیه به این :
function gettData(code) { $.ajax({ url: '@Url.Action(MVC.X.Y())', data: { code: code }, type: "POST", success: function (data) { $("#title").html(data.Title); $("#user-image").html(data.imagePath); }, error: function (response) { } }); }
$(document).on('click', '.item', function () { getData($(this).data("code")); $("#SecondModal").modal('toggle'); });
return json(new { result = "ok" });
//... success: function (data) { if (data) { alert("json data: " + data.result); } }
Visual Studio Code 1.16 منتشر شد
کتابخانه NoobScroll
A lightweight jQuery Plugin that adds some cool function to make scrolling more fun. Demo
$ npm install noobscroll