مطالب دوره‌ها
دریافت قالب WpfFramework.vsix و نحوه نصب و راه اندازی آن
فایل قالب پروژه دوره جاری را از آدرس ذیل می‌توانید دریافت کنید:

نصب ابتدایی آن بسیار ساده است و نکته خاصی ندارد.
پس از نصب، یکبار VS.NET را بسته و سپس باز کنید. این قالب جدید، ذیل قسمت پروژه‌های ویندوز مرتبط با ویژوال سی شارپ، ظاهر خواهد شد:


در این حال اگر یک پروژه جدید را آغاز کنید، این قالب تدارک دیده شده، لایه‌ها و قسمت‌های مختلف را به صورت خودکار اضافه خواهد کرد:



نکته مهم! برنامه کامپایل نمی‌شود!

به عمد، جهت کاهش حجم قالب دریافتی فوق، فایل‌های باینری آن پیوست نشده‌اند. وگرنه باید بالای 30 مگابایت را دریافت می‌کردید که واقعا نیازی نیست.
اما اگر به هر پروژه داخل Solution دقت کنید، فایل متنی packages.config آن نیز پیوست شده است. به کمک این فایل‌ها به سادگی می‌توان تمام وابستگی‌ها را از طریق NuGet بازیابی کرد.
برای این منظور ابتدا به اینترنت متصل شده (مهم) و سپس بر روی Solution کلیک راست کرده و گزینه فعال سازی Restore کلیه بسته‌های نیوگت را انتخاب کنید.


پس از اینکار، آخرین نگارش NuGet.exe از اینترنت دریافت و به پروژه اضافه می‌شود:


اکنون اگر Solution را Build کنید، اولین کاری که صورت خواهد گرفت، دریافت کلیه وابستگی‌ها از سایت NuGet است. اندکی تامل کنید تا اینکار تمام شود.
پس از پایان کار دریافت، پوشه packages در کنار فایل sln پروژه ایجاد شده، تشکیل می‌شود.
یکبار وجود آن‌را بررسی کنید.


اکنون اگر برنامه را Build کنید احتمالا پیغام می‌دهد که Fody را نمی‌تواند پیدا کند با اینکه دریافت شده و در پوشه packages موجود است. هر زمان، هر پیغام خطایی در مورد Fody مشاهده کردید، فقط یکبار VS.NET را بسته و باز کنید. مشکل حل می‌شود!

تنها کاری که پس از بازسازی پوشه packages بهتر است صورت گیرد (اختیاری است البته)، صدور دستور ذیل در خط فرمان پاور شل است:
 PM> Update-Package
با این دستور، دریافت کامل مجددی از اینترنت صورت نمی‌گیرد؛ مگر اینکه به روز رسانی جدیدی را یافت کند. در سایر حالات از کش داخل سیستم اطلاعات را دریافت می‌کند.
پس از اینکار، نیاز است یکبار VS.NET را بسته و مجددا باز کنید (مهم) تا تمام وابستگی‌ها به درستی بارگذاری شوند. خصوصا بسته Fody که کار AOP را انجام می‌دهد. در غیر اینصورت موفق به Build پروژه نخواهید شد.

بنابراین به صورت خلاصه:
الف) یکبار گزینه فعال سازی Restore کلیه بسته‌های نیوگت را انتخاب کنید.
ب) پروژه را Build کنید تا وابستگی‌ها را از سایت NuGet دریافت کند.
ج) دستور Update-Package را اجرا نمائید (اختیاری).
ج) VS.NET را پس از سه مرحله فوق، یکبار بسته و باز کنید.

در کل بسته‌های مورد استفاده به این شرح هستند:
PM> Install-Package MahApps.Metro -Pre 
PM> Install-Package MahApps.Metro.Resources 
PM> Install-Package EntityFramework
PM> Install-Package structuremap
PM> Install-Package PropertyChanged.Fody
PM> Install-Package MvvmLight 
PM> Install-Package Microsoft.SqlServer.Compact

یک نکته جانبی
فید NuGet در VS.NET به Https تنظیم شده است. اگر دسترسی به Https برای شما به کندی صورت می‌گیرد فقط کافی است مسیر فید آن‌را در منوی Tools، گزینه‌ی Options، ذیل قسمت Package manager یافته و به http://nuget.org/api/v2 تغییر دهید؛ یعنی به Http خالی، بجای Https؛ تا سرعت دریافت بسته‌های NuGet مورد نظر افزایش یابند.



اجرای پروژه و برنامه

پس از این مراحل و Build موفقیت آمیز پروژه، برنامه را اجرا کنید. در اولین بار اجرای برنامه به صورت خودکار بانک اطلاعاتی به همراه ساختار جداول تشکیل می‌شوند. اما ... با خطای زیر مواجه خواهید شد:
 The path is not valid. Check the directory for the database. [ Path = D:\...\bin\Debug\Db\db.sdf ]
علت این است که در فایل app.config پروژه ریشه برنامه :
<connectionStrings>
    <clear/>
    <add name="MyWpfFrameworkContext"
         connectionString="Data Source=|DataDirectory|\Db\db.sdf;Max Buffer Size=30720;File Mode=Read Write;"
         providerName="System.Data.SqlServerCE.4.0" />
  </connectionStrings>
مسیر تشکیل بانک اطلاعاتی به پوشه db کنار فایل اجرایی برنامه تنظیم شده است. این پوشه db را در پوشه bin\debug ایجاد کرده و سپس برنامه را اجرا کنید.


برای ورود به برنامه از نام کاربری Admin و کلمه عبور 123456 استفاده نمائید.
این کاربر پیش فرض در کلاس MyWpfFrameworkMigrations لایه داده‌های برنامه، توسط متد addRolesAndAdmin اضافه شده است.


خوب! تا اینجا با نحوه نصب و راه اندازی این قالب جدید آشنا شدیم. در قسمت‌های بعد، به جزئیات ارتباطات و نحوه استفاده از آن به عنوان پایه یک کار و پروژه جدید، خواهیم پرداخت.




به روز رسانی 1.1
جهت سازگاری با EF 6 ، StructureMap 3 و همچنین VS 2013، پروژه به روز شد: WpfFrmwork_1.1.zip

به روز رسانی نهایی
به روز شده‌ی این پروژه را بر اساس آخرین وابستگی‌های آن از اینجا دریافت کنید.
مطالب
PowerShell 7.x - قسمت هفتم - غنی‌سازی PowerShell
غنی‌سازی پاورشل
PowerShell توسط اپلیکیشن‌های مختلفی مانند VS Code یا Console قابل میزبانی است. با کمک این اپلیکیشن‌ها، دستورات به موتور PowerShell ارسال میشوند. این موتور است که دستورات را دریافت کرده و آنها را اجرا میکند و در نهایت خروجی، درون این اپلیکشن‌های میزبان، نمایش داده خواهند شد. علاوه بر آن، یک اپلیکیشن میزبان، مسئولیت بارگذاری و اجرای اسکریپت‌ها را با هربار اجرای شل، بر عهده دارد. درون این اسکریپت‌ها، فرصت این را خواهیم داشت تا ماژول‌های موردنیازمان را بارگذاری کنیم؛ دایرکتوری پیش‌فرض را تغییر دهیم، یکسری توابع را تعریف و یا فراخوانی کنیم. بنابراین این امکان را داریم تا موتور PowerShell را درون یک پراسس NET. میزبانی کنیم. در این‌حالت باید خودمان Input/Output را هندل کنیم. به عنوان مثال میتوانیم Error streams را درون یک Message Box نمایش دهیم، یا اینکه Information streams را درون یکسری RichText Box نمایش دهیم. در اینجا میتوانید مراحل پیاده‌سازی یک نمونه Host سفارشی را مشاهده کنید. 
برای مشاهده‌ی مشخصات اپلیکیشن میزبان میتوانید از دستور Get-Host یا از متغیر خودکار host$ نیز استفاده کنید: 
PS /> Get-Host

Name             : ConsoleHost
Version          : 7.3.0
InstanceId       : c3f625f0-dad8-4325-a0a1-f6499afecb8a
UI               : System.Management.Automation.Internal.Host.InternalHostUserInte
                   rface
CurrentCulture   : en-GB
CurrentUICulture : en-GB
PrivateData      : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
DebuggerEnabled  : True
IsRunspacePushed : False
Runspace         : System.Management.Automation.Runspaces.LocalRunspace
یکسری از بخش‌های Host نیز درون سشن جاری، قابل سفارشی‌سازی هستند؛ به عنوان مثال: 
Function Write-Color {
    Param (
        [ValidateNotNullOrEmpty()]
        [string] $newColor
    )
    $oldColor = $host.UI.RawUI.ForegroundColor
    $host.UI.RawUI.ForegroundColor = $newColor
    If ($args) {
        Write-Output $args
    }
    Else {
        $input | Write-Output
    }
    $host.UI.RawUI.ForegroundColor = $oldColor
}
سفارش‌سازی Prompt
حالت پیش‌فرض نمایش prompt اینچنین است: 
# macOS
PS /{current_dir}>

# Windows
PS C:\>
این نحوه نمایش، توسط تابعِ خودکار Prompt تعیین میشود. این تابع قابل بازنویسی نیز میباشد و خروجی آن میتواند یک شیء یا یک رشته باشد. اما توصیه میشود خروجی به صورت یک رشته‌ی فرمت شده برگردانده شود: 
PS /> function prompt { "Hello, World > " }                 
Hello, World >
منظور از شیء نیز این است که حتی خروجی تابع Prompt میتواند اینچنین نیز باشد: 
PS /> Function prompt { Get-Process Slack }
در اینحالت خروجی که درون Prompt نمایش داده میشود، پیاده‌سازی پیش‌فرض متد ToString شیء استفاده شده خواهد بود: 
System.Diagnostics.Process (Slack)
بنابراین خروجی را میتوانید به هر حالتی که بخواهید نمایش دهید. به عنوان مثال در ادامه یک رشته‌ی فرمت شده را که حاوی زمان جاری، به همراه نام کامپیوتر میزبان است، بجای Prompt نمایش داده‌ایم: 
function prompt { 
$time = (Get-Date).ToShortTimeString() 
"$time $([net.dns]::GetHostName()):> "
}

# eg: 
11:00 Sirwans-MacBook-Pro.local:>
یک مثال دیگر نیز نمایش اطلاعات Git، درون پوشه‌ی جاری میباشد: 
Function Write-Branch {
    If (Test-Path .git) {
        $branch = git branch --show-current
        $lastCommitAuthor = git log -1 --pretty=format:"%an"
        If ($null -ne $lastCommitAuthor) {
            Return "($branch - latest commit written by 🤦👉 $lastCommitAuthor)"
        }
        Return "($branch)"
    }
    Else {
        "Not in a git repo"
    }
}


Function Prompt {
    $CurrentDirectory = Split-Path -Path $pwd -Leaf
    Write-Host "`nPS " -NoNewline -ForegroundColor Cyan
    Write-Host $($CurrentDirectory) -NoNewline -ForegroundColor Green
    Write-Host " $(Write-Branch) " -NoNewline -ForegroundColor Yellow
    Return '> '
}
در کد فوق ابتدا یک تابع را برای استخراج متادیتای گیت تهیه کرده‌ایم. ابتدا بررسی شده‌است که درون دایرکتوری جاری گیت، initialise شده باشد. سپس توسط دستور git branch —show-current برنچ جاری را دریافت کرده و به یک متغیر انتساب داده‌ایم. در ادامه با کمک git log آخرین کامیت (با کمک 1-) را استخراج کرده‌ایم. در ادامه درون تابع Prompt، دایرکتوری جاری را دریافت کرده و در نهایت آن را با نتیجه‌ی فراخوانی تابع Write-Branch ادغام کرده‌ایم: 


ذخیره‌سازی تقییرات شل درون پروفایل

نکته‌ایی که باید به آن دقت داشته باشید این است که تغییرات، تنها برای سشن جاری ذخیره خواهند شد و به محض بستن سشن، این تغییرات از حافظه پاک خواهند شد. همانطور که در قسمت قبل نیز اشاره شد، برای اینکه تغییرات را همیشه موقع باز کردن شل مشاهده کنیم، باید کدها را درون پروفایل ذخیره کنیم. به این معنا که هر وقت PowerShell را باز کنیم، توابع و کدهایی که درون پروفایل تعریف شده باشند، به صورت سراسری قابل استفاده خواهند بود. توسط متغیر خودکار Profile$ میتوانیم پروفایل جاری را مشاهده کنیم:  

PS /> $Profile

{HOME_USER}/.config/powershell/Microsoft.PowerShell_profile.ps1

دقت داشته باشید که پرفایل فوق، برای Host جاری و همچنین کاربر جاری میباشد. به این معنا که محتویات داخل این پروفایل، تاثیری در دیگر شل‌هایی که توسط اپلیکیشن‌های دیگر میزبانی میشوند ندارد. توسط دستور زیر میتوانید لیست پروفایل‌ها را مشاهده نمائید: 

PS /> $PROFILE | Get-Member -Type NoteProperty | Select-Object Name, Value

Name                   Value
----                   -----
AllUsersAllHosts
AllUsersCurrentHost
CurrentUserAllHosts
CurrentUserCurrentHost

مسیر هر کدام از پروفایل‌های فوق را میتوانید در اینجا مشاهده نمائید. همچنین توسط پرچم NoProfile- میتوانیم PowerShell را بدون بارگذاری هیچ پروفایلی باز کنیم: 

pwsh -NoProfile

بنابراین برای ذخیره‌ی تغییرات قبل، میتوانیم توابع تعریف شده را درون پروفایل موردنظر قرار دهیم، تا با هربار باز شدن سشن، کدهای موردنظر قابل استفاده باشند: 

PS /> code $PROFILE.CurrentUserCurrentHost

Function Write-Branch {
    # As before
}


Function Prompt {
    # As before
}

اگر از ماژول Posh برای تغییر ظاهر PowerShell استفاده کرده باشید، متوجه خواهید شد که این ماژول نیز به همین روال کار میکند؛ یعنی با هربار باز شدن سشن، این دستور برای بارگذاری Prompt سفارشی فراخوانی خواهد شد: 

oh-my-posh init pwsh | Invoke-Expression


مطالب
مدیریت سشن‌ها در برنامه‌های وب به کمک تزریق وابستگی‌ها
سشن‌ها در برنامه‌های وب، یکی از وابستگی‌های استاتیکی هستند که می‌توان آن‌ها را از طریق تزریق وابستگی‌ها، جهت بالا بردن قابلیت آزمون پذیری برنامه، تامین کرد. همچنین اگر از سشن‌ها برای نمونه در برنامه‌های ASP.NET MVC استفاده کنید، مقدار آن‌ها در سازنده‌ی کنترلرها نال خواهند بود؛ از این جهت که در زمان نمونه سازی یک کنترلر توسط IoC Container، کار مدیریت سشن‌ها صورت نمی‌گیرد و اگر در این بین سرویسی نیاز به سشن داشته باشد، دیگر وهله سازی نخواهد شد؛ به این دلیل که صرفنظر از مقدار دهی متغیر سشن در صفحه‌ای دیگر، این مقدار در سازنده‌ی کلاس، نال است. در ادامه این مشکل را از طریق غنی سازی تزریق وابستگی‌ها با اطلاعات سشن جاری، برطرف خواهیم کرد.


طراحی یک تامین کننده‌ی عمومی سشن

public interface ISessionProvider
{
    object Get(string key);
    T Get<T>(string key) where T : class;
    void Remove(string key);
    void RemoveAll();
    void Store(string key, object value);
}
در اینجا یک اینترفیس عمومی را مشاهده می‌کنید که کار آن کپسوله سازی اعمال متداول کار با سشن‌ها است؛ برای مثال دریافت اطلاعات یک سشن، بر اساس کلیدی مشخص و یا ذخیره سازی اطلاعات اشیاء در سشن‌ها.
یک نمونه پیاده سازی عمومی آن نیز برای کار با سشن‌ها در برنامه‌های وب ASP.NET وب فرم و MVC، می‌تواند به صورت زیر باشد:
public class DefaultWebSessionProvider : ISessionProvider
{
    private readonly HttpSessionStateBase _session;
 
    public DefaultWebSessionProvider(HttpSessionStateBase session)
    {
        _session = session;
    }
 
    public object Get(string key)
    {
        return _session[key];
    }
 
    public T Get<T>(string key) where T : class
    {
        return _session[key] as T;
    }
 
    public void Remove(string key)
    {
        _session.Remove(key);
    }
 
    public void RemoveAll()
    {
        _session.RemoveAll();
    }
 
    public void Store(string key, object value)
    {
        _session[key] = value;
    }
}
در کلاس DefaultWebSessionProvider مستقیما از HttpContext.Current.Session برای دسترسی به سشن جاری استفاده نشده‌است. این مقدار را از سازنده‌ی خود که توسط کلاس پایه HttpSessionStateBase تامین می‌شود، دریافت خواهد کرد. این سازنده را توسط تنظیمات ابتدایی IoC Container خود وهله سازی و مقدار دهی می‌کنیم؛ زیرا HttpContext.Current.Session برای مقدار دهی، نیاز به راه اندازی یک وب سرور دارد و عملا استفاده و شبیه سازی از آن در بسیاری از آزمون‌های واحد، بسیار مشکل خواهد بود.
private static Container defaultContainer()
{
    return new Container(ioc =>
    {
        // session manager setup
        ioc.For<ISessionProvider>().Use<DefaultWebSessionProvider>();
        ioc.For<HttpSessionStateBase>()
           .Use(ctx => new HttpSessionStateWrapper(HttpContext.Current.Session)); 
 
        ioc.Policies.SetAllProperties(properties =>
        {
            properties.OfType<ISessionProvider>();
        });
    });
}
در مثال فوق یک نمونه از تنظیمات ابتدایی StructureMap را برای استفاده از مقدار HttpContext.Current.Session، جهت وهله سازی سازنده‌ی کلاس DefaultWebSessionProvider مشاهده می‌کنید.


استفاده از تامین کننده‌ی سفارشی سشن در برنامه

پس از طراحی تامین کننده‌ی سفارشی سشن و همچنین معرفی آن به IoC Container خود، اکنون استفاده‌ی از آن به سادگی ذیل است:
public class HomeController : Controller
{
    private readonly ISessionProvider _sessionProvider;
    public HomeController(ISessionProvider sessionProvider)
    {
        _sessionProvider = sessionProvider;
    }
بنابراین اگر در کلاسی، کنترلری و یا سرویسی نیاز به سشن وجود داشت، بهتر است از ISessionProvider بجای مقدار دهی و یا دسترسی مستقیم به شیء استاتیک Session استفاده کرد.
مطالب
ایجاد چارت سازمانی تحت وب #4 - آخر
نما : Layout
در یک نمودار یا چارت سازمانی در حد امکان شاخه‌ها همواره در کنار هم و جمع و جور رسم میشوند. در مثال زیر نود u-Node 1 و u-Node 3 دارای زیر شاخه نبوده ، بنابراین نیازی به فضای زیرین جهت نمایش ندارند. جهت مشاهده این فضا میتوانید خط مشخص شده در کد را فعال نمائید و تفاوت فضای مورد نیاز و ایجاد شده را ببینید.
دو درخت نمودار متفاوت در کنار هم رسم شده اند. هیچ همپوشانی بین درختان رسم شده وجود ندارد ( بنابراین نود Root 2 روی نود u-Node 3  رسم نشده است.


var o = new orgChart();

o.addNode( 0, '', '', 'Root 1');
o.addNode( 1,  0, 'u', 'u-Node 1');
o.addNode( 2,  0, 'u', 'u-Node 2');
o.addNode( 3,  0, 'u', 'u-Node 3');
o.addNode( 4,  0, 'u', 'u-Node 4');
//میتوانید خط زیر را فعال نمائید تا تفاوت فضای ایجاد شده و مورد نیاز را مشاهده نمائید.
 //o.addNode( 9, 3, 'u', 'EXTRA', 0, '', '#CC0000', '#FF0000'); o.addNode(11, 2, 'l', 'l-Node'); o.addNode(12, 2, 'u', 'u-Node'); o.addNode(13, 2, 'u', 'u-Node'); o.addNode(14, 2, 'r', 'r-Node'); o.addNode(20, 4, 'l', 'l-Node'); o.addNode(21, '', '', 'Root 2'); o.drawChart('c_layout');
یک مثال کامل :
نمونه زیر یک مثال کامل میباشد. انواع اتصالهای تو در تو چندگانه در این نمونه استفاده شده است .


این هم کد نمونه فوق :

var o = new orgChart();

o.setFont('Arial', 18);
o.addNode( 0, '', '', 'President', 1);

o.setFont('Arial', 12);
o.addNode('',  0, 'l', 'Control');
o.addNode('',  0, 'l', 'Secretary');
o.addNode('',  0, 'l', 'Marketing');
o.addNode('',  0, 'l', 'Human resources');

o.setColor('#99CC99', '#CCFFCC');
o.addNode(12,  0, 'r', 'Facility');
o.addNode('', 12, 'r', 'IT');
o.addNode('', 12, 'r', 'Resource planning');

o.setFont('Arial', 18);
o.setColor('#CCCC66', '#FFFF99');
o.addNode(20,  0, 'u', 'Projects', 1);

o.setFont('Arial', 12);
o.addNode('', 20, 'r', 'Management');
o.addNode('', 20, 'r', 'Finance');
o.addNode('', 20, 'l', 'Development');
o.addNode('', 20, 'l', 'Maintenance');
o.addNode('', 20, 'l', 'Specials');

o.setColor('#CC4950', '#FF7C80');
o.setFont('Arial', 18);
o.addNode(30,  0, 'u', 'Specials', 1);

o.setFont('Arial', 12);
o.addNode(31, 30, 'l', 'Management');
o.addNode('', 30, 'l', 'Communication');
o.addNode(33, 30, 'r', 'Development');
o.addNode(34, 33, 'r', 'Maintenance');
o.addNode('', 33, 'r', 'Special A');
o.addNode('', 33, 'r', 'Special B');
o.addNode('', 33, 'r', 'Advice');
o.addNode('', 30, 'l', 'Taskforce');

o.setColor('#CC9966', '#FFCC99');
o.setFont('Arial', 18);
o.addNode(40,  0, 'u', 'Programming', 1);

o.setFont('Arial', 12);
o.addNode(41, 40, 'l', 'Management');
o.addNode(42, 40, 'l', 'Finance');
o.addNode('', 40, 'r', 'Assessment');
o.addNode('', 40, 'r', 'Coding team');
o.addNode('', 40, 'r', 'Quality control');

o.drawChart('c_ex1', '', true);
اضافه کردن تصویر به نودها :
شما میتوانید به نودها تصویر دلخواه خود را نیز اضافه نمائید. تصاویر بصورت عمودی قرار خواهند گرفت و در صورتی که بزرگ باشند تغییر اندازه خواهند داد. ( فراخوانی تابع setSize قبل از اضافه کردن عکس در این مثال )

کدهای مثال فوق :

var o = new orgChart();

o.setSize(120, 60);

o.setFont('Arial', 18);
o.addNode( 1, '', '', 'Icon smiley', 0, '', '', '', '', 'pic/smiley.gif');
o.addNode( 2, '', '', 'This is a tree', 0, '', '', '', '', 'pic/tree.jpg');
o.addNode( 3, 2, 'u', 'This is a tree');
o.addNode( 4, '', '', 'Right Top smiley', 0, '', '', '', '', 'pic/smiley.gif', 'rt');
o.addNode( 5, '', '', 'Center bottom smiley', 0, '', '', '', '', 'pic/smiley.gif', 'cb');

o.drawChart('c_img');

یک مثال دیگر از استفاده تصاویر در چارت :


var o = new orgChart();

o.setSize(60, 110);

o.setFont('Arial', 12);
o.addNode( 1, '', '', 'Hominidae');
o.addNode( 10, 1, 'l', 'Hominidae');
o.addNode( 11, 10, 'l', 'Hominini');
o.addNode( 12, 10, 'r', 'Gorillini');
o.addNode( 20, 1, 'r', 'Ponginae');
o.addNode( '', 11, '', 'Homo Sapiens', '', '', '', '', '', 'pic/homo.jpg', 'ct');
o.addNode( '', 11, '', 'Pan', '', '', '', '', '', 'pic/pan.jpg', 'ct');
o.addNode( '', 12, '', 'Gorilla', '', '', '', '', '', 'pic/gorilla.jpg', 'ct');
o.addNode( '', 20, '', 'Pongo', '', '', '', '', '', 'pic/pongo.jpg', 'ct');

o.drawChart('c_img2', 'c');
تبدیل تصویر از فرمت jpg به تصویر با فرمت png :
عدم امکان استفاده از مرورگر IE تا نسخه 8 ، چرا که IE  هیچ پشتیبانی از toDataURL در excanvas.js  را انجام نمیدهد.
شما میتوانید از توابع استاندارد canvas در جهت تبدیل محتویات canvas به تصویر استاتیک استفاده نمائید. برای اینکه بتوانید این کار را تست نمائید باید کد ذیل را در همان صفحه ای که کد ( یک مثال کامل ) را استفاده کردید درج نمائید و در این صورت با کلیک بر روی لینک اول میتوانید یک تصویر با فرمت png در یک صفحه جدید از نمودار خود بدست بیاورید و یا با کلیک بر روی لینک دوم یک تصویر را دانلود نمائید.
<script type="text/javascript">
function openAsPng(id){
        window.open(document.getElementById(id).toDataURL("image/png"));
}
function saveAsPng(id){
var img = document.getElementById(id).toDataURL("image/png");
        document.location.href = img.replace("image/png", "image/octet-stream");
}
</script>

<a href = "javascript:openAsPng('c_ex1');">Click here to open the image as png in a new window</a><BR>
<a href = "javascript:saveAsPng('c_ex1');">Click here to save the image as png</a><BR>

نمایش چارت فقط بصورت یک تصویر :

برای اینکه بتوانید یک چارت ایجاد شده از این روش را فقط بصورت یک تصویر نمایش دهید باید عمل تبدیل به عکس را بلافاصله پس از رسم نمودار در canvas انجام دهید بدین صورت که در کد ذیل مشاهده مینمائید:
<canvas id="c_pngchart" width="1" height="1">Your browser does not support canvas!</canvas>

<img id="pngchart">
<script type="text/javascript">
var o = new orgChart();
o.addNode(0, '', '', 'Root');
o.addNode(1, 0, 'u', 'u-Node 1');
o.addNode(2, 0, 'u', 'u-Node 2');
o.drawChart('c_pngchart', '', true);
var canvas = document.getElementById('c_pngchart');
document.getElementById("pngchart").src = canvas.toDataURL("image/png");
// The html keyword "hidden" doesn't work in IE, so resize the canvas to NUL
canvas.height = 0;
canvas.width = 0;
</script>

همه لینکهایی که در نودها ایجاد شده است غیرفعال شده و از کار می‌افتند. بنابراین برای انجام این کار ،یک المنت تصویر در صفحه خود ایجاد ، نمودار را در canvas رسم نموده ، نمودار را به تصویر تبدیل نموده و آن را به المنت تصویر مقید میکنیم و در آخر canvas مخفی میکنیم. برای این منظور از کلید واژه hidden  استفاده میکنیم که در IE این کلمه باز قابل شناسایی نبوده و باید از روش تخصیص اندازه طول و عرض صفر 0 استفاده شود یعنی width=0 , height=0

تصویر فوق ایجاد شده کد مورد نظر میباشد.

تغییر اندازه پویا :
اگر بخواهید بصورت پویا اندازه canvas را تغییر دهید ، نمودار شما ناپدید میشود و پس از تغییر اندازه ، نمودار پاک خواهد شد.
برای رسم نمودار باید دوباره از توابع drawChart() یا redrawChart()   استفاده نمائید.
برای رسم نودها نیازی به تعریف دوباره آنها نمیباشد ( مخصوصا در مثالی که در این صفحه برای شما ارائه شده است )
تابع ()drowChart تمامی نودها را در زمان رسم دوباره جاگذاری میکند ، در صورتی که اگر شما میدانید چارت شما به غیر از اندازه هیچ تغییر دیگری نداشته میتوانید با فراخوانی تابع redrawChart  یک کپی از همان چارت را که در حافظه canvas وجود دارد را رسم نمائید.
از تمامی دوستان خوبم تشکر میکنم که این مطلب را دنبال نمودند . ما را از نظرات خوب و سازنده خود بی نصیب نفرمائید.

اشتراک‌ها
انتشار Azure Data Studio نگارش ماه May

The key highlights to cover this month include:

  • Announcing the Schema Compare extension
  • Changed location of tasks view
  • Added welcome page
  • Notebook improvements
  • Bug fixes 
انتشار Azure Data Studio نگارش ماه May
اشتراک‌ها
پیاده سازی صحیح الگوی PRG در ASP.NET MVC

خلاصه کار استفاده از دو اکشن فیلتر زیر برروی اکشن‌های GET و POST میباشد:

public abstract class ModelStateTransfer : ActionFilterAttribute  
{
    protected static readonly string Key = typeof(ModelStateTransfer).FullName;
}

public class ExportModelStateAttribute : ModelStateTransfer  
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        //Only export when ModelState is not valid
        if (!filterContext.Controller.ViewData.ModelState.IsValid)
        {
            //Export if we are redirecting
            if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
            {
                filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
            }
        }

        base.OnActionExecuted(filterContext);
    }
}

public class ImportModelStateAttribute : ModelStateTransfer  
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;

        if (modelState != null)
        {
            //Only Import if we are viewing
            if (filterContext.Result is ViewResult)
            {
                filterContext.Controller.ViewData.ModelState.Merge(modelState);
            }
            else
            {
                //Otherwise remove it.
                filterContext.Controller.TempData.Remove(Key);
            }
        }

        base.OnActionExecuted(filterContext);
    }
}
پیاده سازی صحیح الگوی PRG در ASP.NET MVC