با استفاده از
ScriptManager خیر! اما در مقالههای بعدی با روش دیگری توضیح خواهم داد.
یکی از دغدغههای جدی امروزه توسعه دهندگان نرم افزار در سمت Front end، توسعه برنامههای Cross Platform است. در این سری آموزشی به صورت قدم به قدم و پروژه محور میخواهیم برنامهای را برای Android/iOS/Windows توسعه دهیم که روی کامپیوتر، تبلت و موبایل به خوبی کار کند.
انتخاب ابزار درست برای شروع به کار از اهمیت شایانی برخوردار است و بد نیست در ابتدا به بررسی دلایل انتخاب ابزارهایی بپردازیم که قرار است در این دوره از آنها استفاده شود.
۱- زبان برنامه نویسی: CSharp
CSharp با وجود امکاناتی مانند Generics، Lambda Expressions، Linq، Async و ... که تا حدودی در سایر زبانها هم هستند، زبانی خوش ساختار و کاربردی است. همچنین اضافه شدن امکانات جدیدی مانند ref returns و ... نشان دهنده این است که این زبان رو به جلو در حرکت و در برخی موارد پیشرو است. اما در توسعه یک برنامه Cross Platform مواردی اهمیت پیدا میکنند که شاید توسعه دهنده نرم افزار مستقیما با آنها درگیر نشود، ولی از آنها تاثیر میپذیرد. در زبان CSharp مواردی مانند P/Invoke ،Pointers، Extern و ... جزء این دست از موارد هستند که کمک میکنند CSharp به یکی از لذت بخشترین زبان هایی تبدیل شود که قابلیت فراخوانی 100% امکانات زبانهای دیگر را بدون اما و اگرهای فراوان داشته باشد.
در سایر زبانهای Cross Platform اگر کتابخانههای توسعه داده شده و ترکیب زبانهای برنامه نویسی استفاده شده در آنها را بررسی کنید، میبینید که اگر قرار است کتابخانه مربوطه مثلا در JavaScript استفاده شود، توسعه دهنده کد، درصدی از کد را با Java، درصدی را با Swift و درصدی را با JavaScript توسعه داده است! اگر معادل همان کتابخانه را برای CSharp پیدا کنید، میبینید که تمامی قسمتهای مربوط به اندروید، iOS و ویندوز به زبان CSharp است.
برای مثال در ادامه کدهای مربوط به پروژهای را میبینید که هدف آن، ارائه متدهایی ساده برای کار با امکانات مختلف دستگاه، به صورت Cross Platform هست. مثلا برای بررسی وضعیت باطری بنویسید:
var state = Battery.State; // Charging, Full, Discharging, ...
که تماما با CSharp توسعه داده شده است.
اما معادل چنین پروژهای در هیچ زبان دیگری به صورت 100% با خود آن زبان توسعه داده نشدهاست و بیشتر مواقع با چنین چیزی مواجه میشوید:
این مسئله وقتی حائز اهمیت میشود که در پروژهتان به سمت کارهایی حرکت کنید که کمی خاص باشند و نتوانید کتابخانهای را پیدا کنید که نیازهای شما را پوشش دهد و یا از کیفیت خوبی برخوردار نباشد و ... و خلاصه بخواهید کمی بیشتر دست به کد شوید. در چنین مواقعی شما عملا درگیر چندین زبان و محیط توسعه و سیستم عامل و Debugger و ... میشوید. به هر میزان که برنامه شما خاص باشد، این هزینه افزایش پیدا میکند تا جایی که ممکن است ادامه توسعه نرم افزار را غیر ممکن کند.
در CSharp شما به صد در صد امکانات سیستم عاملها (Android/iOS/Windows/Linux/Mac/Tizen) دسترسی دارید.
۲- اجرا کننده برنامه: NET.
انتخاب NET. و کتابخانههای آن مانند Task Parallel Library - Entity Framework(Sqlite) - Noda - JSON.NET که در هر زمینهای بالاترین کیفیت ممکن را به شما ارائه میکنند به خودی خود منطقی به نظر میرسد. اما تمامی اینها در کنار سرعت اجرای NET. به صورت Native و همچنین قابلیت اجرای NET. در تمامی سیستم عاملها و همچنین امکان اجرای آن در مرورگر به کمک استاندارد Web Assembly آن را به انتخابی فوق العاده بدل میکند. سرعت گسترش محبوبیت و استفاده از NET. در دنیا نیز دلیل دیگری است برای اطمینان خاطر از انتخاب درست.
۳- Xamarin forms
Xamarin forms همه آن چیزهای پایهای است که برای نوشتن یک برنامه لازم داریم. کنترل هایی مانند ListView، Button و ...به همراه Binding - Navigation و ...
در عمل میتوانید آن را معادل Angular & Angular Material بدانید. وقتی شما فرمی را با Xamarin Forms توسعه میدهید و درون آن دکمهای است که از فرم اول، شما را به فرم دوم میبرد، میتوانید آن را در هر جایی که Xamarin forms پشتیبانی میکند، استفاده کنید. پشتیبانی Xamarin forms برای Android/iOS/Windows خوب و برای Linux/Mac/Tizen و Web در مراحل اولیه است.
در Xamarin forms شما UI کاملا Native خواهید داشت.
۴- Prism Patterns & practices
Prism همه آن چیزی است که برای نوشتن یک برنامه با کیفیت، با قابلیت نگهداری بالا و تست پذیر احتیاج داریم.
با نقش Bit و کمکهای آن در طول مسیر آموزش بیشتر آشنا خواهیم شد.
در قسمتهای بعدی به آموزش نصب و نحوه دیباگ کردن کد و ارائه پابلیش در Android-iOS-Windows خواهیم پرداخت و سپس وارد کدنویسی شده و پروژه اولیه را خواهیم ساخت و در قسمتهای بعد از آن هم کار با دیتابیس کلاینت ساید، ارتباط با سرور و ... را آموزش میبینیم.
اگر قبلا Xamarin Forms را تست کردهاید و به علت مسائلی مانند حجم بالای خروجی برنامه و یا کندی در توسعه برنامه یا اجرای آن در دستگاه مشتری آن را کنار گذاشتهاید، توصیه میکنم بار دیگر آن را با ما تست کنید و با رعایت چند نکته ساده از نوشتن برنامه Cross Platform به بهترین شکل لذت ببرید و خروجی خوبی را در نهایت به مشتریان سیستم ارائه کنید.
پیشنهادها
C# 7 - Ref Returns and Ref Locals
Ref Returns In C# 7.0
Why ref locals allow only a single binding
C# 7.0 – Ref returns and Locals
C# 7 Feature Proposal: Ref Returns and Locals
C# 7.0 Out Vars and Ref Returns
C#7: Better Performance with Ref Locals, and Ref and Async Returns
مستندات رسمی
Why ref locals allow only a single binding
C# 7.0 – Ref returns and Locals
C# 7 Feature Proposal: Ref Returns and Locals
C# 7.0 Out Vars and Ref Returns
C#7: Better Performance with Ref Locals, and Ref and Async Returns
مستندات رسمی
پیش از ارائه نهایی مطلب، تمام کدهای آن با VS 2017 RTM آزمایش و بررسی شوند.
اشتراکها
لیست تغییرات جدید ASP.NET Core 5.0
عناوین برخی از امکانات و بهبود ها
- MVC model binding improvements, including support for C# 9 record types
- Blazor Server & Blazor WebAssembly support and improvements
- Built-in OpenAPI and Swagger UI support for Web APIs
- SignalR Hub filters and parallel Hub invocations
- Azure AD authentication with MIcrosoft.Identity.Web
- Auto browser refresh with dotnet watch
- HTTP/2 and gRPC performance improvements
بعد از مطالعه پستهای ^ و ^ نکته ای به ذهنم رسید که بیان آن از بنده و مطالعه آن توسط شما خالی از لطف نیست. اگر مثالهای پیاده سازی شده در پستهای ^ و ^ را با AngularJs نسخه 1.2 اجرا نمایید به طور حتم با خطا روبرو میشوید و نتیجه مورد نظر حاصل نمیشود. در این پست نیز توسط یکی از دوستان اشاره ای به این مطلب شد.
دلیل خطا این است که از نسخه 1.2 به بعد در Angular سیستم مسیر یابی به این شکل امکان پذیر نیست و بخش مسیریابی به یک فایل دیگر به نام angular-route.js منتقل شده است. در نتیجه اگر به سبک نسخههای قبلی Angular از سیستم مسیریابی استفاده نمایید با خطا مواجه خواهید شد و خطای مورد نظر هم مربوط به عدم توانایی در تزریق وابستگی routeProvider$ به ماژول مورد نظر است. حال راه حل چیست؟
کافیست در هنگام تعریف ماژول، ngRoute را به عنوان وابستگی ماژول تعیین نمایید. و از طرفی فایل اسکریپتی angular-route.js را بعد از angular.js فراخوانی کنید.
بررسی مثال:
کدهای زیر مربوط به مثالهای پست قبلی میباشد که شرح کامل آن در این پست است:
دلیل خطا این است که از نسخه 1.2 به بعد در Angular سیستم مسیر یابی به این شکل امکان پذیر نیست و بخش مسیریابی به یک فایل دیگر به نام angular-route.js منتقل شده است. در نتیجه اگر به سبک نسخههای قبلی Angular از سیستم مسیریابی استفاده نمایید با خطا مواجه خواهید شد و خطای مورد نظر هم مربوط به عدم توانایی در تزریق وابستگی routeProvider$ به ماژول مورد نظر است. حال راه حل چیست؟
کافیست در هنگام تعریف ماژول، ngRoute را به عنوان وابستگی ماژول تعیین نمایید. و از طرفی فایل اسکریپتی angular-route.js را بعد از angular.js فراخوانی کنید.
بررسی مثال:
کدهای زیر مربوط به مثالهای پست قبلی میباشد که شرح کامل آن در این پست است:
var myFirstRoute = angular.module('myFirstRoute', []); myFirstRoute.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/pageOne', { templateUrl: 'templates/page_one.html', controller: 'ShowPage1Controller' }). when('/pageTwo', { templateUrl: 'templates/page_two.html', controller: 'ShowPage2Controller' }). otherwise({ redirectTo: '/pageOne' }); }]); myFirstRoute.controller('ShowPage1Controller', function($scope) { $scope.message = 'Content of page-one.html'; }); myFirstRoute.controller('ShowPage2Controller', function($scope) { $scope.message = 'Content of page-two.html'; });
var myFirstRoute = angular.module('myFirstRoute',['ngRoute']); myFirstRoute.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/pageOne', { templateUrl: 'templates/page_one.html', controller: 'ShowPage1Controller' }). when('/pageTwo', { templateUrl: 'templates/page_two.html', controller: 'ShowPage2Controller' }). otherwise({ redirectTo: '/pageOne' }); }]);
<body ng-app="app"> <div> <div> <div> <ul> <li><a href="#pageOne"> Show page one </a></li> <li><a href="#pageTwo"> Show page two </a></li> </ul> </div> <div> <div ng-view></div> </div> </div> </div> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="angular-route.js"></script> <script src="app.js"></script> </body>
نظرات مطالب
ASP.NET MVC #18
قسمت type مشکلی نداره، breakpoint رو وقتی داخل متد GetRolesForUser قرار میدم فراخوانی میشه ولی چون مقدار Id صفر درنظر گرفته شده نمیتونه Role موردنظر رو برای این Id توی دیتابیس پیدا کنه، موقع لاگین فقط UserName و Password توسط سیستم Binding یرای متد Login فرستاده میشه :
وقتی در فرم لاگین هم به صورت دستی Id رو ارسال میکنم، باز هم پیام Attempted to perform an unauthorized operation. دریافت میکنم. آیا تغییری دیگری در View لاگین نیاز هست اعمال بشه؟
از آنجا که الکترون از مفاهیم وب در دسکتاپ به خوبی پشتیبانی میکند، پس به راحتی میتوان از کتابخانههای تحت وب و جاوااسکرپیتی چون جی کوئری و آنگولار و ... استفاده کرد. پروژهای داریم که در آن، حین باز شدن صفحه، به کاربر پیام خوش آمد گویی نشان داده میشود:
<!DOCTYPE html> <html> <head> <script src="./jquery.min.js"></script> <meta charset="utf-8"> <title></title> <script> $(document).ready(()=> { alert("Welcome"); }); </script> </head> <body> </body> </html>
برنامه را اجرا میکنیم و در کمال تعجب میبینیم که پیامی نمایش داده نمیشود. برای اینکه بتوانیم اشکال آن را پیدا کنیم بهتر است ابزارهای سودمند توسعه و دیباگینگ کرومیوم را فراخوانی کنیم. برای باز کردن این پنجره، بعد از ایجاد شیء پنجره (فرضا نام متغیر win باشد) عبارت زیر را مینویسیم:
win.openDevTools();
برنامه را بار دیگر اجرا کنید. در سمت راست برنامه یک پنجره جدید باز میشود تا بتوانید از طریق آن به دیباگینگ Render Process بپردازید. اگر اینبار به پنجره کنسول نگاهی بیندازید متوجه میشوید که خطای داده شده به دلیل عدم شناخت $ بوده است؛ در صورتی که همه چیز به طور صحیح قرار گرفته است و در یک صفحه وب عادی خیلی راحت اجرا میشود، پس مشکل از کجاست؟
module و module.exports
در اکثر کتابخانههای جاوااسکریپتی شما با عبارت require زیاد مواجه شدهاید و این امکان از طریق شیءایی به نام module.exports امکان پذیر شده است. شما با کدی مشابه زیر:
module و module.exports
در اکثر کتابخانههای جاوااسکریپتی شما با عبارت require زیاد مواجه شدهاید و این امکان از طریق شیءایی به نام module.exports امکان پذیر شده است. شما با کدی مشابه زیر:
exports.sayHelloInEnglish=()=> { console.log("hello"); } exports.sayHelloInPersian=()=> { console.log('salam'); }
const test=require("./test.js"); test.sayHelloInPersian(); test.sayHelloInEnglish();
همانطور که میبینید شیء module.exports از این طریق میتواند در دسترس دیگران قرار بگیرد. حالا جی کوئری و هر کتابخانه مشابهی که کدی شبیه به کد زیر را داشته باشد میتواند به چنین مشکلی دچار شود:
کد بالا بررسی میکند که آیا module.export وجود دارد یا خیر. اگر وجود داشته باشد، در اختیار آن قرار میگیرد و اگر نداشته باشد در اختیار شیء window قرار میگیرد. پس کاری که جی کوئری اینجا انجام میدهد این است که توابع آن در اختیار شیء window نیست و در اختیار exports است. به همین علت ما باید شیء جی کوئری را از طریق آن دریافت کنیم. پس کد زیر را قبل از کدهای جی کوئری مینویسیم:
if ( typeof module === "object" && typeof module.exports === "object" ) { // set jQuery in `module` } else { // set jQuery in `window` }
کد بالا بررسی میکند که آیا module.export وجود دارد یا خیر. اگر وجود داشته باشد، در اختیار آن قرار میگیرد و اگر نداشته باشد در اختیار شیء window قرار میگیرد. پس کاری که جی کوئری اینجا انجام میدهد این است که توابع آن در اختیار شیء window نیست و در اختیار exports است. به همین علت ما باید شیء جی کوئری را از طریق آن دریافت کنیم. پس کد زیر را قبل از کدهای جی کوئری مینویسیم:
<script src="./jquery.min.js"></script> <script> window.$=window.jQuery=module.exports; </script>
window.$ = window.jQuery = require('./jquery.min.js');
Vue.js چیست؟
ویوجیاس یا وو جی اس (Vue.js) یکی از فریمورکهای جاوااسکریپتی است که به ما در ساختن اپلیکیشنهای تحت وب و تحت معماری MVVM یا همان (Model–view–viewmodel) کمک میکند.
در حالیکه مدت کمی از انتشار Vue.js میگذرد، اما این فریمورک به شدت محبوب شده و طرفداران زیادی پیدا کرده است.
پیشنیازها :
- آشنایی کامل با جاوااسکریپت
- آشنایی با Object-oriented در جاوااسکریپت
اولین قدم برای استفاده از Vue.js، نصب آن میباشد که مرحله به مرحله توضیح خواهم داد. جهت نصب، سایت Vue.js به ما چندین راه پیشنهاد میدهد که ما آنها را در ذیل بررسی میکنیم:
1- CDN
در قسمت CDN به آدرس زیر مراجعه کرده و لینک آن را در صفحهای که نیاز است از آن استفاده کنیم، قرار میدهیم. هرچندکه به صورت لوکال هم میتوانید کدها را در یک فایل ذخیره کرده و از آن استفاده کنید.
ابتدا باید آدرس زیر، درون تگ < script> قرار بگیرد
https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.0/vue.js
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.0/vue.js"></script>
2- NPM
طبق همین دستور میتوانید Vue.js را نصب کنید
$ npm install vue
3- CLI
با استفاده از کامند لاین هم به راحتی قابل نصب میباشد؛ با استفاده از دستورات زیر
$ npm install -g vue-cli $ vue init webpack my-project $ cd my-project $ npm install $ npm run dev
توجه: بهترین روش نصب، استفاده از CDN میباشد که توصیه میشود جهت سهولت و جلوگیری از دردسرهای نصب فریمورک، از مورد اول استفاده کنید.
حال پس از نصب، چنین کدی آماده خواهد شد.
<html> <body> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.0/vue.js"></script> </body> </html>
آخرین نسخه از ویو جی اس، 2.2.0 است.
با تشکر؛ علت اینکه تابع paginate در دل render نوشتید چی بوده؟ چرا آن را قبل از render ننوشتید؟ آیا فرقی میکند؟
AvalonEdit یکی از زیرساختهای برنامهی SharpDevelop است که ویرایشگر متنی به همراه syntax highlighting زبانهای مختلف را در آن پشتیبانی میکند. کیفیت بالایی داشته و بسیاری از برنامههای دیگر نیز از آن جهت ارائه ویرایشگر و یا syntax highlighting متون ارائه شده، استفاده میکنند. در ادامه نحوهی استفاده از این ویرایشگر را در برنامههای WPF خصوصا با دید MVVM بررسی خواهیم کرد.
دریافت و نصب AvalonEdit
برای نصب AvalonEdit میتوان دستور ذیل را در کنسول پاورشل نیوگت صادر کرد:
استفادهی مقدماتی از AvalonEdit
برای استفاده از این ویرایشگر ابتدا نیاز است فضای نام xmlns:avalonEdit تعریف شود. سپس کنترل avalonEdit:TextEditor در دسترس خواهد بود:
توسط خاصیت SyntaxHighlighting آن میتوان زبان مشخصی را تعریف کرد. لیست زبانهای توکار پشتیبانی شده
استفاده از AvalonEdit در برنامههای MVVM
خاصیت Text این ویرایشگر به صورت معمولی تعریف شده (DependencyProperty نیست) و امکان binding دو طرفه به آن وجود ندارد. به همین جهت نیاز است یک چنین DependencyProperty را به آن اضافه کرد:
کار با ارث بری از TextEditor (ویرایشگر AvalonEdit) شروع میشود. سپس یک DependencyProperty به نام BoundText در اینجا اضافه شدهاست. هر زمان که متن داخل آن تغییر کرد، آنرا به خاصیت متنی Text این ویرایشگر نسبت میدهد. به این ترتیب binding یک طرفه (از کدها به کنترل) کار میکند. فعال سازی binding دو طرفه با پشتیبانی از انتقال تغییرات از ویرایشگر به خواص ViewModel در متد بازنویسی شدهی OnTextChanged انجام میشود.
اکنون برای استفاده از این کنترل جدید که BindableAvalonTextEditor نام دارد، میتوان به نحو ذیل عمل کرد:
ابتدا فضای نام جدید کنترل BindableAvalonTextEditor مشخص میشود و سپس به controls:BindableAvalonTextEditor دسترسی خواهیم داشت. در اینجا نحوهی استفاده از خاصیت جدید BoundText را نیز مشاهده میکنید.
افزودن syntax highlighting زبانهایی که به صورت رسمی پشتیبانی نمیشوند
به خاصیت SyntaxHighlighting این کنترل صرفا مقادیری را میتوان نسبت داد که به صورت توکار پشتیبانی میشوند. برای مثال#XML، C و امثال آن.
فرض کنید نیاز است SyntaxHighlighting زبان SQL را فعال کنیم. برای اینکار نیاز به فایلهای ویژهای است، با پسوند xshd. برای نمونه فایل sql-ce.xshd را در اینجا میتوانید مطالعه کنید. در آن یک سری واژههای کلیدی و حروفی که باید با رنگی متفاوت نمایش داده شوند، مشخص میگردند.
برای استفاده از فایل sql-ce.xshd باید به نحو ذیل عمل کرد:
الف) فایل sql-ce.xshd را به پروژه اضافه کرده و سپس در برگهی خواص آن در VS.NET، مقدار build action آنرا به embedded resource تغییر دهید.
ب) با استفاده از متد ذیل، این فایل مدفون شده در اسمبلی را گشوده و به متد HighlightingLoader.Load ارسال میکنیم:
نحوه استفاده از آن نیز به صورت ذیل است:
به این ترتیب میتوان یک فایل xhsd را به صورت پویا بارگذاری و به خاصیت SyntaxHighlighting کنترل انتساب داد.
برای سهولت استفاده از این قابلیت شاید بهتر باشد یک DependencyProperty دیگر به نام SyntaxHighlightingResourceName را به کنترل جدید BindableAvalonTextEditor اضافه کنیم:
کاری که در اینجا انجام شده، افزودن یک خاصیت جدید به نام SyntaxHighlightingResourceName به کنترل BindableAvalonTextEditor است. هر زمانیکه مقدار آن تغییر کند، متد getHighlightingDefinition بحث شده، فراخوانی گردیده و به صورت پویا مقدار خاصیت SyntaxHighlighting این کنترل، مقدار دهی میشود.
استفاده از آن نیز به شکل زیر است:
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید:
AvalonEditWpfTest.zip
دریافت و نصب AvalonEdit
برای نصب AvalonEdit میتوان دستور ذیل را در کنسول پاورشل نیوگت صادر کرد:
PM> install-package AvalonEdit
استفادهی مقدماتی از AvalonEdit
برای استفاده از این ویرایشگر ابتدا نیاز است فضای نام xmlns:avalonEdit تعریف شود. سپس کنترل avalonEdit:TextEditor در دسترس خواهد بود:
<Window x:Class="SyntaxHighlighter.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit" Title="MainWindow" Height="401" Width="617"> <Grid> <avalonEdit:TextEditor Name="txtCode" SyntaxHighlighting="C#" FontFamily="Consolas" FontSize="10pt"/> </Grid> </Window>
استفاده از AvalonEdit در برنامههای MVVM
خاصیت Text این ویرایشگر به صورت معمولی تعریف شده (DependencyProperty نیست) و امکان binding دو طرفه به آن وجود ندارد. به همین جهت نیاز است یک چنین DependencyProperty را به آن اضافه کرد:
using System; using System.Collections.Concurrent; using System.Reflection; using System.Windows; using System.Xml; using ICSharpCode.AvalonEdit; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting.Xshd; namespace AvalonEditWpfTest.Controls { public class BindableAvalonTextEditor : TextEditor { public static readonly DependencyProperty BoundTextProperty = DependencyProperty.Register("BoundText", typeof(string), typeof(BindableAvalonTextEditor), new FrameworkPropertyMetadata(default(string), propertyChangedCallback)); public static string GetBoundText(DependencyObject obj) { return (string)obj.GetValue(BoundTextProperty); } public static void SetBoundText(DependencyObject obj, string value) { obj.SetValue(BoundTextProperty, value); } protected override void OnTextChanged(EventArgs e) { SetCurrentValue(BoundTextProperty, Text); base.OnTextChanged(e); } private static void propertyChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args) { var target = (BindableAvalonTextEditor)obj; var value = args.NewValue; if (value == null) return; if (string.IsNullOrWhiteSpace(target.Text) || !target.Text.Equals(args.NewValue.ToString())) { target.Text = args.NewValue.ToString(); } } } }
اکنون برای استفاده از این کنترل جدید که BindableAvalonTextEditor نام دارد، میتوان به نحو ذیل عمل کرد:
<Window x:Class="AvalonEditWpfTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:viewModels="clr-namespace:AvalonEditTests.ViewModels" xmlns:controls="clr-namespace:AvalonEditWpfTest.Controls" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <viewModels:MainWindowViewModel x:Key="MainWindowViewModel"/> </Window.Resources> <Grid DataContext="{Binding Source={StaticResource MainWindowViewModel}}"> <controls:BindableAvalonTextEditor BoundText="{Binding SourceCode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" WordWrap="True" ShowLineNumbers="True" LineNumbersForeground="MediumSlateBlue" FontFamily="Consolas" VerticalScrollBarVisibility="Auto" Margin="3" HorizontalScrollBarVisibility="Auto" FontSize="10pt"/> </Grid> </Window>
افزودن syntax highlighting زبانهایی که به صورت رسمی پشتیبانی نمیشوند
به خاصیت SyntaxHighlighting این کنترل صرفا مقادیری را میتوان نسبت داد که به صورت توکار پشتیبانی میشوند. برای مثال#XML، C و امثال آن.
فرض کنید نیاز است SyntaxHighlighting زبان SQL را فعال کنیم. برای اینکار نیاز به فایلهای ویژهای است، با پسوند xshd. برای نمونه فایل sql-ce.xshd را در اینجا میتوانید مطالعه کنید. در آن یک سری واژههای کلیدی و حروفی که باید با رنگی متفاوت نمایش داده شوند، مشخص میگردند.
برای استفاده از فایل sql-ce.xshd باید به نحو ذیل عمل کرد:
الف) فایل sql-ce.xshd را به پروژه اضافه کرده و سپس در برگهی خواص آن در VS.NET، مقدار build action آنرا به embedded resource تغییر دهید.
ب) با استفاده از متد ذیل، این فایل مدفون شده در اسمبلی را گشوده و به متد HighlightingLoader.Load ارسال میکنیم:
private static IHighlightingDefinition getHighlightingDefinition(string resourceName) { if (string.IsNullOrWhiteSpace(resourceName)) throw new NullReferenceException("Please specify SyntaxHighlightingResourceName."); using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) { if (stream == null) throw new NullReferenceException(string.Format("{0} resource is null.", resourceName)); using (var reader = new XmlTextReader(stream)) { return HighlightingLoader.Load(reader, HighlightingManager.Instance); } } }
txtCode.SyntaxHighlighting = getHighlightingDefinition(resourceName);
برای سهولت استفاده از این قابلیت شاید بهتر باشد یک DependencyProperty دیگر به نام SyntaxHighlightingResourceName را به کنترل جدید BindableAvalonTextEditor اضافه کنیم:
using System; using System.Collections.Concurrent; using System.Reflection; using System.Windows; using System.Xml; using ICSharpCode.AvalonEdit; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting.Xshd; namespace AvalonEditWpfTest.Controls { public class BindableAvalonTextEditor : TextEditor { public static readonly DependencyProperty SyntaxHighlightingResourceNameProperty = DependencyProperty.Register("SyntaxHighlightingResourceName", typeof(string), typeof(BindableAvalonTextEditor), new FrameworkPropertyMetadata(default(string), resourceNamePropertyChangedCallback)); public static string GetSyntaxHighlightingResourceName(DependencyObject obj) { return (string)obj.GetValue(SyntaxHighlightingResourceNameProperty); } public static void SetSyntaxHighlightingResourceName(DependencyObject obj, string value) { obj.SetValue(SyntaxHighlightingResourceNameProperty, value); } private static void loadHighlighter(TextEditor @this, string resourceName) { if (@this.SyntaxHighlighting != null) return; @this.SyntaxHighlighting = getHighlightingDefinition(resourceName); } private static void resourceNamePropertyChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args) { var target = (BindableAvalonTextEditor)obj; var value = args.NewValue; if (value == null) return; loadHighlighter(target, value.ToString()); } } }
استفاده از آن نیز به شکل زیر است:
<controls:BindableAvalonTextEditor SyntaxHighlightingResourceName = "AvalonEditWpfTest.Controls.sql-ce.xshd" />
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید:
AvalonEditWpfTest.zip