silverlightsl04-ch16

30
Silverlight 4 ﻧﮕﺎﺭﺵ ﭘﮋﻭﻫﺶ: ﻧﺼﻴﺮﻱ ﻭﺣﻴﺪ[email protected] ﺑﻬﺎﺭ١٣٨٩

Upload: aoe1831

Post on 08-Nov-2014

3 views

Category:

Documents


0 download

DESCRIPTION

silverlight 16

TRANSCRIPT

Page 1: silverlightSL04-Ch16

را

Silverlight 4

وحيد نصيري: پژوهش و نگارش [email protected]

١٣٨٩بهار

Page 2: silverlightSL04-Ch16

Silverlight 4 ٣٣٣

فهرست مطالب Silverlight ...................................... ۳۳۴ در كاربر ورودي اعتبار تعيين هاي روش – ۱۶ فصل

٣٣٤ ...................................................................................................................................................................................................... مقدمه ٣٣٤ ................................................................................................... حاصل هاي استثناء و اطالعات مستقيم بررسي كمك به اعتبار تعيين ٣٤٤ ................................................................................................................................................ ها داده هاي ويژگي كمك به اعتبار تعيين

٣٤٨ .............................................................................................................................................................. سفارشي هاي ويژگي تعريف ٣٤٩ .................................................................................................. اشياء اعتبار تعيين جهت IDataErrorInfo اينترفيس سازي پياده

٣٥٢ ............................................................................................ اشياء) Asynchronous( همزمان غير اعتبار تعيين ي نحوه با آشنايي ٣٥٣ ................................................................................................................................................................ كاربردي مثال يك بررسي

.چاپ عمومي غير رايگان اين مطالب بدون مجوز كتبي از طرف نويسنده به هر نحوي غيرمجاز است .خذ بال مانع استأدر نشريات الكترونيكي با ذكر مانتشار اين مطالب بر روي اينترنت و يا استفاده از آن به صورت مستقيم و يا غير مستقيم

Page 3: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٣٤

Silverlightهاي تعيين اعتبار ورودي كاربر در روش – ۱۶فصل

مقدمه

ها در يك سيستم و هاي كاربران اطمينان كرد؛ زيرا منشاء اصلي بسياري از ناهماهنگي هيچگاه نبايد به ورودي در اين فصل نگاهي خواهيم .ي كاربران است هاي تعيين اعتبار نشده ها، ورودي آنيا حمالت صورت گرفته به

نيز Bindingي كه جزو مباحث تكميلي و پيشرفته Silverlightي تعيين اعتبار ورودي كاربر در داشت به نحوه .هاي كاربردي و تجاري است و همچنين جزو الزامات تمامي برنامه شود محسوب مي

هاي حاصل بررسي مستقيم اطالعات و استثناء بار به كمكتعيين اعت

Silverlightي تعيين اعتبار ورودي كاربر در نمايي از اولين برنامه –۱شكل

قصد داريم با سيستم اعتبار ، MVVMپياده سازي شده توسط الگوي در طي يك مثال كاربردي و كامل

در . را دارد، آشنا شويم Bindingاستثناهاي صادره در حين عمليات كه قابليت يكپارچگي با Silverlightسنجي گردد و مقادير دريافتي قبل از هر ، سه خاصيت نام، سن و آدرس ايميل يك كارمند دريافت مي)۱شكل (اين مثال

هاي غامپي. عمليات ديگري تعيين اعتبار شده و اگر مطابق منطق مورد نظر ما نبودند، يك استثناء صادر خواهد شدبه كاربر نمايش داده ۱ها به صورت خودكار در رابط كاربري برنامه همانند شكل صادره در اين استثناء

.شوند ميي جاري، افزودن ارجاعي به اسمبلي پروژههاي پيش نياز استفاده از كنترل

System.Windows.Controls.Data.Input هاي به اين ترتيب كنترل. باشد ميValidationSummary و

Page 4: silverlightSL04-Ch16

Silverlight 4 ٣٣٥DescriptionViewer توان مي ۱ ها را در شكل ، قابل استفاده در پروژه خواهند بود كه نمايي از آن

اي در پايين صفحه جهت برشمردن كليه تذكرات خالصه ValidationSummaryتوسط كنترل . مشاهده نمودكوچك Tooltip، امكان نمايش يك DescriptionViewerالزم جهت تعيين اعتبار مقادير ورودي و توسط كنترل

.مرتبط با دريافت مقدار سن، فراهم شده است TextBoxو زيبا در كنار

Silverlightي تعيين اعتبار ورودي كاربر در هاي اولين پروژه ها و فايل ساختار پوشه –۲شكل

مخفف INPC(ايجاد شده است ها INPCجهت سهولت كار با Extensionsكالس

INotifyPropertyChanged زمانيكه نياز به فراخواني متد هاي قبل، هاي فصل در تمام مثال). استraisePropertyChanged ،بايستي يك رشته را مساوي نام خاصيت مورد استفاده در آن وارد مي وجود داشت

نيازي نيست تا نام خاصيت ديگر آن Raiseبا استفاده از متد و ذيل Extensionsاما با كمك كالس . كرديم ميمورد نظر را به صورت يك رشته كه امكان اشتباه تايپي در آن وجود دارد و تحت كنترل كامپايلر نيست، وارد

ي شيء توان ارجاع تحت نظر كامپايلري را از يك وهله مي lambda expressionsبه اين صورت با كمك . نمائيم :معرفي نمود

Extensions.cs

using System; using System.ComponentModel; using System.Linq.Expressions; using System.Reflection; namespace SilverlightApplication68.Helper { public static class Extensions {

Page 5: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٣٦

/// <summary> /// saves us from typos when using INPC. /// </summary> public static void Raise( this PropertyChangedEventHandler eventHandler, Expression<Func<object>> expression) { if (null == eventHandler) return; PropertyInfo propertyInfo; ConstantExpression constantExpression = expression.GetPropertyInfo(out propertyInfo); foreach (var del in eventHandler.GetInvocationList()) { del.DynamicInvoke( new[] { constantExpression.Value, new PropertyChangedEventArgs(propertyInfo.Name) }); } } public static ConstantExpression GetPropertyInfo (this Expression<Func<object>> expression, out PropertyInfo propertyInfo) { var lambda = expression as LambdaExpression; MemberExpression memberExpression; if (lambda.Body is UnaryExpression) { var unaryExpression = lambda.Body as UnaryExpression; memberExpression = unaryExpression.Operand as MemberExpression; } else { memberExpression = lambda.Body as MemberExpression; } if (memberExpression == null) throw new NullReferenceException("memberExpression"); var constantExpression = memberExpression.Expression as ConstantExpression;

Page 6: silverlightSL04-Ch16

Silverlight 4 ٣٣٧ if (constantExpression == null)

throw new NullReferenceException("constantExpression"); propertyInfo = memberExpression.Member as PropertyInfo; return constantExpression; } } }

كنيد، ذكر گرديده را در ادامه مالحظه مي برنامه كه كدهاي آن Modelاكنون كاربردي از كالس فوق، در كالس ):PropertyChanged.Raiseمتدهاي (است

Employee.cs

using System; using System.ComponentModel; using SilverlightApplication68.Helper; namespace SilverlightApplication68.Models { public class Employee : INotifyPropertyChanged { private string _name = string.Empty; public string Name { get { return _name; } set { if (string.IsNullOrEmpty(value)) { throw new ArgumentException("Name is required"); } if (_name != value) { _name = value; PropertyChanged.Raise(() => Name); } } } private int _age; public int Age { get { return _age; } set { if (value > 60 || value<25)

Page 7: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٣٨

{ throw new ArgumentException("Age should be between 25-60"); } if (_age != value) { _age = value; PropertyChanged.Raise(() => Age); } } } private string _email = string.Empty; public string Email { get { return _email; } set { if (string.IsNullOrEmpty(value)) { throw new ArgumentException("Email is required"); } if (!value.Contains("@") && !value.Contains(".")) { throw new ArgumentException("Email is Invalid"); } if (_email != value) { _email = value; PropertyChanged.Raise(() => Email); } } } public event PropertyChangedEventHandler PropertyChanged; } }

برنامه، سه خاصيت كه بيانگر نام، سن و آدرس ايميل يك كارمند هستند با پياده سازي Modelدر كالس ي دريافت مقادير از كاربر، در اين كالس دقيقا در لحظه. اند ارائه شده ،INotifyPropertyChangedاينترفيس

اين . گردد اء صادر مينين نشوند، يك استثها صورت گرفته و اگر شرايط مورد نظر تام عمليات اعتبار سنجي آن . گردد منتشر شده و سپس به كاربر ارائه مي Silverlightاستثناء در سيستم اعتبارسنجي

Page 8: silverlightSL04-Ch16

Silverlight 4 ٣٣٩هاي ويژگي ،ها برنامه جهت استفاده از اطالعات اين استثناء Viewبراي مثال در

ValidatesOnExceptions وNotifyOnValidationError سيستمBinding بهTrue كدهاي (اند تنظيم شده ).را در ادامه مالحظه خواهيد نمود Viewمرتبط با XAMLكامل

<TextBox Grid.Column="1" Text="{ Binding EmployeeInfo.Age, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}" Grid.Row="1" Margin="5" Width="auto" />

نمائيم كه درخواست مي Silverlightاز سيستم تعيين اعتبار NotifyOnValidationErrorبا كمك خاصيت را BindingValidationErrorعاله بر آن ويژگي . ار دهيدلطفا خطاهاي حاصل از تعيين اعتبار را تحت نظر قر

تعريف روال رخداد گردان دريافت ،كار اين ويژگي. تعريف نمودبرنامه نيز Viewتوان در گريد اصلي نيز ميواگذار Silverlightكه عموما اينكار انجام نشده و به سيستم اعتبار سنجي ؛خطاهاي ناشي از تعيين اعتبار است

برنامه قرار خواهد Viewفايل Code behindدر صورت نياز، امضاي اين روال رخدادگردان كه در .ودش مي :سازگار نيست به شرح زير است MVVMگرفت و آنچنان با الگوي

EmployeeViewModel.cs

private void OnValidationError(object sender, ValidationErrorEventArgs e) { switch (e.Action) { case ValidationErrorEventAction.Added: Exception ex = e.Error.Exception; break; case ValidationErrorEventAction.Removed: break; default: break; } }

گيرند؟ به همين جهت خاصيت اكنون سؤال اينجا است كه چه زماني اين خطاها دريافت و تحت كنترل قرار مي

ValidatesOnExceptions به نيزTrue به اين ترتيب به . تنظيم شده استSilverlight خواهيم گفت در زمانفا هر گونه استثناء صادر شده را ، لط)Mode=TwoWayبا توجه به ( Bindingدريافت اطالعات از طريق سيستم

علت وجود .به عنوان خطاي اعتبار سنجي در نظر گرفته و سبب از كار افتادن برنامه نگرديدArgumentException هاي تعريف شده در كالس مدل برنامه نيز همين نكته است.

دادهاي گيرد به كليه رخ زمانيكه بر روي يك فرم قرار مي ValidationSummaryكنترل BindingValidationError كند ي خطاهاي حاصل را ليست مي ي جاري گوش فرا داده و خالصه اشياء صفحه.

:فرمائيد پروژه را مالحظه مي ViewModelدر ادامه كدهاي

Page 9: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٤٠

EmployeeViewModel.cs

using System.Windows; using System.Windows.Input; using SilverlightApplication68.Helper; using SilverlightApplication68.Models; namespace SilverlightApplication68.ViewModels { public class EmployeeViewModel { public ICommand SaveCommand { set; get; } public Employee EmployeeInfo { set; get; } public EmployeeViewModel() { EmployeeInfo = new Employee(); SaveCommand = new DelegateCommand<Employee>( saveCommand, canSaveCommand); } private bool canSaveCommand(Employee arg) { //TODO: validating model return arg != null; } private void saveCommand(Employee obj) { //In a real applicaiton implement saving the //EmployeeInfo to the database //In M-V-VM applications the ViewModel does not raise //UI Message Boxes. //Instead, a Logger Service is used. MessageBox.Show(string.Format("{0} Saved.", EmployeeInfo.Name)); } } }

Viewفوق بسيار ساده بوده و كار آن در اختيار قرار دادن اطالعات شيء مدل برنامه به ViewModelكالس در اين كالس نيز از كالس . ي ذخيره سازي برنامه است و همچنين مديريت روال رخدادگردان كليك بر روي دكمه

DelegateCommand ،استفاده گرديده است و از تكرار مجدد معروفي كه در طي فصول قبلي كتاب توسعه يافتند .شود كدهاي آن صرفنظر مي

Page 10: silverlightSL04-Ch16

Silverlight 4 ٣٤١

:بايد در نظر داشت ViewModelدو نكته را در اين تا به اين صورت . ودانجام ش canSaveCommandتعيين اعتبار كلي مدل برنامه در متد بهتر است •

مرتبط فعال نخواهد Saveي كمههاي تعريف شده را تامين نكند، د زمانيكه اين مدل، شرايط اعتبار سنجي .شد

گرديدهاستفاده MessageBoxاز يك ،صرفا جهت نمايش اطالعات وارد شده saveCommandدر متد •برنامه تا حد امكان نبايد ارجاع مستقيمي را به عناصر ViewModelاست و بايد در نظر داشت كه

.ا با مشكل مواجه خواهند كردر هاي واحد آن بصري داشته باشد زيرا امكان انجام آزمون داراي ValidationSummaryقصد داريم اگر كنترل . ايم در ادامه يك تبديل كننده سفارشي را ايجاد نموده

ي ذخيره سازي اطالعات غيرفعال گردد و بود، دكمه) ي خطاهاي تعيين اعتبار برنامه خالصه(تعدادي خطا قا براي همين منظور تدارك ديده شده است اما براي كار ما مناسب اين كنترل دقي HasErrorsخاصيت . برعكسي ذخيره زيرا نقيض آن به معناي عدم وجود خطا است و در اين حالت است كه قصد داريم كنترل دكمه. نيست

:باشد ي سفارشي بعد مي به همين جهت نياز به كالس تبديل كننده. سازي اطالعات فعال گردد يا برعكسHasErrorToIsEnabledConverter.cs

using System; using System.Globalization; using System.Windows.Data; namespace SilverlightApplication68.Converter { public class HasErrorToIsEnabledConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return (bool)value ? false : true; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return value; } } }

:نمائيد اصلي برنامه را در ادامه مشاهده مي Viewمتناظر با XAMLكدهاي EmployeeView.xaml

<UserControl x:Class="SilverlightApplication68.Views.EmployeeView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

Page 11: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٤٢

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc= "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:SilverlightApplication68.ViewModels" xmlns:Controls= "clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input" xmlns:local="clr-namespace:SilverlightApplication68.Converter" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <UserControl.Resources> <vm:EmployeeViewModel x:Key="viewModel" /> <local:HasErrorToIsEnabledConverter x:Key="HasErrorsToIsEnabledConverter" /> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource viewModel}}" > <Grid.ColumnDefinitions> <ColumnDefinition Width="88*" /> <ColumnDefinition Width="184*" /> <ColumnDefinition Width="28*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="auto" /> <RowDefinition Height="auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <TextBlock Text="Name:" HorizontalAlignment="Right" Margin="5" Grid.Column="0" Grid.Row="0" /> <TextBlock Text="Age:" HorizontalAlignment="Right" Grid.Row="1" Margin="5" Grid.Column="0" /> <TextBlock Text="Email:" HorizontalAlignment="Right" Grid.Row="2" Margin="5" Grid.Column="0" /> <TextBox Grid.Column="1" Text="{ Binding EmployeeInfo.Name, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}" Margin="5" Width="auto" /> <TextBox Grid.Column="1" Text="{ Binding EmployeeInfo.Age, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}" Grid.Row="1" Margin="5" Width="auto" /> <Controls:DescriptionViewer Grid.Row="1" Grid.Column="2"

Page 12: silverlightSL04-Ch16

Silverlight 4 ٣٤٣ Description="Age should be between 25-60" />

<TextBox Grid.Column="1" Text="{ Binding EmployeeInfo.Email, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}" Grid.Row="2" Margin="5" Width="auto" /> <Button Content="Save" Grid.Row="3" HorizontalAlignment="Right" Command="{Binding SaveCommand}" CommandParameter="{Binding EmployeeInfo}" Margin="5" VerticalAlignment="Top" Width="75" IsEnabled="{Binding ElementName=ValidationSummary1,Path=HasErrors, Converter={StaticResource HasErrorsToIsEnabledConverter}}" /> <Controls:ValidationSummary Margin="5" x:Name="ValidationSummary1" Grid.Column="1" Grid.Row="3" VerticalAlignment="Top" /> </Grid> </UserControl>

:اند ابتدا سه فضاي نام مورد استفاده تعريف شده Viewدر اين ۱. vm : جهت معرفي فضاي نامViewModels برنامه.

۲. Controls :

كه پيشتر در مورد آن توضيح System.Windows.Controls.Data.Inputبراي معرفي فضاي نام .داده شد

۳. local :است ف شدهي سفارشي تعري براي معرفي فضاي نام تبديل كننده.

منبع . اند برنامه تعريف شده ViewModel، منابع تبديل كننده و User controlسپس در قسمت منابع ثابت اين ViewModel بهDataContext هاي موجود در گريد اصلي صفحه منتسب شده و سپس از اين طريق كليه كنترل

.خود را خواهند يافت Bindingصفحه، منبع اصلي هاي قرار گرفته بر روي صفحه، داراي ويژگي TextBoxطور كه پيشتر نيز توضيح داده شد، هر سه كنترل همان

Binding متناظر با سيستم اعتبار سنجي بوده و به اين ترتيب نسبت به خطاهاي حاصل به صورت خودكار .عكس العمل نشان خواهند داد

نيز جالب ValidationSummaryكنترل HasErrorsخاصيت ي انقياد خاصيت فعال بودن كنترل دكمه به نحوه .را عهده دار خواهد بود HasErrorsي صحيح مقادير ي تعريف شده، كار ترجمه توجه است و تبديل كننده

رود و در سيستم تعيين اعتبار نيز به شمار مي Bindingهايي كه جزو خواص تعاريف يكي ديگر از خاصيت Silverlightرا در Explicitو Defaultنام دارد كه دو مقدار UpdateSourceTriggerنقش ساز است،

آن مورد استفاده قرار گرفته Defaultنمائيد زيرا مقدار اين خاصيت را در تعاريف فوق مالحظه نمي. پذيرد مي

Page 13: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٤٤

فرم، كار به روز هاي قرار گرفته بر روي TextBoxهر كدام از LostFocusدر اين حالت پس از رخدادن . استاين رخداد براي اكثر (شود ها و همچنين تعيين اعتبار اطالعات دريافتي، انجام مي رساني اطالعات متناظر آن

درنظر گرفته LostFocusها TextBoxباشد، اما براي مي PropertyChangedمساوي Silverlightهاي كنترليرد به اين معنا است كه كار اعتبار سنجي را به صورت دستي قرار گ Explicitاگر مقدار آن مساوي ). شده است

.مديريت خواهيد نمود

:ي اصلي برنامه استفاده گرديده است در صفحه Viewو نهايتا از اين

MainPage.xaml

<UserControl x:Class="SilverlightApplication68.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc= "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SilverlightApplication68.Views" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <local:EmployeeView /> </Grid> </UserControl>

ها هاي داده تعيين اعتبار به كمك ويژگي System.ComponentModel.DataAnnotationsهاي فضاي نام اين قسمت قصد داريم از توانايي در

.بنابراين الزم است در ابتدا ارجاعي را به اين اسمبلي اضافه كنيم. استفاده نمائيمو نيم، ۳به دات نت فريم ورك System.ComponentModel.DataAnnotationsي فضاي نام تاريخچه

در . را معرفي كرد ASP.NET Dynamic Dataي ، پروژه ASP.NETگردد؛ زمانيكه تيم پك يك بر ميسرويس به خواص يك مدل، كار اعتبار ] Range[و ] Required[مانند ) attributes(ها اين پروژه با اعمال يك سري ويژگي

هاي ات در ساير فناوريپس از آن از اين امكان. صورت خواهد گرفت WebFormsها در سنجي خودكار آن :اند ها در جدول بعد ليست شده اين ويژگي .مرتبط نيز استفاده گرديد

Page 14: silverlightSL04-Ch16

Silverlight 4 ٣٤٥

Validation attributesمعرفي -۱جدول ويژگي

)Attribute( مثال توضيحات

Required و يا null(نمايد ضروري بودن يك خاصيت را مشخص مي

).خالي نبايد باشد]Required[

StringLength توان توسط آن يك رشته را ميمجاز حداقل و حداكثر طول

.معرفي كرد]StringLength(10)[

Range اي از اعداد مجاز و يا تاريخ را توان بازه توسط آن مي [Range(1, 500)] .مشخص كرد

RegularExpression امكان تعريف عبارات باقاعده را جهت اعتبار سنجي خاصيت

.وردآ مورد نظر فراهم مي[RegularExpression(

"[1-9][0-9]{3}")]

CustomValidation سازد متدي سفارشي را جهت تعيين اعتبار مشخص مي. CustomValidation(

typeof(MyValidatorClass) ,"ValidateDateMethod")]

هولت كار با جهت سرا در ادامه مالحظه خواهيد نمود كه كدهاي آن ValidationHelper از كالس

DataAnnotations از متد . شود استفاده ميGetErrors توان جهت تعيين اعتبار كلي يك شيء پيش از آن ميگرداند مساوي اگر تعداد خطاهايي كه بر مي. ذخيره سازي اطالعات آن در بانك اطالعاتي برنامه استفاده كرد

ي ما وارد كرده است يا مطابق قيود تعريف شده صفر باشد به اين معنا است كه كاربر اطالعات صحيحي رااي كه اطالعات را اين كالس براي تعيين اعتبار ورودي كاربر دقيقا در لحظه ValidatePropertyاز متد . برعكسجهت معرفي و يافتن نام خاصيت تحت lambda expressionsاين متد نيز از . توان كمك جست كند مي وارد مي

كه Extensionsاين كالس از متدهاي كالس .هاي خام در اينجا استفاده نشده است ند و از رشتهك نظر استفاده مي .نمايد در مثال قبل معرفي شدند، استفاده مي

ValidationHelper.cs

using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq.Expressions; using System.Reflection; namespace SilverlightApplication68.Helper { public class ValidationHelper { public static IList<ValidationResult> GetErrors(object instance) { var res = new List<ValidationResult>();

Page 15: silverlightSL04-Ch16

Silverlight ودي كاربر درهاي تعيين اعتبار ور روش – ١٦ فصل

٣٤٦

Validator.TryValidateObject(instance, new ValidationContext(instance, null, null), res, true); return res; } public static void ValidateProperty(object value, Expression<Func<object>> expression) { PropertyInfo propertyInfo; var constantExpression = expression.GetPropertyInfo(out propertyInfo); Validator.ValidateProperty(value, new ValidationContext( constantExpression.Value, null, null) { MemberName = propertyInfo.Name }); } } }

:ويسي خواهيم كرد بر اين اساس، همان كالس كارمند مثال قبل را به صورت ذيل بازنEmployee.cs

using System.ComponentModel; using System.ComponentModel.DataAnnotations; using SilverlightApplication68.Helper; namespace SilverlightApplication68.Models { public class Employee : INotifyPropertyChanged { private string _name = string.Empty; [Required(ErrorMessage = "{0} is required.")] [StringLength(15, MinimumLength = 6, ErrorMessage = "{0} len must be between {1} and {2}")] public string Name { get { return _name; } set { if (_name != value) { ValidationHelper.ValidateProperty(value, () => Name); _name = value; PropertyChanged.Raise(() => Name); } }

Page 16: silverlightSL04-Ch16

Silverlight 4 ٣٤٧ }

private int _age; [Required(ErrorMessage = "{0} is required.")] [Range(25, 60, ErrorMessage = "{0} must be set between {1} and {2}")] public int Age { get { return _age; } set { if (_age != value) { ValidationHelper.ValidateProperty(value, () => Age); _age = value; PropertyChanged.Raise(() => Age); } } } private string _email = string.Empty; [Required(ErrorMessage = "{0} is required.")] [RegularExpression( @"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Please enter a valid email.")] public string Email { get { return _email; } set { if (_email != value) { ValidationHelper.ValidateProperty(value, () => Email); _email = value; PropertyChanged.Raise(() => Email); } } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion } }

كليه توان كه پيشتر معرفي گرديد، مي ValidationHelperكالس GetErrorsاكنون با كمك متد همچنين

:اعتبار سنجي نمود به صورت كلي اي از آن از هرگونه استفاده قبلمدل برنامه را خواص

Page 17: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٤٨

EmployeeViewModel.cs

... private void saveCommand(Employee obj) { //validating model var errorInfos = ValidationHelper.GetErrors(obj); if(errorInfos.Any()) // using System.Linq; { MessageBox.Show("Model is not valid"); return; } MessageBox.Show(string.Format("{0} Saved.", obj.Name)); } ...

هاي سفارشي تعريف ويژگي

در . به سادگي قابل توسعه هستند CustomValidationها با استفاده از ويژگي هاي قابل اعمال به داده ويژگي خروجي اين متد بايد از . نمائيد دهد مالحظه مي ادامه يك كالس كه متد سفارشي تعيين اعتبار واحدها را ارائه مي

.بوده و تنها يك پارامتر را از نوع خاصيتي كه قرار است توسط آن اعتبار سنجي گردد، دريافت نمايد boolنوع MyValidations.cs

namespace SilverlightApplication68.CustomValidations { public class MyValidations { public static bool UnitsValidation(int units) { return units < 100; } } }

:تواند باشد ي اعمال اين ويژگي سفارشي تعريف شده به صورت زير مي اكنون نحوه[CustomValidation(typeof(MyValidations), "UnitsValidation")] public int UnitsOnOrder;

Page 18: silverlightSL04-Ch16

Silverlight 4 ٣٤٩

جهت تعيين اعتبار اشياء IDataErrorInfoپياده سازي اينترفيس

نيز به اين IDataErrorInfo، اينترفيس Silverlight 4جهت تكميل امكانات تعيين اعتبار ورودي كاربران در مطلب جديدي نيست و WinFormsو يا WPFاين اينترفيس براي برنامه نويسان . مجموعه اضافه گرديده است

:نمائيد را در ادامه مشاهده مي امضاي آن .ها اضافه گرديده است به درخواست آن

C#

public interface IDataErrorInfo { string Error { get; } string this[string columnName] { get; } }

ها و اشياء اي را بر اساس كالس توان منطق سفارشي تعيين اعتبار ويژه آن، مي Errorبا پياده سازي خاصيت

به من بگو كال چه مشكلي در تعيين : اين به اين معنا است Silverlightبراي Errorخاصيت ( نامه ارائه دادديگر بري نام ارائه دهنده Indexerباشد كه يك مي thisترين قسمت آن ، خاصيت مهم. )؟اعتبار شيء جاي وجود داردي ن به ازاي هر خاصيت، منطق ويژهتوا براي اين اساس مي. استي شيء جاري خواص تعيين اعتبار شونده

به من بگو اين خاصيت : به اين معنا است Silverlightبراي Indexerاين ( اعتبار سنجي خاصي را ارائه دادتوان به تعيين اعتبار در اينجا بدون ايجاد استثناءها مي. )نامبرده شده از لحاظ تعيين اعتبار چه مشكلي دارد؟

خواص setي تنظيم كننده محل همچنين ديگر نيازي به بررسي مقادير در. ء پرداختهاي يك شي مقادير خاصيت .نيز نخواهد بود

فرا Binding، اكنون نوبت به شناساندن آن به سيستم IDataErrorInfoپس از پياده سازي اينترفيس به NotifyOnValidationErrorو ValidatesOnDataErrorsبراي اين منظور تنها كافي است خواص . رسد مي

true براي مثال . تنظيم شوند: XAML <TextBox Text="{Binding Name, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />

Page 19: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٥٠

طفا به پياده سازي ديگري از كالس كارمند فصل جاري دقت براي توضيح كاربردي مباحث توضيح داده شده، ل :بفرمائيد

Employee.cs

using System.ComponentModel; using SilverlightApplication68.Helper; namespace SilverlightApplication68.Models { public class Employee : INotifyPropertyChanged, IDataErrorInfo { private string _name = string.Empty; public string Name { get { return _name; } set { if (_name != value) { _name = value; PropertyChanged.Raise(() => Name); } } } private int _age; public int Age { get { return _age; } set { if (_age != value) { _age = value; PropertyChanged.Raise(() => Age); } } } private string _email = string.Empty; public string Email { get { return _email; } set { if (_email != value) { _email = value;

Page 20: silverlightSL04-Ch16

Silverlight 4 ٣٥١ PropertyChanged.Raise(() => Email);

} } } public event PropertyChangedEventHandler PropertyChanged; #region IDataErrorInfo Members public string Error { get { return null; } } public string this[string columnName] { get { switch (columnName) { case "Name": if (string.IsNullOrEmpty(Name)) return "Name is required"; break; case "Age": if (Age > 60 || Age < 25) return "Age should be between 25-60"; break; case "Email": if (string.IsNullOrEmpty(Email)) { return "Email is required"; } if (!Email.Contains("@") && !Email.Contains(".")) { return "Email is Invalid"; } break; default: break; } return string.Empty; } } #endregion } }

Page 21: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٥٢

امكان دريافت ، IDataErrorInfoاينترفيس Indexerدهاي قبل نيز مشخص است، به كمك همانطور كه در ك

منتسب به هر كدام از خواص شيء جاري بررسي شده و در هايسپس مقدار. وجود دارد مدلنام خواص ه اي حاوي متن خطاي مورد نظر ارائ ها، تنها كافي است رشته صورت وجود خطايي در منطق تعيين اعتبار آن

.اين رشته به صورت خودكار به كاربر نمايش داده خواهد شد. گردد

اشياء )Asynchronous( ي تعيين اعتبار غير همزمان آشنايي با نحوه

كه هدف آن سازگاري INotifyDataErrorInfo اضافه شده است به نام Silverlight 4اينترفيس ديگري به asynchronous(تعيين اعتبار غيرهمزمان ميسر ساختنو Silverlightبيشتر با رفتار پيش فرض غيرهمزمان

validation (امضاي اين اينترفيس به شرح زير است .باشد مي: C#

public interface INotifyDataErrorInfo { bool HasErrors { get; } event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; IEnumerable GetErrors(string propertyName); }

توان وضعيت اعتبار كل يك شيء را مشخص ساخت؛ مي HasErrorsپس از پياده سازي آن، با كمك خاصيت ، اطالعات بيشتري را در مقايسه GetErrorsتوسط متد .پيش بيني نشده است IDataErrorInfoموردي كه در

همچنين در اين روش يك . توان ارائه داد مي IDataErrorInfoمرتبط با Indexerر با يك رشته ساده بازگشتي د .ارائه دهد نيز تواند بيش از يك خطاي اعتبار سنجي را خاصيت مي

بسيار مناسب است؛ ،در اينجا جهت كار با اعمال طوالني كه نياز به تعيين اعتبار دارند ErrorsChangedرخداد دريافت اطالعاتي از بانك اطالعاتي و سپس تعيين اعتبار مقادير ، WCF Serviceه يك براي مثال مراجعه بدر اينجا اگر پس از پايان عمليات و بررسي منطق اعتبار سنجي ، مشكلي وجود .بر اين اساس دريافتي از كاربرهاي الزم به كاربر مطلع امي پيغ ، رابط كاربر را جهت ارائه ErrorsChangedتوان به كمك رخداد داشته باشد، مي

تعريف شده در رابط كاربر برنامه، خاصيت Bindingدر اين حالت حتما نياز است تا در خواص .ساختValidatesOnNotifyDataErrors بهtrue هاي صادره از طرف رخداد تنظيم گردد تا رابط كاربر به پيغام

ErrorsChanged گوش فرا دهد.

Page 22: silverlightSL04-Ch16

Silverlight 4 ٣٥٣

يبررسي يك مثال كاربرد

در اين مثال قصد . به مثال بعد دقت بفرمائيدلطفا ، INotifyDataErrorInfo جهت درك بهتر كاربرد اينترفيس مقايسه WCF Serviceداريم در حين ثبت نام يك كاربر درسايت، نام كاربري او را با اطالعات دريافتي از يك

.)۳شكل ( به او نمايش دهيمنموده و در صورت وجود نام كاربري مشابه، پيغام خطايي را

نمايي از مثال تعيين اعتبار غيرهمزمان –۳شكل

نمايي از .آن آغاز نمائيد ASP.NET Web siteرا به همراه Silverlightي جديد براي اين منظور يك پروژه

.نمائيد مالحظه مي ۴هاي اين پروژه را در شكل هاي و پوشه ساختار فايلهاي قبل كتاب جاري توسعه يافتند كه در مثال Extensionsو DelegateCommandدر اين مثال از دو كالس

همچنين از ذكر مباحث امنيتي مرتبط با .گردد ها خودداري مي استفاده خواهد شد و از ذكر مجدد كدهاي آنWCF Service بديهي است موارد امنيتي ياد شده در فصل امنيت در . شود صرفنظر مينيزSilverlight را بايد . ها اعمال نمائيد ي نهايي آن هاي كاربردي خود پيش از ارائه ها و پروژه به كليه برنامه

Silverlight-enabled، يك Add new itemي پس از ايجاد ساختار اوليه پروژه، از منوي پروژه، گزينه

WCF Service را به نامValidateUser.svc ي به پروژه ۴مطابق شكلASP.NET كدهاي . برنامه اضافه كنيد :اند در ادامه ارائه شده WCF Serviceاين

Page 23: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٥٤

هاي پروژه تعيين اعتبار غير همزمان هاي و پوشه ساختار فايل –۴شكل

ValidateUser.svc.cs

using System.ServiceModel; using System.ServiceModel.Activation; using System.Threading; namespace SilverlightApplication69.Web { [ServiceContract(Namespace = "")] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class ValidateUser { [OperationContract] public bool IsValid(string userName) { //TODO: رعايت مسايل امنيتي ذكر شده در فصل امنيت //TODO: منطق دريافت اطالعات از بانك اطالعاتي را در اينجا پياده سازي نمائيد Thread.Sleep(2000); //شبيه سازي عملياتي طوالني

return userName.ToLower().Trim() != "vahid"; } } }

Page 24: silverlightSL04-Ch16

Silverlight 4 ٣٥٥

falseمقايسه شده و در صورت تساوي، vahidي نام كاربري دريافت شده با كلمه WCF Serviceتوسط اين . بازگشت داده خواهد شد

را Add service referenceي ژه، گزينهمراجعه نموده و از منوي پرو Silverlightي در ادامه به پروژه هاي اين دكمه قابليت تشخيص سرويس. كليك نمائيد Discoverي ي باز شده روي دكمه در صفحه. انتخاب كنيد

را ValidationServiceپس از انتخاب سرويس مورد نظر، نام . ي جاري را دارد تعريف شده در سطح پروژه .كليك نمائيد OKي وارد نموده و بر روي دكمه

در ادامه مالحظه خواهيد ،كه عمليات اعتبار سنجي نيز در آن قرار گرفته استرا برنامه Modelكدهاي كالس :نمود

UserInfo.cs

using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using SilverlightApplication69.Helper; namespace SilverlightApplication69.Models { public class UserInfo : INotifyPropertyChanged, INotifyDataErrorInfo { private string _name = string.Empty; public string Name { get { return _name; } set { if (_name != value) { _name = value; validateNameProperty(); PropertyChanged.Raise(() => Name); } } } private void validateNameProperty() { IsBusy = true; clearValidationErrors("Name"); var srv = new ValidationService.ValidateUserClient(); srv.IsValidCompleted += (o, h) => {

Page 25: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٥٦

if (h.Error != null) return; string errMsg = string.Format( "Account with the ID {0} already exists", Name); if (!h.Result) { addValidationError("Name",errMsg); } else { removeValidationError("Name", errMsg); } IsBusy = false; }; srv.IsValidAsync(Name); } private int _age; public int Age { get { return _age; } set { if (_age != value) { _age = value; validateAgeProperty(); PropertyChanged.Raise(() => Age); } } } private void validateAgeProperty() { const string errMsg = "Age should be between 25-60"; if (Age > 60 || Age < 25) { addValidationError("Age", errMsg); } else { removeValidationError("Age", errMsg); } } private bool _isBusy;

Page 26: silverlightSL04-Ch16

Silverlight 4 ٣٥٧ public bool IsBusy

{ get { return _isBusy; } set { if (_isBusy != value) { _isBusy = value; PropertyChanged.Raise(() => IsBusy); } } } public event PropertyChangedEventHandler PropertyChanged; #region INotifyDataErrorInfo Members public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; public System.Collections.IEnumerable GetErrors( string propertyName) { if (_errorList != null && _errorList.ContainsKey(propertyName)) return _errorList[propertyName]; return null; } public bool HasErrors { get { if (_errorList == null) return false; return _errorList.Any(); } } Dictionary<string, List<object>> _errorList; private void addValidationError(string propName, object error) { if (_errorList == null) _errorList = new Dictionary<string, List<object>>(); if (!_errorList.ContainsKey(propName)) _errorList[propName] = new List<object>(); if (!_errorList[propName].Contains(error))

Page 27: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در روش – ١٦ فصل

٣٥٨

{ _errorList[propName].Add(error); OnErrorsChanged(propName); } } private void removeValidationError(string propName, object error) { if (_errorList == null) _errorList = new Dictionary<string, List<object>>(); if (!_errorList.ContainsKey(propName)) _errorList[propName] = new List<object>(); if (_errorList[propName].Contains(error)) { _errorList[propName].Remove(error); OnErrorsChanged(propName); } } private void clearValidationErrors(string propName) { if (_errorList == null) return; if (!_errorList.ContainsKey(propName)) return; _errorList[propName] = new List<object>(); OnErrorsChanged(propName); } protected void OnErrorsChanged(string propName) { if (ErrorsChanged != null) ErrorsChanged(this, new DataErrorsChangedEventArgs(propName)); } #endregion } }

ي خاصيت هدف از ارائه. گردد ي برنامه از دو خاصيت نام و سن شخص ثبت نام كننده تشكيل مي مدل سادهIsBusy نمايش كنترل ،BusyIndicator ثانيه تاخيري است كه در سمت ۲در طيWCF Service ايجادرا پياده سازي INotifyDataErrorInfoو INotifyPropertyChangedكالس مدل برنامه دو اينترفيس . نموديم

.نموده است

Page 28: silverlightSL04-Ch16

Silverlight 4 ٣٥٩

مرسوم است كه به ازاي هر خاصيت تعريف شده يك متد INotifyDataErrorInfoهنگام استفاده از اينترفيس . تعيين اعتبار نيز در ذيل آن تعريف گردد كه در كدهاي فوق مشخص هستند

كه (شود انجام مي Nameر غيرهمزمان خاصيت ، كار تعيين اعتباvalidateNamePropertyتوسط متد ي ها است و نكته همانند مطالب عنوان شده در طي فصل آشنايي با بكارگيري وب سرويسجزئيات اعمال آن

از آنجائيكه اين عمليات طوالني است نياز است تا در ابتداي كار كليه خطاهاي مرتبط با اين ). جديدي نداردهاي مناسبي در صورت لزوم به سيستم اضافه سپس در پايان عمليات، پيغام خاصيت از سيستم حذف شده و

اين پاك سازي اوليه در حين اعتبار سنجي خاصيت سن صورت نگرفته است زيرا كدهاي آن وابسته به . گردند .خارجي نبوده و آني است WCF Serviceيك

ي پياده سازي همچنين نحوه. ضافه شده استيك سري متد كمكي نيز به اين كالس جهت افزودن حذف خطاها ا .نيز ذكر گرديده است HasErrorsو خاصيت GetErrorsمتد

، با پياده EntityBaseمرسوم است كه يك كالس كمكي را مثال به نام ،باتوجه به تكراري بودن اينگونه عمليات .برند ا از آن به ارث ميهاي ياد شده ، تشكيل داده و سپس كالس مدل برنامه ر سازي اينترفيس

:نمائيد برنامه را در ادامه مالحظه مي ViewModelكدهاي

UserInfoViewModel.cs

using System.Windows; using System.Windows.Input; using SilverlightApplication69.Helper; using SilverlightApplication69.Models; namespace SilverlightApplication69.ViewModels { public class UserInfoViewModel { public ICommand SaveUserInfo { set; get; } public UserInfo UserInfo { set; get; } public UserInfoViewModel() { UserInfo = new UserInfo(); SaveUserInfo = new DelegateCommand<UserInfo>( saveUserInfo, canSaveUserInfo); } private bool canSaveUserInfo(UserInfo arg) { return true; } private void saveUserInfo(UserInfo obj)

Page 29: silverlightSL04-Ch16

Silverlight هاي تعيين اعتبار ورودي كاربر در وشر – ١٦ فصل

٣٦٠

{ if (obj.HasErrors) { MessageBox.Show("Model is not valid"); return; } MessageBox.Show(string.Format("{0} Saved!", obj.Name)); } } }

همچنين يك خاصيت . وال رخدادگردان ذخيره سازي اطالعات كاربر را برعهده دارداين كالس كار مديريت ر

ي مهم آن نكته. دهد اي اصلي برنامه قرار مي برنامه يا همان صفحه Viewعمومي اطالعات كاربر را نيز در اختيار .اشدب آن مي اقدام به هرگونه عملياتي با محتوايپيش از شيء مدل، HasErrorsبررسي خاصيت

:برنامه را در ادامه مشاهده خواهيد نمود Viewمتناظر با XAMLكدهاي

MainPage.xaml

<UserControl x:Class="SilverlightApplication69.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc= "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:SilverlightApplication69.ViewModels" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" xmlns:toolkit= "http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"> <UserControl.Resources> <vm:UserInfoViewModel x:Key="vmUserInfoViewModel" /> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White" Margin="5" DataContext="{Binding Source={StaticResource vmUserInfoViewModel}}" > <Grid.ColumnDefinitions> <ColumnDefinition Width="88" /> <ColumnDefinition Width="184" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions>

Page 30: silverlightSL04-Ch16

Silverlight 4 ٣٦١ <TextBlock Text="Name:" HorizontalAlignment="Right"

Margin="5" Grid.Column="0" Grid.Row="0" /> <TextBlock Text="Age:" HorizontalAlignment="Right" Grid.Row="1" Margin="5" Grid.Column="0" /> <TextBox Grid.Column="1" Text="{ Binding UserInfo.Name, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" Margin="5" Width="auto" /> <TextBox Grid.Column="1" Text="{ Binding UserInfo.Age, Mode=TwoWay, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" Grid.Row="1" Margin="5" Width="auto" /> <Button Content="Save" Grid.Row="2" HorizontalAlignment="Right" Command="{Binding SaveUserInfo}" CommandParameter="{Binding UserInfo}" Margin="5" VerticalAlignment="Top" Width="75" /> <toolkit:BusyIndicator Grid.Column="2" Grid.Row="0" Margin="5" Height="20" IsBusy="{Binding UserInfo.IsBusy}" HorizontalAlignment="Left" BusyContent="Validating..." /> </Grid> </UserControl>