View Full Version : حرفه ای: استفاده از کنترل Silverlight DataGrid در الگویMVVM-قسمت اول
piroozman
شنبه 30 فروردین 1393, 22:29 عصر
Silverlight Datagrid Silverlight Datagrid کنترلی قدرتمند است که به شما اجازه ویرایش درون خطی (inline editing)، صفحه بندی (paging)، مرتب سازی (sorting) و چینش (جابجایی) مجدد ستونها (drop re-ordering columns) را می دهد. درک چگونگی استفاده از این کنترل با تکنیک های معمول code-behind می تواند چالش برانگیز باشد، اما گاهی اوقات استفاده از این کنترل با استفاده از سبک برنامه نویسی View Model / MVVM بسیار گیج کننده خواهد بود.
در این مثال، در View Model ارجاع مستقیمی به DataGrid نخواهیم داشت. کدهای ارائه شده را می توانید برای هر یک از کنترلهای Collection دیگر مانند ListBox به کار برده و آنها را استفاده کنید.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img32.jpg
نکته: اگر با سبک برنامه نویسی View Model آشنا نیستید، پیشنهاد می شود به صفحه Silverlight View Model Style: An (Overly) Simplified Explanation (http://openlightgroup.net/Blog/tabid/58/EntryId/89/Silverlight-MVVM-An-Overly-Simplified-Explanation.aspx) مراجعه کنید.
در اصل عملیاتهای خود را روی DataGrid انجام نمی دهید، بلکه Collection متصل به دیتاگرید را دستکاری می کنید.
یکی از نکات اولیه جهت شناخت کنترل Silverlight Datagrid این است که این کنترل از "View of the Data" استفاده می کند که یک ICollectionView را پیاده سازی می کند. طبق نظر شرکت مایکروسافت در لینک زیر
http://msdn.microsoft.com/en-us/library/system.componentmodel.icollectionview(VS.95).aspx (http://msdn.microsoft.com/en-us/library/system.componentmodel.icollectionview%28VS.95%29.a spx)
"کنترل دیتاگرید از رابط ICollectionView برای نمایش داده های (indicated functionality ) موجود در منبع داده تخصیصی به ItemsSource Property استفاده می کند. اگر خصیصه ItemsSource، Ilist را پیاده سازی کند اما ICollectionView را پیاده سازی نکند، دیتاگرید ItemsSource را در یک ICollectionView قرار می دهد.”
در مثالهای اولیه، صرفاً یک مجموعه را به DataGrid متصل کرده و اجازه می دهیم CollectionView به طور خودکار ایجاد شود. در مثال Sorting، ما CollectionViewSource را پیاده سازی می کنیم، طوری که بتوانیم رویدادها را به تله انداخته و آنها را شناسایی کنیم.
متوجه خواهید شد که وقتی کنترلی روی مجموعه دیتاگرید به View Model متصل می شود، تمامی کنترلهای مورد نیاز جهت پیاده سازی قابلیت مورد انتظار به ما ارائه خواهد شد.
برای آشنایی با تمامی متدها و خواص DataGrid به صفحه زیر مراجعه کنید.
http://msdn.microsoft.com/en-us/library/system.windows.controls.datagrid_methods(v=VS.95). aspx (http://msdn.microsoft.com/en-us/library/system.windows.controls.datagrid_methods%28v=VS.95 %29.aspx)
در این آموزش از Visual Studio 2010 (یا بالاتر) و Expression Blend 4 (یا بالاتر) استفاده کنید.
برنامه کاربردی
http://www.codeproject.com/KB/silverlight/RIADataGrid/imgC1.jpg
برنامه کاربری این اجازه را می دهد که با کلیک روی سر ستون ها (column headers) عملیات مرتب سازی صورت پذیرد و صفحه بندی با استفاده از دکمه هایی در پایین DataGrid پیاده سازی شده است.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img62.jpg
می توانید با جابجا کردن سر ستون ها چینش آنها را تغییر دهید.
http://www.codeproject.com/KB/silverlight/RIADataGrid/imgE1.jpg
فیلد Comment فقط 25 کاراکتر اول را نشان می دهد مگر اینکه بخواهید آنرا ویرایش کنید.
با دبل کلیک کردن روی یکی از فیلهای Comment خواهید توانست آنرا ویرایش کنید. با کلیک در هر قسمت از برنامه کاربردی به غیر از جعبه متن در حال ویرایش، توضیحات ورودی شما ذخیره خواهد شد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img61.jpg
با کلیک روی دکمه Clear محتویات فیلد Comment همان ردیف به **** تغییر پیدا خواهد کرد.
نمایش آیتم ها در یک DataGrid
http://www.codeproject.com/KB/silverlight/RIADataGrid/img6D.jpg
حال نمایش ساده ی آیتم ها در یک DataGrid آغاز می کنیم.
http://www.codeproject.com/KB/silverlight/RIADataGrid/imgC.jpg
ابتدا یک پروژه Silverlight همراه با یک website ایجاد کنید.
سپس دیتابیسی با نام RIATasks ایجاد کرده و جدول RIAComments را به آن اضافه کنید.
USE [RIATasks]
GO
CREATE TABLE [dbo].[RIAComments](
[CommentID] [int] IDENTITY(1,1) NOT NULL,
[Comment] [nvarchar](max) NOT NULL,
[CommentUpdateDate] [datetime] NOT NULL,
CONSTRAINT [PK_RIAComments] PRIMARY KEY CLUSTERED
(
[CommentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO یک کلاس LINQ to SQL به سایت RIADataGrid.Web با نام RIATasksDB.dbml اضافه کنید.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img4.gif
روی لینک ServerExplorer کلیک کنید.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img30.jpg
یک ارتباط به پایگاه داده RIATasks ایجاد کرده و جدول RIAComment را روی سطح Object Relational Designer بکشید.
http://www.codeproject.com/KB/silverlight/RIADataGrid/imgD.jpg
فایل را ذخیره کرده و ببندید.
ساخت وب سرویس
http://www.codeproject.com/KB/silverlight/RIADataGrid/imgF.jpg
اکنون یک متد Web Service که ایتم های موجود در جدول را با استفاده از کدهای زیر برمی گرداند ایجاد کنید.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using Microsoft.VisualBasic;
namespace RIADataGrid.Web
{
[WebService(Namespace = "http://OpenLightGroup.net/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class WebService : System.Web.Services.WebService
{
// Web Methods
#region GetRIAComments
[WebMethod]
public List<RIAComment> GetRIAComments()
{
RIATasksDBDataContext DB = new RIATasksDBDataContext();
var colRIAComments = (from RIAComments in DB.RIAComments
select RIAComments).ToList();
return colRIAComments;
}
#endregion
}
}
http://www.codeproject.com/KB/silverlight/RIADataGrid/img16.jpg
در پروژه Silverlight یک Service Reference با نام wsRIARIAComments اضافه کنید.
همچنین به این پروژه یک ارجاع به اسمبلی Microsoft.VisualBasic نیز باید اضافه شود.
به منظور فراخوانی متد موجود در Web Service می بایست یک Model در پروژه کاربردی Silverlight ایجاد کرد. برای مطالعه ادامه مقاله به قسمت دوم مراجعه کنید.
piroozman
شنبه 30 فروردین 1393, 22:35 عصر
ساخت مدل
http://www.codeproject.com/KB/silverlight/RIADataGrid/img15.jpg
به منظور فراخواني متد موجود در Web Service يک Model در پروژه کاربردي Silverlight ايجاد کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img19.jpg
يک پوشه با نام Model ايجاد کرده و يک کلاس تحت عنوان RIACommentsModel.cs که شامل کدهاي زير باشد به آن اضافه کنيد.
using Microsoft.VisualBasic;
using System.Linq;
using System;
using System.Collections.Generic;
using System.ServiceModel;
using RIADataGrid.wsRIARIAComments;
using RIADataGrid;
namespace RIADataGrid
{
public class RIACommentsModel
{
#region GetRIAComments
public static void GetRIAComments(
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();
}
#endregion
// Utility
#region GetBaseAddress
private static Uri GetBaseAddress()
{
// Get the web address of the .xap that launched this application
string strBaseWebAddress = App.Current.Host.Source.AbsoluteUri;
// Find the position of the ClientBin directory
int PositionOfClientBin =
App.Current.Host.Source.AbsoluteUri.ToLower().Inde xOf(@"/clientbin");
// Strip off everything after the ClientBin directory
strBaseWebAddress = Strings.Left(strBaseWebAddress, PositionOfClientBin);
// Create a URI
Uri UriWebService = new Uri(String.Format(@"{0}/WebService.asmx",
strBaseWebAddress));
// Return the base address
return UriWebService;
}
#endregion
}
}
اين کلاس به ما اين اجازه را خواهد داد که متد وب سرويس GetRIAComment را در View Model فراخواني کنيم. ساخت View Model
http://www.codeproject.com/KB/silverlight/RIADataGrid/img13.jpg
سپس يک View Model ايجاد مي کنيم که منطق برنامه نويسي ما را شامل خواهد شد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img23.jpg
پوشه اي با نام ViewModels ايجاد کرده و کلاسي تحت عنوان MainPageModel.cs که شامل کدهاي زير باشد به آن اضافه کنيد:
using System;
using System.Linq;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;
using System.Windows;
using RIADataGrid.wsRIARIAComments;
using Microsoft.VisualBasic;
using System.Windows.Controls;
using System.Windows.Data;
using System.Collections.Specialized;
namespace RIADataGrid
{
public class MainPageModel : INotifyPropertyChanged
{
public MainPageModel()
{
// The following line prevents Expression Blend
// from showing an error when in design mode
if (!DesignerProperties.IsInDesignTool)
{
// Get the RIAComments
GetRIAComments();
}
}
// Operations
#region GetRIAComments
private void GetRIAComments()
{
// Call the Model to get the collection of RIAComments
RIACommentsModel.GetRIAComments((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
// Collections
#region colRIAComments
private ObservableCollection<RIAComment> _colRIAComments
= new ObservableCollection<RIAComment>();
public ObservableCollection<RIAComment> colRIAComments
{
get { return _colRIAComments; }
private set
{
if (colRIAComments == value)
{
return;
}
_colRIAComments = value;
this.NotifyPropertyChanged("colRIAComments");
}
}
#endregion
// Utility
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
}
ما اين کلاس و ساير کلاسها را در بخش هاي بعدي گسترش مي دهيم. ولي اکنون فقط يک collection با نام colRIAComments را از نتايج به دست آمده از Web Service پر مي کنيم. حال پروژه را Build کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img12.jpg
در قسمت سوم View را ايجاد مي کنيم.
piroozman
شنبه 30 فروردین 1393, 22:39 عصر
ساخت View
http://www.codeproject.com/KB/silverlight/RIADataGrid/img12.jpg
http://www.codeproject.com/KB/silverlight/RIADataGrid/img3F.jpg
روي فايل MainPage.xaml کليک راست کرده و روي Open it in Expression Blend کليک کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img42.jpg
روي LayoutRoot در پنجره Objects and Timeline کليک کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img43.jpg
در Properties مربوط به LayoutRoot گزينه DataContext را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img44.jpg
MainPageModel. را انتخاب و روي OK کليک کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img6B.jpg
طبق شکل بالا در تب Data گزينه Create Sample Data from Class . . . را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img47.jpg
MainPageModel. را انتخاب و روي OK کليک کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img4A.jpg
روي دکمه Assets کليک کرده و يک DataGrid را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img4B.jpg
DataGrid را به روي MainPage بکشيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img49.jpg
colRIAComments را از قسمت Sample Data انتخاب کرده
http://www.codeproject.com/KB/silverlight/RIADataGrid/img4C.jpg
. . . و روي DataGrid رها کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img58.jpg
داده هاي نمونه در DataGrid به نمايش درخواهد آمد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img5A.jpg
نکته: اگر هيچ Columns را زير DataGrid در پنجره Objects and Timeline مشاهده نمي کنيد، برنامه Expression Blend را بسته و دوباره باز کنيد. وقتي پروژه را مجدداً باز کنيد ستونها را مشاهده خواهيد کرد.
قالب بندي ستونها
http://www.codeproject.com/KB/silverlight/RIADataGrid/img5D.jpg
در پنجره objects and Timeline ستون Comment را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img2.jpg
کليه خواص DataGrid را همانند تصوير فوق تنظيم کنيد.
نکته: مهم است که در Layout خصيصه Width به مقدار 1 و Star تنظيم شود. بدون انجام اين تنظيمات، دکمه Clear (که در مراحل بعدي همين آموزش ايجاد خواهد شد) کار نخواهد کرد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img60.jpg
سپس، در پنجره objects and Timeline، ستون CommentID را انتخاب کرده و برخي خواص آنرا مانند تصوير فوق تنظيم کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img64.jpg
در نهايت، در پنجره objects and Timeline، ستون CommentUpdateDate انتخاب کرده و برخي خواص آنرا مانند تصوير فوق تنظيم کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img66.jpg
ستون ID را به بالاي ستون Comment جابجا کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img50.jpg
روي نام پروپزه در پنجره Projects کليک راست کرده و آنرا روي Startup Project ست کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img51.jpg
روي صفحه .aspx کليک راست کرده (شايد در پروژه شما داراي نام …TestPage.aspx باشد) و آنرا به Startup ست کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img68.jpg
براي build و اجراي پروژه کليد F5 را بفشاريد. پروژه اجرا شده و در مرورگر وب شما باز خواهد شد.
piroozman
شنبه 30 فروردین 1393, 22:43 عصر
ويرايش درون خطي
در پروژه اين امکان را ايجاد خواهيم کرد که بتوان فيلد Comment را به صورت درون خطي (Inline Editing) ويرايش کرد. در اصل، قبلا اين امکان فعال شده است! چون ما گزينه IsReadOnly را در هنگام تعريف ستون Comment فعال نکرديم (به صورت un-checked است). حالا تصميم داريم که Comment هاي به روز شده را در ديتابيس ذخيره کنيم.
در ضمن، کاري مي کنيم که GetRIAComments در Web Service فقط 25 کاراکتر اول فيلد Comment را نشان دهد. اين کار موجب مي شود که برنامه سريعتر اجرا شود چون داده هاي کمتري براي نمايش فراخواني خواهند شد. وقتي کاربر Comment ي را ويرايش مي کند، موجب فراخواني متد Web Service شده و که کل Comment را بر ميگرداند و آنرا براي ويرايش در اختيار کاربر قرار مي دهد.
همچنين براي اطمينان از اين که فقط رکوردي را که از آخرين زمان بازيابي آن تغييري نداشته است، به روزرساني کنيم، متدي را پياده سازي خواهيم کرد.
افزودن Errors Property
http://www.codeproject.com/KB/silverlight/RIADataGrid/img3.jpg
صفحه Central Silverlight Business Rules Validation (http://www.codeproject.com/KB/silverlight/RiaValidation.aspx) نحوه افزودن Errors property به Partial Class يک جدول LINQ to SQL را آموزش داده است.
پوشه اي با نام Classes و فايلي تحت عنوان DataBaseParticalClass.cs را به پروژه اضافه کنيد و کدهاي زير را در آن قرار دهيد.
using System.Collections.Generic;
namespace RIADataGrid.Web
{
#region public partial class RIAComment
public partial class RIAComment
{
public List<string> Errors = new List<string>();
}
#endregion
}
تغيير Web Service
http://www.codeproject.com/KB/silverlight/RIADataGrid/imgF1.jpg
دو متد زير را به وب سرويس اضافه کنيد.
#region GetRIAComments
[WebMethod]
public List<RIAComment> GetRIAComments()
{
// 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;
// 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 = item.Comment.Substring(0, 25) + " ...";
OutputRIAComment.CommentUpdateDate = item.CommentUpdateDate;
// Add to the final results
colResult.Add(OutputRIAComment);
}
return colResult;
}
#endregion
#region GetRIAComment
[WebMethod]
public RIAComment GetRIAComment(int RIACommentID)
{
RIATasksDBDataContext DB = new RIATasksDBDataContext();
var result = (from RIAComments in DB.RIAComments
where RIAComments.CommentID == RIACommentID
select RIAComments).FirstOrDefault();
return result;
}
#endregion
#region UpdateRIAComment
[WebMethod]
public RIAComment UpdateRIAComment(RIAComment objRIAComment)
{
DateTime dtCurrentDate = DateTime.Now;
RIATasksDBDataContext DB = new RIATasksDBDataContext();
var result = (from RIAComments in DB.RIAComments
where RIAComments.CommentID == objRIAComment.CommentID
// This will only perform the update if the CommentUpdateDate matches
// the existing CommentUpdateDate in the database
where RIAComments.CommentUpdateDate == objRIAComment.CommentUpdateDate
select RIAComments).FirstOrDefault();
if (result != null)
{
result.Comment = objRIAComment.Comment.Substring(0, 10000);
result.CommentUpdateDate = dtCurrentDate;
DB.SubmitChanges();
// Update the CommentUpdateDate on the object that will be returned
objRIAComment.CommentUpdateDate = dtCurrentDate;
}
else
{
// The record could not be found because the CommentUpdateDate did not match
// Or the record was deleted
objRIAComment.Errors.Add("The record was not updated");
}
// Update comments to only show 25 characters
objRIAComment.Comment = objRIAComment.Comment.Substring(0, 25) + " ...";
return objRIAComment;
}
#endregionدر زير يک نماي کلي از متدهاي وب ارائه شده است:
• GetRIAComments – طوري تغيير داده شد که 25 کاراکتر اول به اضافه "..." که به انتهاي Comment ها افزوده مي شود را بر مي گرداند.
• GetRIAComment- اين متد تنهاي يک Comment را برمي گرداند. از اين متد جهت به دست آوردن کامل يک Comment وقتي کاربري در حال ويرايش درون خطي است استفاده مي شود.
• UpdateRIAComment- Comment ي را به روز رساني مي کند که فيلد CommentUpdateDate آن مطابق با Date همان رکورد موجود در Database باشد. همچنين در صورتي که عمليات به روز رساني با موفقيت به انجام برسد، Comment به روز رساني شده را برمي گرداند و در صورتي که عمليات به روزرساني به درستي انجام نشود، يک پيغام خطا به ليست Errors اضافه خواهد شد.
به روز رساني Web Reference
http://www.codeproject.com/KB/silverlight/RIADataGrid/img18.jpg
روي مرجع وب (Web Reference)wsRIARIAComments کليک راست کرده و گزينه Update Service Reference را انتخاب کنيد.
به روزرساني Model
http://www.codeproject.com/KB/silverlight/RIADataGrid/img1F.jpg
متدهاي زير به مدل موجود اضافه کنيد.
#region GetRIAComment
public static void GetRIAComment(int RIACommentID,
EventHandler<GetRIACommentCompletedEventArgs> eh)
{
// Set up web service call
WebServiceSoapClient WS = new WebServiceSoapClient();
// Set the EndpointAddress
WS.Endpoint.Address = new EndpointAddress(GetBaseAddress());
WS.GetRIACommentCompleted += eh;
WS.GetRIACommentAsync(RIACommentID);
}
#endregion
#region UpdateRIAComment
public static void UpdateRIAComment(RIAComment objRIAComment,
EventHandler<UpdateRIACommentCompletedEventArgs> eh)
{
// Set up web service call
WebServiceSoapClient WS = new WebServiceSoapClient();
// Set the EndpointAddress
WS.Endpoint.Address = new EndpointAddress(GetBaseAddress());
WS.UpdateRIACommentCompleted += eh;
WS.UpdateRIACommentAsync(objRIAComment);
}
#endregion
متدها صرفاً توابع Web Service را که اضافه کرده بوديد را فراخواني خواهند کرد.
نکته: چون پارامترهاي تابع GetRIAComments موجود در Web Service هيچ تغييري نداشتند لذا نيازي به تغيير اين متد در Model نبود.
The View Model
حالا بايد View Model را به روزرساني کرد. در ابتدا اجازه بدهيد يک Helper Class به پروژه اضافه خواهيم کرد که به ما در پياده سازي ICommand ها کمک خواهد کرد. ICommand ها جهت بالا آوردن رويدادها در View Model از طرف View به کار خواهند رفت.
The DelegateCommand Helper Class
http://www.codeproject.com/KB/silverlight/RIADataGrid/img20.jpg
در پوشه Classes کلاسي تحت عنوان DelegateCommand.cs ايجاد کنيد.
کدهاي زير را جايگزين کدهاي موجود کنيد.
using System.Windows.Input;
using System;
// From http://johnpapa.net/silverlight/
// 5-simple-steps-to-commanding-in-silverlight/
namespace RIADataGrid
{
public class DelegateCommand : ICommand
{
Func<object, bool> canExecute;
Action<object> executeAction;
bool canExecuteCache;
public DelegateCommand(Action<object> executeAction,
Func<object, bool> canExecute)
{
this.executeAction = executeAction;
this.canExecute = canExecute;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
bool temp = canExecute(parameter);
if (canExecuteCache != temp)
{
canExecuteCache = temp;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, new EventArgs());
}
}
return canExecuteCache;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
executeAction(parameter);
}
#endregion
}
}
اين کلاس اين اجازه را به ما مي دهد که به سادگي به ICommand ها احضار کنيم. براي اطلاعات بيشتر مي توانيد در خصوص اين کلاس مي توانيد به لينک زير مراجعه کنيد: http://johnpapa.net/silverlight/5-simple-steps-to-commanding-in-silverlight (http://johnpapa.net/silverlight/5-simple-steps-to-commanding-in-silverlight/)
View Model
http://www.codeproject.com/KB/silverlight/RIADataGrid/img27.jpg
Property هاي زير را به View Model اضافه کنيد.
#region MessageVisibility
private Visibility _MessageVisibility
= Visibility.Collapsed;
public Visibility MessageVisibility
{
get { return _MessageVisibility; }
private set
{
if (_MessageVisibility == value)
{ return; }
_MessageVisibility = value;
this.NotifyPropertyChanged("MessageVisibility");
}
}
#endregion
#region Errors
private ObservableCollection<string> _Errors
= new ObservableCollection<string>();
public ObservableCollection<string> Errors
{
get { return _Errors; }
private set
{
if (_Errors == value)
{ return; }
_Errors = value;
this.NotifyPropertyChanged("Errors");
}
}
#endregion
کد فوق يک property جهت نگهداري تمامي خطاهاي برگشت داده شده است و property ديگر اجازه نمايش (يا عدم نمايش) ليست خطا را مي دهد.
کدهاي زير را نيز به کلاس اضافه کنيد:
#region GetRIAComment
private void GetRIAComment(RIAComment Comment)
{
// Call the Model to get the full RIAComment
RIACommentsModel.GetRIAComment(Comment.CommentID, (Sender, EventArgs) =>
{
if (EventArgs.Error == null)
{
// Find the comment in the colRIAComments collection
var CommentInCollection = (from comment in colRIAComments
where comment.CommentID == EventArgs.Result.CommentID
select comment).FirstOrDefault();
if (CommentInCollection != null)
{
CommentInCollection.Comment = EventArgs.Result.Comment;
}
}
});
}
#endregion
#region UpdateRIAComment
private void UpdateRIAComment(RIAComment objRIAComment)
{
// Call the Model to UpdateRIAComment the RIAComment
RIACommentsModel.UpdateRIAComment(objRIAComment, (Sender, EventArgs) =>
{
if (EventArgs.Error == null)
{
// Find the comment
var CommentInCollection = (from comment in colRIAComments
where comment.CommentID == EventArgs.Result.CommentID
select comment).FirstOrDefault();
if (CommentInCollection != null)
{
// Update the Comment
CommentInCollection.Comment = EventArgs.Result.Comment;
CommentInCollection.CommentUpdateDate = EventArgs.Result.CommentUpdateDate;
}
// Show any errors
Errors = EventArgs.Result.Errors;
// Set the visibility of the Message ListBox
MessageVisibility = (Errors.Count > 0) ?
Visibility.Visible : Visibility.Collapsed;
}
});
}
#endregion
این متدها محتوي کامل فيلد Comments را استخراج مي کند و يک Comment را با فراخواني متدهاي مربوطه در Model به روزرساني مي کند.
کدهاي زير را به کلاس اضافه کنيد:
#region GetRIACommentsCommand
public ICommand GetRIACommentsCommand { get; set; }
public void GetRIAComments(object param)
{
GetRIAComments();
}
private bool CanGetRIAComments(object param)
{
return true;
}
#endregion
#region GetRIACommentCommand
public ICommand GetRIACommentCommand { get; set; }
public void GetRIAComment(object param)
{
GetRIAComment((RIAComment)param);
}
private bool CanGetRIAComment(object param)
{
return true;
}
#endregion
#region UpdateRIACommentCommand
public ICommand UpdateRIACommentCommand { get; set; }
public void UpdateRIAComment(object param)
{
// This is an Update
UpdateRIAComment((RIAComment)param);
}
private bool CanUpdateRIAComment(object param)
{
// Do not allow if there is no Current RIAComment
return (param as RIAComment != null);
}
#endregion
اين کد ICommand ها را پياده سازي مي کند. اين ICommand ها از طريق View با استفاده از Behavior ها فراخواني خواهند شد.
کدهاي زير را به constructor کلاس View Model اضافه کنيد:
GetRIACommentsCommand = new DelegateCommand(GetRIAComments, CanGetRIAComments);
GetRIACommentCommand = new DelegateCommand(GetRIAComment, CanGetRIAComment);
UpdateRIACommentCommand = new DelegateCommand(UpdateRIAComment, CanUpdateRIAComment);
اين کد ها با استفاده از کلاس کمکيDelegateCommand ، ICommand ها را راه اندازي مي کنند.
براي ساخت View به قسمت پنجم مقاله مراجعه کنيد.
piroozman
شنبه 30 فروردین 1393, 22:50 عصر
ساخت View
http://www.codeproject.com/KB/silverlight/RIADataGrid/img48.jpg
حال قصد تکميل View را داريم. پروژه را build کرده و سپس آنرا ببنديد و فايل MainPage.xaml را در Expression Blend جهت تشخيص Property هاي جديد باز کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img33.jpg
در پنجره Data Context، روي Errors Collection کليک کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img34.jpg
. . . و آن را به روي Design کشيده و رها کنيد. به طور خودکار يک ListBOx ايجاد شده که مقيد (bound) به collection مي باشد.
پس از ايجاد ListBox، اندازه ListBox طوري تغيير دهيد که در قسمت پايين گوشه سمت راست قرار بگيرد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img35.jpg
در پنجره Data Context، روي خصيصه MessageVisibility کليک کرده و آنرا روي Errors ListBox کشيده و رها کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img36.jpg
پنجره اي با نام Create Data Binding ظاهر خواهد شد. گزينه Visibility را براي Porperty of
[ListBox] انتخاب کرده و روي OK کليک کنيد.
افزودن Behavior ها
http://www.codeproject.com/KB/silverlight/RIADataGrid/img38.jpg
از قسمت Assets، InvokeCommand Action Behavior را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img39.jpg
آنرا کشيده و روي DataGrid در پنجره Objects and Timeline رها کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img3C.jpg
در Property هاي Behavior، در قسمت Event Name گزينه PreparingCellForEdit انتخاب کنيد. روي آيکون Data ind براي Command بعدي کليک کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img3D.jpg
فرمان (command) GetRIAComment را مقيد کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img63.jpg
به منظور ست کردن CommandParameter، Advanced options را انتخاب کنيد و سپس از منوي popup، گزينه Create Data Binding را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img41.jpg
DataGrid را انتخاب کرده و آنرا به SelectedItem مقيد کنيد.
مرحله قبلي را روي InvokeCommand Action Behavior ديگري با مشخصات زير تکرار کنيد.
• RowEditEnded به عنوان Event Name
• براي Command مقدار UpdateRIACommentsCommand انتخاب کنيد.
• در قسمت CommandParameter ، DataGrid را انتخاب کرده و مقدار SelectedItem را براي آن ست کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img4E.gif
کليد F5 را بزنيد تا برنامه Build و اجرا شود. شما فقط 25 کاراکتر اول هر Comment مشاهده خواهيد کرد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img52.jpg
وقتي روي يک رديف دبل کليک مي کنيد، Comment را به صورت کامل مشاهده خواهيد کرد و مي توانيد آنرا تغيير دهيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img4D.jpg
اگر زمان به روز رساني رکوردي در پايگاه داده را بعد از اين که آنرا ويرايش کرديد تغيير دهيد، تغييرات ذخيره نخواهد شد و خطا نمايش داده خواهد شد.
از اينکه تا اينجا ما را دنبال کرديد تشکر مي کنم. صبر کنيد هنوز تمام نشده است. در قسمت ششم به صفحه بندي DataGrid خواهيم پرداخت.
piroozman
شنبه 30 فروردین 1393, 22:58 عصر
متد GetRIACommetns را به صورت زير تغيير دهيد:
#region GetRIAComments
private void GetRIAComments()
{
// Call the Model to get the collection of RIAComments
RIACommentsModel.GetRIAComments(CurrentPage, (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
ICommand هاي زير را نيز اضافه کنيد:
#region PreviousPageCommand
public ICommand PreviousPageCommand { get; set; }
public void PreviousPage(object param)
{
CurrentPage--;
GetRIAComments();
}
private bool CanPreviousPage(object param)
{
// Must not already be on the first page
return (CurrentPage > 1);
}
#endregion
#region NextPageCommand
public ICommand NextPageCommand { get; set; }
public void NextPage(object param)
{
CurrentPage++;
GetRIAComments();
}
private bool CanNextPage(object param)
{
// There must be records to move to the next page
return (colRIAComments.Count > 0);
}
#endregion
و در نهايت، کدهاي زير را به Constructor اضافه کنيد:
PreviousPageCommand = new DelegateCommand(PreviousPage, CanPreviousPage);
NextPageCommand = new DelegateCommand(NextPage, CanNextPage);
View
http://www.codeproject.com/KB/silverlight/RIADataGrid/img72.jpg
دو دکمه به صفحه اضافه کنيد و عنوان آنرا نيز همانند شکل بنويسيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img76.jpg
يک InvokeCommandAction Behavior روي هر يک از دکمه ها قرار دهيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img40.jpg
در Properties مربوط به هر Behavior، براي EventName مقدار Click را انتخاب کنيد و روي Advanced Options کنار جعبه Command کليک کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img3C.gif
گزينه Data Binding... انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img77.jpg
و Behavior ها را به Command مربوطه مقيد کنيد ( يا PreviousPageCommand يا NextPageCommand)
http://www.codeproject.com/KB/silverlight/RIADataGrid/img7D.jpg
همانند شکل فوق.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img7F.jpg
با اجراي برنامه خواهيد ديد که صفحه بندي اجرا مي شود.
فراخواني يک ICommand از کليک يک دکمه درون DataGrid
در اين مرحله مي خواهيم دکمه اي را در هر رديف DataGrid قرار دهيم که با کليک بر روي آن Comment همان رديف را به مقدار **** تغيير دهد.
ابتدا کدهاي زير را به View Model اضافه کنيد:
#region ClearCommand
public ICommand ClearCommand { get; set; }
public void Clear(object param)
{
// Clear the Comment
RIAComment objRIAComment = (RIAComment)param;
objRIAComment.Comment = "****";
}
private bool CanClear(object param)
{
// Do not allow if there is no Current RIAComment
return (param as RIAComment != null);
}
#endregion
خط زير را به سازنده View Model بيافزاييد:
ClearCommand = new DelegateCommand(Clear, CanClear);
http://www.codeproject.com/KB/silverlight/RIADataGrid/imgA.jpg
در پنجره object and Tiemline روي DataGrid کليک راست کرده و يک DataGridTextColumn ايجاد کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/imgB.jpg
پس از افزودن ستون، آنرا به ابتداي تمامي ستونها منتقل کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img7.jpg
نکته: اگر با خطايي مضمون Value does not fall within the expected range مواجه شديد
http://www.codeproject.com/KB/silverlight/RIADataGrid/img8.jpg
شما DisplayIndex تکراري يا بدون شماره در کدهاي خود داريد. اين خطا را مي توانيد با مراجعه به کدهاي XAML و شماره گذاري درست ستونها رفع کنيد( ستونها را با شروع از صفر شماره گذاري کنيد).
http://www.codeproject.com/KB/silverlight/RIADataGrid/img37.jpg
مهم است که هر رديف در DataGrid به داده ها مقيد شود، در غير اينصورت شما هر وقت که بخواهيد پروژه را اجرا کنيد، با خطاي Value cannot be null مواجه خواهيد شد.
در Property ها براي رديف (ستوني که به تازگي آنرا اضافه کرده ايد)، گزينه Advanced options در کنار Binding را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img45.jpg
و آنرا به colRIAComments مقيد کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img4.jpg
پس از انجام عمل انقياد، ساير خواص باقي مانده را همانند تصوير فوق تنظيم کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/imgE.jpg
روي ستون مجدداً کليک راست کرده و سپس Edit a Copy مربوط به Edit CellStyle را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img21.jpg
در جعبه Create Style Resource، گزينه New را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img22.jpg
روي OK کليک کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img1A.jpg
در پنجره Create Style Resource روي OK کليک کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img29.jpg
حال بايد Style را ويرايش کنيد. روي Style کليک راست کرده و گزينه Edit Current را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img1D.jpg
روي ContentPresenter کليک کنيد. اين کار طراحي اصلي صفحه را تغيير خواهد داد طوري که شما مي توانيد Content Template را ويرايش کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img29.gif
يک دکمه را روي design page قرار دهيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img24.jpg
در خواص مربوط به Button:
• مقدار Margin ها را به 5 تغيير دهيد.
• محتوي Content را به Clear تغيير دهيد.
• روي دکمه کليک کرده سپس مقدار DataContext را . . .
http://www.codeproject.com/KB/silverlight/RIADataGrid/img26.jpg
. . . به View Model مورد استفاده MaingPage تنظيم کنيد.
اين کار به منظور انجام مي شود که Behavior ي که در مرحله بعدي افزوده خواهد شد قادر باشد ICommand هاي روي View Model اصلي ببيند، در غير اين صورت دامنه (scope) دکمه (و هر Behavior پيوست شده به آن) فقط به عناصر موجود در رديف DataGrid محدود خواهد شد.
به هر حال توجه داشته باشيد که آنچه که انجام داديم ساخت يک نمونه جديد از MainPageModel است. ICommand ي که آن را بالا خواهيم آورد (raise) به نمونه MainPageModel ي که به صفحه .xaml که UI (رابط کاربر) روي آن قرار دارد متصل نخواهد شد، بلکه به کپي ديگري از آن مقيد خواهد شد.
همچنين توجه کنيد که نمونه جديد MainPageModel براي هر رديف ايجاد خواهد شد و اين که در اين مثال، يک فراخواني در سازنده کلاس براي اخذ RIAComments وجود دارد که در هر بار فراخواني خواهد شد. بنابراين وقتي اين برنامه بارگذاري مي شود (load)، برنامه GetRIAComments Web Service را 6 بار بيشتر (extra times) فراخواني خواهد کرد. اين کار فقط روي صفحه اول انجام مي شود، اما ممکن است به انجام اين عمل در تمامي صفحات علاقه مند نباشيد.
اگر چندين بار نمونه سازي مي شود، راه حل ايجاد يک ViewModel جداگانه است که مانع از ايجاد تاثيرات ناخواسته شود. براي مطالعه بيشتر به آموزشي که در صفحه زير است مراجعه کنيد:
Deleting a Silverlight DataGrid Row With a Button on the Row (http://openlightgroup.net/Blog/TabId/58/PostId/57/Deleting-A-Silverlight-DataGrid-Row-With-A-Button-On-The-Row.aspx)
http://www.codeproject.com/KB/silverlight/RIADataGrid/img25.jpg
يک InvokeCommandAction Behavior روي دکمه قرار دهيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img28.jpg
در خواص مربوط به Behavior، EventName را برابر کليک قرار داده و Command آنرا روي ClearCommand ست کنيد.
contentPresenter (والد دکمه) به بستر رديف جاري مقيد است، بنابراين شما مي توانيد به راحتي DataContext آنرا به عنوان پارامتر ارسال کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img2E.jpg
در خواص مربوط به Behavior، روي Advanced options مربوط به CommandParameter کليک کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img31.jpg
پارامتر را به DataContext مربوط به ContentPresenter مقيد کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img53.jpg
کليد F5 را جهت ساخت و اجراي پروژه فشار دهيد.
وقتي روي دکمه Clear در يک رديف کليک مي کنيد، موجب تغيير محتواي Comment همان رديف به **** خواهد شد. شما مي توانيد به راحتي ICommand فراخواني شده به وسيله دکمه را به Update يا Delete يک Comment تغيير دهيد.
انشالله در قسمت بعد به مبحث مرتب سازي (Sorting) خواهيم پرداخت.
piroozman
شنبه 30 فروردین 1393, 23:02 عصر
مرتب سازي
مرتب سازي را در انتهاي اين آموزش قرار داده ايم چون در واقع نياز به کدنويسي بيشتري دارد. به هر حال در اين مورد، 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
http://www.codeproject.com/KB/silverlight/RIADataGrid/img18.jpg
روي 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 را فراخواني کرده و صفحه رکوردها را واکشي خواهد کرد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img55.jpg
در آخرين مرحله پروژه را Build کنيد. سپس روي DataGrid کليک کنيد و در خواص آن در کنار ItemsSource گزينه Advanced options را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img57.jpg
Data Binding... را انتخاب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img3A1.jpg
و آنرا به ViewSource>View مقيد کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img3D1.jpg
حالا، اگر به صفحه آخر رفته و آنرا مرتب کنيد، کل مجموعه مرتب خواهد شد، (و نه فقط رکوردهاي قابل مشاهده در آخرين صفحه).
Style
به سادگي مي توانيد کل برنامه را قالب بندي (Theme) کنيد. ابتدا Silverlight Toolkit را نصب کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img5.jpg
Theme را بيابيد و تم مورد نظر را انتخاب کنيد و . . .
http://www.codeproject.com/KB/silverlight/RIADataGrid/img6.jpg
. . . و آنرا روي [UserControl] رها کنيد.
http://www.codeproject.com/KB/silverlight/RIADataGrid/img9.jpg
برنامه قالب بندي مي شود.
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 نداشته و به همين شکل خواهند بود.
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.