خواص CLR :
هر برنامه نویس دات نتی، با مفهومی به نام خواص یا همان Property ها آشنا می باشد.
مفاهیمی مانند:
private int age;
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
به این گونه خواص، اصطلاحا خواص CLR می گویند. (CLR Property ) . در این قسمت، قصد بیان این موضوع را که این خواص چه هستند و چگونه پیاده سازی می شوند و چرا از آن ها استفاده می کنیم، را ندارم. برای مطالعه خواص CLR به لینک زیر مراجعه کنید.
هدف از بحث فوق، یک یاداوری در مورد اینگونه خواص، مقایسه آن ها با خواص جدید در تکنولوژی WPF ، جهت تشریح خواص WPF که به Dependency Property معروف هستند، می باشد.
خواص وابسته : (Dependency properties)
تکنولوژی WPF سرویس های جدیدی را برای گسترش خواص CLR در اختیار شما، قرار می دهد. این سرویس ها باعث می شود که بتوانید از این خواص در موارد زیادی از جمله متحرک سازی ها، استایل ها، قالب ها و عملیات بایند کردن و ... استفاده کنید. به چنین خواصی اصطلاحا Dependency Property می گویند.
خواص وابسته و خواص CLR :
در ساده ترین حالت، می توانید خواص وابسته را به مانند خواص CLR در نظر بگیرید. این وضوع را از ابتدای مباحث آموزشی تا بدین جا نیز، با آن برخورد داشته اید. به عنوان مثال، در هنگام استفاده از خواص WPF احتمالا به این نکته توجه کرده اید که روش استفاده از این خواص نیز مانند خواص CLR می باشند.
به عنوان مثال دو قطعه کد زیر مشابه هم می باشند :
Textbox1.Text = "save";
Textbox1.Text = "save";
با این تفاوت که در کد اول، خاصیت Text یک خاصیت CLR می باشد ولی در کد دوم خاصیت Text یک Dependency Properrty می باشد. اما واقعیت این است که این خواص و قدرت آن ها بسیار فراتر از این موضوع می باشد.
این گونه خواص می توانند مقادیر خود را بر مبنای ورودی های دیگر محاسبه نمایند. این ورودی ها هر چیزی می توانند باشند. به عنوان مثال در بحث Trigger ها، خواهید دید که چگونه بر مبنای تغیر یک خاصیت، خواص دیگر می توانند به صورت اتوماتیک مقادیر خود را تنظیم کرده و آن رفتاری را از خود بروز دهند که شما انتظار دارید.
علاوه بر این، اینگونه خواص، سیستم جدیدی را در اعتبار سنجی مقادیر به شما ارائه می
دهند.
خواص وابسته :
شما می توانید، با پیاده سازی خواص CLR به عنوان Dependency Property ،در سیستم WPF Properties، قابلیت های بسیاری از جمله ارث بری، انیمیشن، پشتیبانی از استایل ها، مقید سازی داده ها و ... به کار برید.
Dependency property ها ، خواصی هستند که در سیستم WPF Properties توسط متد Register ، ثیت شده باشند. هر Dependency property توسط کلاسی پیاده سازی می شود که در آن کلاس فیلدی با امضای public static از نوع Dependency Property وجود دارد که به آن شناسه آن خاصیت می گویند.
در نام گذاری شناسه ها اینگونه عمل میشود که پس از نام خاصیت، کلمه Property در
ادامه آن ذکر می گردد. به عنوان مثال شناسه خاصیت Background Property، background می باشد.
این شناسه، اطلاعاتی راجع به خاصیت خود به هنگام ثیت شدن را درون خود نگه داری می کند.
دقت داشته باشید که Dependency property ها تنها توسط نوع های Dependency object قابل استفاده می باشند.
اما همانطور که قبلا اشاره کردم، کلاس Dependency object در بالای هرم ساختاری کلاس ها در معماری wpf قرار دارد،. به همین دلیل بسیاری از کلاس های اصلی این سیستم می توانند از Dependency property ها پشتیبانی کنند.
چرا و چه زمانی از Dependency property ها استفاده کنیم؟
زمانی که درون کلاسی که از کلاس Dependency object ارث بری می کند، حاصیتی را تعریف می کنید، می توانید این خاصیت را به صورت Dependency پیاده سازی نمایید. اما سوال این است که آیا همیشه و در همه حال بایستی از این نوع خواص استفاده کرد؟ یقینا جواب خیر می باشد. در بسیاری از مواقع پیاده سازی یک خاصیت CLR با یک فیلد خصوصی کافی است.
اما با این حال، ممکن است در بعضی مواقع نیاز به تعریف و پیاده سازی خواص یه شیوه Dependency property را داشته باشید. در ادامه چند دلیل برای تعریف این خواص آورده می شود:
زمانی که می خواهید، خاصیت شما قابل مقدار دهی در استایل ها ( Styles) و قالب ها (Templates) باشد.
زمانی که می خواهید، خاصیت شما قابل استفاده در مقید سازی داده ها (Data Bindings) باشد.
زمانی که می خواهید، خاصیت شما به صورت اتوماتیک بتواند مقدار خودش را از مقدار
والد خود ارث بری کند.
زمانی که می خواهید از خاصیت خود در متحرک سازی استفاده نمایید. در واقع نیاز دارید
که مقدار خاصیت شما در یک پروسیه انیمیشنی قابل کنترل باشد.
اگر چه در سناریو های بالا، شما نیاز به خواص Dependency دارید، ولی در بسیاری از موارد می توانید به جای نوشتن خاصیت های جدید، با دوباره باز نویسی کردن متا داده های خواص Dependency موجود، به هدف خود دست یابید.
تعریف و پیاده سازی خواص Dependency :
تعریف و پیاده سازی خواص Dependency دارای چهار مرحله زیر می باشد.دقت داشته باشید که این چهار مرحله، مراحل ترتیبی نیستند. علاوه بر این، این مراحل قابل اقدام در یکدیگز نیز می باشند.
تعریف متا داده برای خاصیت. این مرحله اختیاری می باشد. می تواند در تعریف خاصیت مقدار null داشته باشد.
تعریف یک فیلد با امضای readonly public static به عنوان شناسه خاصیت . این فیلد بایستی از نوع Dependency property باشد.
ثیت کردن خاصیت، در سیستم wpf توسط متد Register.
ایجاد یک پوشاننده (wrapper) برای خاصیت، که همنام با نام خاصیت می باشد.
مثال:
فرض کنید کلاسی به نام MyControl ایجاد کرده اید. این کلاس از کلاس UserControl ارث بری می کند. می خواهیم خاصیتی به نام CornerRadius برای این کنترل تعریف کنیم.
Public class MyControl :UserControl
{
}
ابندا شناسه خاصیت را تعریف می کنیم.
public static readonly DependencyProperty
CornerRadiusProperty;
همانطور که مشاهده می کنید، شناسه به صورت CornerRadiusProperty نام گذاری شده است که CornerRadius نام خاصیت می باشد.
در مرحله بعدی می بایستی خاصیت خود را ثبت کنیم. برای این منظوراز متد Register استفاده می کنیم.
DependencyProperty.Register("CornerRadius", typeof
(CornerRadius), typeof(MyControl), new
FrameworkPropertyMetadata (0));
همانطور که مشاده می کنید از متد Register از کلاس Dependency Property که یک کلاس مهر شده ( درای امضای seald) می باشد، استفاده شده است.
آرگومان اول این متد، نام خاصیت را مشخص می کند. در اینجا نام خاصیت، CornerRadius می باشد.
آرگومان دوم نوع خاصیت را مشخص می کند. نوع خاصیت همانطور که مشاهده می
کنید، از نوع CornerRadius در نظر گرفته شده است.
نکته:
CornerRadius یک ساختار (Structure) در فضای نام System.Windows می باشد که اینترفیس ژنریک IEquatable را پیاده سازی میکند.
آرگومان سوم، مالک(owner) خاصیت را مشخص می کند. که در این مثال، کلاس
MyControl می باشد.
آرگومان چهارم، متا داده ای است که برای این خاصیت در نظر گرفته شده است. مقدار صفر درون آن، معرف مقدار پیش فرض خاصیت، می باشد. موارد دیگری را نیز می توانید در تعریف متا داده های یک خاصیت، لحاظ کنید که در ادامه توضیح داده می شوند.
علاوه بر این، همانطور که پیش تر گفته شد، تعریف متا داده برای یک حاصیت اختیاری
می باشد ولی تنظیم آن اغلب موارد دارای مزایایی است که در ادامه خواهید دید.
قبل از بررسی آرگومان FrameworkPropertyMetadata به صورت عمیق تر، به آرگومان دیگری که می توان به متد Register پاس داد، می پردازیم.
ValidateValueCallback:
آرگومان دیگری که به متد Register می توان پاس داد، نمونه ای از Delegat ای به نام ValidateValueCallback می باشد. این Delegate دارای تعریفی مانند زیر می باشد:
public delegate bool ValidateValueCallback(object value);
از این Delegate می توان جهت اعتبار سنجی مقدار خاصیت، که توسط کاربر نهایی(end user) مقدار دهی شده است، استفاده کرد. همانطور که در امضای این Delegate مشخص است، نوع برگشتی متد هایی که این Delegate می تواند، مرجعی برای آن ها باشد، از نوع bool می باشد. در واقع چنانچه مقدار خاصیت، دارای اعتبار باشد، مقدار بازگشتی true و در غیر این صورت مقدار بازگشتی false می باشد پس می توان نعریف متد Register را به شکل زیر کامل تر کرد:
DependencyProperty.Register("CornerRadius", typeof
(CornerRadius), typeof(MyControl), new
FrameworkPropertyMetadata(0), new ValidateValueCallback
(CornerRadiusValidateCallBack));
که متد CornerRadiusValidateCallBack به صورت زیر می باشد:
static bool CornerRadiusValidateCallBack(object value)
{
// write your validastion code here
//
//
// if (value is Valid)
// return true;
// return false;
}
مرحله آخر پوشانیدن خاصیت می باشد.
Property Wrapper :
در این مر حله بایستی خاصیت شما به شکل یک خاصیت CLR پوشانیده شود تا قابل
استفاده باشد. به این خاصیت اصطلاحا property wrapper می گویند.
نحوه تعریف یک wrapper برای خواص Dependency به صورت زیر می باشد:
public CornerRadius CornerRadius
{
get
{
return (CornerRadius)GetValue(CornerRadiusProperty);
}
set
{
SetValue(CornerRadiusProperty, value);
}
}
متد های GetValue و SetValue توسط کلاس Dependency Object مورد استفاده قرار می گیرند تا خاصیت شما را مقدار دهی کنند. به همین دلیل، نبایستی در Property Wrapper ها، منطقی را پیاده سازی کنید چون ممکن است که نا دیده گرفته شوند.