مرتب سازي
مرتب سازي را در انتهاي اين آموزش قرار داده ايم چون در واقع نياز به کدنويسي بيشتري دارد. به هر حال در اين مورد، View را تغيير چنداني نخواهيم داد (به جز تغيير در انقياد DataGrid). آنچه نياز به انجام آن مي باشد ايجاد مجموعه اي است که ICollectionView مورد نظر ما را پياده سازي کند.
به اين دليل نياز به انجام اين کار است که بتوانيم به رويدادهاي هدف مجموعه دسترسي داشته باشيم و وقتي کاربري DataGrid را مرتب مي کند آنها را کشف کنيم. در حال حاضر، DataGrid مرتب مي شود. اما فقط صفحه جاري مرتب مي شود. به جاي اين که اجازه دهيم DataGrid به طور خودکار مرتب سازي را انجام دهد، ما Web Service را فراخواني کرده و رکوردهاي آنرا مرتب مي کنيم و سپس صفحه جاري را با داده هايي که عمل مرتب سازي روي آنها انجام شده است نمايش مي دهيم.
در اينجا يه تجربه مرتب سازي صحيح را ارائه خواهيم کرد. براي مثال، اگر شما در صفحه دوم باشيد و رکورد ها را بر اساس شماره ID مرتب کنيد، صفحه دوم از کل مجموعه مرتب شده را مشاهده خواهيد کرد.
متد GetRIAComments Web Service تغيير دهيد طوري که پارامترهاي مرتب سازي را بتوان به آن پاس کرد تا بتوان از آنها براي انجام کوئري به کار برد:
#region GetRIAComments
[WebMethod]
public List<RIAComment> GetRIAComments(int intPage,
string SortProperty, string SortDirection)
{
// Create a collection to hold the results
List<RIAComment> colResult = new List<RIAComment>();
RIATasksDBDataContext DB = new RIATasksDBDataContext();
var colRIAComments = from RIAComments in DB.RIAComments
select RIAComments;
if (SortDirection == "Descending")
{
switch (SortProperty)
{
case "CommentID":
colRIAComments = colRIAComments.OrderByDescending(x => x.CommentID);
break;
case "Comment":
colRIAComments = colRIAComments.OrderByDescending(x => x.Comment);
break;
case "CommentUpdateDate":
colRIAComments =
colRIAComments.OrderByDescending(x => x.CommentUpdateDate);
break;
default:
colRIAComments = colRIAComments.OrderByDescending(x => x.CommentID);
break;
}
}
else
{
switch (SortProperty)
{
case "CommentID":
colRIAComments = colRIAComments.OrderBy(x => x.CommentID);
break;
case "Comment":
colRIAComments = colRIAComments.OrderBy(x => x.Comment);
break;
case "CommentUpdateDate":
colRIAComments = colRIAComments.OrderBy(x => x.CommentUpdateDate);
break;
default:
colRIAComments = colRIAComments.OrderBy(x => x.CommentID);
break;
}
}
// Compute the CurrentPage
int CurrentPage = ((intPage * 5) - 5);
// Implement paging
colRIAComments = colRIAComments.Skip(CurrentPage).Take(5);
// Loop thru the Tasks
foreach (var item in colRIAComments)
{
// Create a Task
RIAComment OutputRIAComment = new RIAComment();
// Get only the first 25 charaters of the comment
OutputRIAComment.CommentID = item.CommentID;
OutputRIAComment.Comment = Strings.Left(item.Comment, 25) + " ...";
OutputRIAComment.CommentUpdateDate = item.CommentUpdateDate;
// Add to the final results
colResult.Add(OutputRIAComment);
}
return colResult;
}
#endregion
روي wsRIARIAComments web reference کليک راست کرده و Update Service Reference کليک کنيد.
متد GetRIAComments موجود در Model را مطابق کدهاي زير تغيير دهيد:
#region GetRIAComments
public static void GetRIAComments(int intPage, string SortProperty,
string SortDirection, EventHandler<GetRIACommentsCompletedEventArgs> eh)
{
// Set up web service call
WebServiceSoapClient WS = new WebServiceSoapClient();
// Set the EndpointAddress
WS.Endpoint.Address = new EndpointAddress(GetBaseAddress());
WS.GetRIACommentsCompleted += eh;
WS.GetRIACommentsAsync(intPage, SortProperty, SortDirection);
}
#endregion
اين کد اجازه مي دهد پارامترهاي مرتب سازي به متد GetRIAComments موجود در وب سرويس پاس شود.
کدهاي زير را به خواص موجود در View Model اضافه کنيد:
#region ViewSource
private CollectionViewSource _ViewSource = new CollectionViewSource();
public CollectionViewSource ViewSource
{
get { return _ViewSource; }
private set
{
_ViewSource = value;
this.NotifyPropertyChanged("ViewSource");
}
}
#endregion
اين کد يک CollectionViewSource فراهم مي کند که مي توانيم ديتاگريد را به آن مقيد کنيم. وقتي اين کار انجام شد، DataGrid از View Source داخلي ديگر استفاده اي نخواهد کرد. سپس قادر خواهيم بود رويداد هاي مربوط به مرتب سازي را گير بياندازيم که در غير اين صورت انکان دسترسي به آنها غير ممکن خواهد بود.
Property هاي زير را به View Model اضافه کنيد:
#region SortProperty
private string _SortProperty;
public string SortProperty
{
get { return _SortProperty; }
private set
{
if (SortProperty == value)
{
return;
}
_SortProperty = value;
this.NotifyPropertyChanged("SortProperty");
}
}
#endregion
#region SortDirection
private string _SortDirection;
public string SortDirection
{
get { return _SortDirection; }
private set
{
if (SortDirection == value)
{
return;
}
_SortDirection = value;
this.NotifyPropertyChanged("SortDirection");
}
}
#endregion
خواص فوق فيلد جاري اي را که مرتب سازي براساس آن انجام شده و نيز جهتي (Direction) اي را که مرتب سازي بر اساس آن انجام شده را ذخيره خواهند کرد.
کدهاي زير با سازنده View Model اضافه کنيد:
// Connect the ViewSource to the Comments collection
// The DataGrid will be bound to the ViewSource so that it
// can implement sorting that we can wire-up an event handler to
ViewSource.Source = colRIAComments;
// Wire-up an event handler to the SortDescriptions collection on the ViewSource
INotifyCollectionChanged sortchangeNotifier =
ViewSource.View.SortDescriptions as INotifyCollectionChanged;
// Call View_CollectionChanged when the SortDescriptions collection is changed
sortchangeNotifier.CollectionChanged +=
new NotifyCollectionChangedEventHandler(View_Collectio nChanged);
اين کد، colRIAComments را به CollectionViewSource (ViewSource) تخصيص مي دهد.
سپس به يک کنترل کننده تغييرات در SortDescriptions مربوط به CollectionViewSource متصل مي شود. CollectionViewSource وقتي نوع مرتب سازي DataGrid که به collection مقيد است، تغيير مي يابد (هنگام کليک کاربر بروي سرستونهاي DataGrid) به طور خودکار مجموعه SortDescriptions را تغيير مي دهد.
کدهاي زير را براي پاسخ به رويداد به View Model اضافه کنيد:
#region View_CollectionChanged
void View_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// Clear the underlying collection to prevent the ViewSource
// from sorting the collection currently displayed in the ViewSource
// and then sorting it again after the web service call
colRIAComments.Clear();
// When the sort is in Add mode, it is the second (the last step)
// of defining a new Sort
if (e.Action == NotifyCollectionChangedAction.Add)
{
// re-query the datasource
GetRIAComments();
}
}
#endregion
متد فوق چندين بار فراخواني خواهدشد (يک براي هر Action اي که در مجموعه SortDescriptions قراردارد) و اين که وقتي بخواهيم عمل پرس و جو وب سرويس را مجدداً (re-query web service) انجام دهيم و رکورد ها را واکشي کنيم، مرتب سازي جاري را پاس خواهيم کرد.
متد زير را به کلاس بيافزاييد:
#region SetSortProperties
private void SetSortProperties()
{
// Set the Sort PropertyName and Direction
// If there is anything in the SortDescriptions collection
// Items are placed here when the Control attached to this ViewSource
// is sorted (for example, by clicking on the Header in the DataGrid)
if (ViewSource.View != null)
{
if (ViewSource.View.SortDescriptions.Count > 0)
{
SortProperty = ViewSource.View.SortDescriptions[0].PropertyName;
SortDirection = ViewSource.View.SortDescriptions[0].Direction.ToString();
}
}
}
#endregion
اين کد به مجموعه SortDescriptions نگاه مي کند و property (نام فيلد) ي که مرتب سازي و جهت دهي بايد بر اساس آنها انجام شود را بيرون مي کشد. اين مقادير در SortProperty و خواص SortDirection (که پيش از اين ايجاد شده بودند) قرار دارد. اين مقادير به Web Service پاسخ خواهند شد.
متد فوق به وسيله متد زير که تغيير يافته متد GetRIAComments است فراخواني خواهد شد:
#region GetRIAComments
private void GetRIAComments()
{
// Set Sort Properties if there are any
SetSortProperties();
// Call the Model to get the collection of RIAComments
RIACommentsModel.GetRIAComments(CurrentPage, SortProperty,
SortDirection, (Sender, EventArgs) =>
{
if (EventArgs.Error == null)
{
// Clear the current RIAComments
colRIAComments.Clear();
// loop thru each item
foreach (var RIAComment in EventArgs.Result)
{
// Add to the colRIAComments collection
colRIAComments.Add(RIAComment);
}
}
});
}
#endregion
اين متد Web Service را فراخواني کرده و صفحه رکوردها را واکشي خواهد کرد.
در آخرين مرحله پروژه را Build کنيد. سپس روي DataGrid کليک کنيد و در خواص آن در کنار ItemsSource گزينه Advanced options را انتخاب کنيد.
Data Binding... را انتخاب کنيد.
و آنرا به ViewSource>View مقيد کنيد.
حالا، اگر به صفحه آخر رفته و آنرا مرتب کنيد، کل مجموعه مرتب خواهد شد، (و نه فقط رکوردهاي قابل مشاهده در آخرين صفحه).
Style
به سادگي مي توانيد کل برنامه را قالب بندي (Theme) کنيد. ابتدا Silverlight Toolkit را نصب کنيد.
Theme را بيابيد و تم مورد نظر را انتخاب کنيد و . . .
. . . و آنرا روي [UserControl] رها کنيد.
برنامه قالب بندي مي شود.
ViewModel کد کمتر، واقعاً!
خوشحالم که تا انتهاي اين مقاله با ما بوديد و ديديد که کدنويسي View Model هميشه سخت نيست. با يک نگاه به چگونگي توليد آن متوجه خواهيد شد که اين شيوه ايجاد آن چندان پيچيده نيست. Expression Blend براي کار با “View Model Styel” طراحي شده است، بنابراين با استفاده از Expression Blend درهنگام به کارگيري اين الگوي ساده ، اوقات راحتري را خواهيد داشت.
در حالي که به نظر مي رسد پياده سازي يک DataGrid با استفاده از code-behind ساده تر است، اکثر اوقات متوجه خواهيد شد که مقدار کد زيادي را براي جستجو، تغيير مقادير و خواص در DataGrid بايد توليد کنيد.
کنترل هايي مانند DataGrid براي انقياد به مجموعه ها طراحي شده اند. View Model براي پياده سازي عمليات انقياد پياده سازي مي شود. View Model انقيادي است که موجب صرفه جويي در کدهاي شما خواهد شد. هنگامي که يک انقياد ايجاد مي شود، کاهش ميزان کدنويسي به خودي خود انجام مي شود. مجبور نيستيد که صراحتاً براي هر قسمت از عملکردها کد نويسي کنيد.
علاوه براين، متوجه شديد که بسياري از قابليت هاي برنامه نويسي به بهترين نحو در داخل منابع داده پياده سازي شده است و نه در خود DataGrid. همچنين توجه داشته باشيد که اين مثال از Web Service هاي استاندارد استفاده کرده است و شما مي توانيد به راحتي از WCF يا WCF RIA نيز استفاده کنيد. تغيير در نوع Web Service تاثيري بر روي View و View Model نداشته و به همين شکل خواهند بود.