Level 37
0◆
to level 38 |
AIfonsAdd a review about this player
Adding a new review will overwrite your old one. Any player can add a review. Good guy. Honors his flags and doesn't let ninjas get a away with stuff.
willod on Monday February 22, 2010 Attacks lower flags, watch out
rhettbuck on Monday February 22, 2010 LIAR !
mozzer on Saturday February 20, 2010 does not respect flag. asshole player. fag.
soid-exe on Friday February 19, 2010 seriously a bad player with very low intelligence
John Milton on Thursday February 18, 2010 Biggest cunt on earth!!!
disrespects flags!
ASSHOLE!
guys like u ruin the game
furzknoten on Friday February 12, 2010 The MVVM pattern allows applications to be divided up into separate layers that provide multiple benefits ranging from better code re-use to enhanced testing capabilities. This post will explain key concepts found in the MVVM pattern and attempt to present them in a way that is easy to understand. I?ll show some code along the way to demonstrate how the MVVM pattern can be used and provide a few alternatives when it comes to binding data. The code shown later in the post can be downloaded here. Getting Started with the MVVM Pattern The MVVM pattern defines three key parts including the Model, the View and the ViewModel. The following image shows a slide from a Silverlight course we offer that sums up the role of each part of the MVVM pattern in a concise way: Looking through the description of each part you can see that the Model represents the business domain which includes the model classes used (Customer, Order, etc.), data access code and business rules. In general you can think of the Model as representing the entities that live on the server as well as the objects that are responsible for interacting with the data store your application uses and filling entities with data. While some people feel that the Model represents only the model classes (classes like Customer, Order, etc.) used in the application I personally think of it more broadly and include data access code and business rules in the Model definition. Silverlight applications will call into the Model code through services written using WCF, ASMX, REST or even custom solutions. The View in MVVM represents the Silverlight screens that you build. This includes the XAML files and the code-beside files that are responsible for showing data to end users. The View's responsibilities include displaying data and collecting data from end users. A given View isn't responsible for retrieving data, performing any business rules or validating data. The ViewModel acts as the middle-man between the View and the Model. It's responsible for aggregating and storing data that will be bound to a View. For example, a ViewModel may contain a List<State> property and a List<Person> property that may be bound to two ComboBox controls in a View. The ViewModel will retrieve the values held by these two properties from the Model. By using a ViewModel the View doesn't have to worry about retrieving data and knows nothing about where data comes from. Additional players may be added into the Model-View-ViewModel mix to help segregate code even further. For example, I normally create a service agent class that is responsible for making calls from Silverlight to remote services. The service agent is responsible for initiating the service call, capturing the data that's returned and forwarding the data back to the ViewModel. By doing this the ViewModel classes can delegate data gathering responsibilities to the service agent. A given service agent can also be re-used across multiple ViewModel classes as needed. The image above shows how the service agent can be integrated into the MVVM pattern. When developers first start building Silverlight applications they typically add all of the code for the application into the XAML's code-beside file (MainPage.xaml.cs for example). Although this approach certainly works, by following the MVVM pattern you can take advantage of several inherent benefits including better code re-use, simplified maintenance, more modular code and enhanced testing support. I'll focus on the overall benefits achieved by building applications that are based on the MVVM pattern throughout the rest of this article. The Model There are many different ways that the Model can be created including using Microsoft's Entity Framework or LINQ to SQL technologies, nHibernate, PLINQO, SubSonic, custom solutions and more. The technology chosen is generally unique to a given company's development policies so I'm not going to go into a discussion of the pros and cons of each technology here. What's important is that one or more classes used by a Silverlight application are "modeled" using tools or by writing code by hand. This involves defining all of the properties that each class will expose. A simple example of a Model class is shown next: public class Person { public string FirstName { get;set;} public string LastName { get;set; } public int Age { get; set; } } Once the Model classes are in place they'll need to be populated with data from a data store which can be done by writing custom code or using ORM frameworks that handle mapping query results to object instances. Services will also need to be written to expose one or more of the Model classes used in a Silverlight application which can be done using WCF, ASMX or even custom REST services. The View and ViewModel Classes Once the Model is ready to go the View and ViewModel classes can be created. As mentioned earlier, a View represents a Silverlight screen that end users interact with which includes the XAML file and the associated code-beside file. Rather than adding all of the code to call the Model and retrieve data directly into the View's code-beside file, the View will rely on a ViewModel class to retrieve data and then bind to the properties of the ViewModel. ViewModel classes should implement an interface that's available in Silverlight called INotifyPropertyChanged which defines a single event named PropertyChanged. This event is used to notify different Silverlight bindings that data has changed for one or more properties so that controls can be updated automatically. Although INotifyPropertyChanged can be implemented directly on a ViewModel class, your application may have multiple ViewModel classes in it and writing the same code over and over tends to get old. Creating a base ViewModel class that handles implementing INotifyPropertyChanged is useful to minimize code and allow more re-use to occur in applications. The following code shows a class named ViewModelBase that implements the INotifyPropertyChanged interface. The class also provides an OnNotifyPropertyChanged method that can be used to raise the PropertyChanged event. public class ViewModelBase : INotifyPropertyChanged { protected void OnNotifyPropertyChanged(string p) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(p)); } } public bool IsDesignTime { get {return (Application.Current == null) || (Application.Current.GetType() == typeof(Application));} } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion } A ViewModel class can derive from ViewModelBase and automatically take advantage of the INotifyPropertyChanged interface. An example of a ViewModel class named PeopleViewModel that derives from the ViewModelBase class and defines several properties and methods is shown next: public class PeopleViewModel : ViewModelBase { IServiceAgent _ServiceAgent; Person _Person; ObservableCollection<Person> _People; public PeopleViewModel() : this(new ServiceAgent()) {} public PeopleViewModel(IServiceAgent serviceAgent) { if (!IsDesignTime) { _ServiceAgent = serviceAgent; GetPeople(); } } #region Properties public Person Person { get { return _Person; } set { if (_Person != value) { _Person = value; OnNotifyPropertyChanged("Person"); } } } public ObservableCollection<Person> People { get { return _People; } set { if (_People != value) { _People = value; OnNotifyPropertyChanged("People"); } } } #endregion public void GetPeople() { _ServiceAgent.GetPeople((s,e) => this.People = e.Result); } public void UpdatePerson() { _ServiceAgent.UpdatePerson(this.Person, (s, e) => { PeopleEventBus.OnOperationCompleted(this, new OperationCompletedEventArgs { OperationStatus = e.Result }); }); } } Looking through the code you'll see that PeopleViewModel defines two fields, two properties and two methods. Each property raises the PropertyChanged event as the set block is called by calling the OnNotifyPropertyChanged method defined in ViewModelBase. This notifies any controls bound to the properties that the values have changed which allows them to update the data they display automatically. Looking at the first constructor in PeopleViewModel you'll see that it forwards the call to a secondary constructor that accepts a parameter of type IServiceAgent. Why have two constructors? This approach allows testing frameworks to pass in different types of service agents to the ViewModel when running tests. When the ViewModel is called at runtime the parameterless constructor will be called and an instance of a ServiceAgent class (shown next) will be passed as the IServiceAgent parameter. From there, once the service agent object is passed into the ViewModel's constructor a call to a method named GetPeople is made which invokes a method on the service agent and passes a callback delegate. The WCF service is then called by the service agent and the results are assigned to the People property. public interface IserviceAgent { void GetPeople(EventHandler<GetPeopleCompletedEventArgs> callback); void UpdatePerson(Person p, EventHandler<UpdatePersonCompletedEventArgs> callback); } public class ServiceAgent : IServiceAgent { public void GetPeople(EventHandler<GetPeopleCompletedEventArgs> callback) { PeopleServiceClient proxy = new PeopleServiceClient(); proxy.GetPeopleCompleted += callback; proxy.GetPeopleAsync(); } public void UpdatePerson(Person p, EventHandler<UpdatePersonCompletedEventArgs> callback) { PeopleServiceClient proxy = new PeopleServiceClient(); proxy.UpdatePersonCompleted += callback; proxy.UpdatePersonAsync(p); } } Binding a ViewModel to a View Now that the ViewModel class is defined it can be bound to a View. This can be done declaratively in XAML or imperatively through code in the View's code-beside file. Imperative (or code-based) binding is typically accomplished by assigning a ViewModel instance to the layout root's DataContext property as shown next: this.LayoutRoot.DataContext = new PeopleViewModel(); An example of declaratively binding a ViewModel (which is my personal preference) to a View is shown next: <UserControl x:Class="ViewModelExample.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:converter="clr-namespace:ViewModelExample" xmlns:viewModel="clr-namespace:ViewModelExample.ViewModel" mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"> <UserControl.Resources> <viewModel:PeopleViewModel x:Key="ViewModel" /> </UserControl.Resources> <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource ViewModel}}"> </Grid> </UserControl> The ViewModel namespace is first referenced using an XML namespace prefix of "viewModel". The ViewModel is then defined in the UserControl's Resources section and given a key of "ViewModel" (note that any name can be chosen for the key). The key is important since it's used to hook the ViewModel to the DataContext of the layout root using the {Binding Source={StaticResource ViewModel}} syntax. The declarative binding will cause a new PeopleViewModel instance to be created at runtime which is then bound to the layout root's DataContext. Child controls of the layout root can then bind to properties on the ViewModel. An example of binding a ListBox to the ViewModel's People property and a StackPanel to the Person property is shown next: <StackPanel Margin="20"> <TextBlock Text="Binding Controls to a ViewModel" Margin="20,0,0,0" FontWeight="Bold" FontSize="12" /> <ListBox x:Name="lbPeople" Margin="0,10,0,0" Height="250" Width="300" HorizontalAlignment="Left" ItemsSource="{Binding People}" ScrollViewer.HorizontalScrollBarVisibility="Hidden" SelectedItem="{Binding Person, Mode=TwoWay}"> <ListBox.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="100" /> <ColumnDefinition Width="100" /> <ColumnDefinition Width="100" /> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Margin="10" Text="{Binding FirstName}" /> <TextBlock Grid.Column="1" Margin="10" Text="{Binding LastName}" /> <TextBlock Grid.Column="2" Margin="10" Text="{Binding Age}" /> </Grid> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <StackPanel DataContext="{Binding Person}"> <TextBlock Text="First Name" Margin="0,10,0,0" /> <TextBox Text="{Binding FirstName,Mode=TwoWay}" Width="100" Height="25" HorizontalAlignment="Left"/> <TextBlock Text="Last Name" /> <TextBox Text="{Binding LastName,Mode=TwoWay}" Width="100" Height="25" HorizontalAlignment="Left"/> <TextBlock Text="Age" /> <TextBox Text="{Binding Age,Mode=TwoWay}" Width="100" Height="25" HorizontalAlignment="Left"/> </StackPanel> <Button Margin="0,10,0,0" Click="Button_Click" Content="Submit" Height="20" Width="100" HorizontalAlignment="Left" /> </StackPanel> The MVVM pattern provides a flexible way to work with data that encourages code re-use and simplifies maintenance. There's much more that can be discussed with regard to the MVVM pattern in Silverlight such as event buses, commanding and dependency injection but I hope this post helps jumpstart the process of architecting and developing Silverlight applications. ________________________________________ Among the promises of frameworks such as Silverlight, Microsoft's plug-in for developing rich Internet applications, are lower development costs and shorter development cycles -- not to mention much more engaging and interactive Web content. But Silverlight also provides a broad range of networking features that can be used to access distributed data. Standard SOAP services such as those created using Active Server Methods Extension (ASMX) and Windows Communication Foundation (WCF) technologies can return a specific contract, and REST services can return custom data structures. Silverlight also supports direct socket communication for applications that require data to be pushed to them in real time. While these features work well, there's a price in terms of complexity because they rely on an asynchronous programming model and require code to be synchronized between Silverlight and server projects. Microsoft recognized the challenges of the asynchronous model and that sharing data validation rules between projects could be tricky. To simplify the process, it has developed WCF RIA Services, a data exchange and validation framework for Visual Studio 2008 and Visual Studio 2010. Silverlight applications can also use WCF RIA Services to authenticate users, check roles, access profile provides, query and modify data and even share data annotations. Getting Started with WCF RIA Services Once WCF RIA Services is installed, new templates appear when you create a new Silverlight project as in Figure 1. To get started using WCF RIA Services you'll need to add a domain service class that wraps a LINQ-to-SQL or Entity Framework model into the Web project. It's important to note that other ORM frameworks such as nHibernate aren't supported out-of-the-box, but can be integrated into WCF RIA Services by deriving from a base class named DomainService and overriding the appropriate methods. Brad Abrams provides an introductory look at using nHibernate with WCF RIA Services at http://tinyurl.com/kmbkfl. Figure 3 shows a simple LINQ to SQL diagram added into the Web project that models tables in the Northwind database. Once the ORM model is completed the project must be compiled so that the new objects are accessible to WCF RIA Services. After compiling, right-click on the project, select "Add --> New Item", then select the domain service Class template. The Add New Domain Service Class dialog window will appear which allows the desired DataContext or ObjectContext object to be selected (depending upon which Microsoft ORM was added into the project). The dialog window allows the entities that should be exposed by WCF RIA Services to be selected as well as whether or not the entities should support editing features (insert, update, delete). A metadata class can also be generated for each entity in cases where custom data annotations need to be applied for data validation. Figure 4 shows the Add New Domain Service Class dialog. Once the domain service class is added into the project it can be customized. Listing 1 is an example of the methods added into a domain service class for the Customer entity in Figure 3. [EnableClientAccess()] public class NorthwindDomainService : LinqToSqlDomainService<NorthwindDataContext> { public IQueryable<Customer> GetCustomers() { return this.DataContext.Customers; } public void InsertCustomer(Customer customer) { this.DataContext.Customers.InsertOnSubmit(customer); } public void UpdateCustomer(Customer currentCustomer) { this.DataContext.Customers.Attach(currentCustomer, this.ChangeSet.GetOriginal(currentCustomer)); } public void DeleteCustomer(Customer customer) { this.DataContext.Customers.Attach(customer); this.DataContext.Customers.DeleteOnSubmit(customer); } } A few things that are important to point out in the code shown in Listing 1 include the EnableClientAccess attribute which makes the class and its methods accessible to client applications such as Silverlight. Also note the IQueryable<Customer> type returned from the GetCustomers method. Any method returning IEnumerable<'T> or IQueryable<T> is treated as a query method by default in a domain service. In situations where a single object needs to be returned as opposed to a collection the [Query] attribute can be used as shown next. This example sets the QueryAttribute's IsComposable property to false since the client won't need to perform query operations (sorting or filtering) on the returned object. [Query(IsComposable=false)] public Customer GetCustomer(string custID) { return this.DataContext.Customers.Where(c => c.CustomerID == custID).SingleOrDefault(); } The other methods in Listing 1 automatically handle performing insert, update, and delete operations respectively due to their name being prefixed with Insert, Update or Delete. In situations where methods don't start with one of the built-in WCF RIA Services keywords, attributes can be applied above the methods as in Listing 2. [Insert] public void NewCustomer(Customer cust) { this.DataContext.Customers.InsertOnSubmit(cust); } [Update] public void SaveCustomer(Customer currentCustomer) { this.DataContext.Customers.Attach(currentCustomer, this.ChangeSet.GetOriginal(currentCustomer)); } [Delete] public void DestroyCustomer(Customer cust) { this.DataContext.Customers.Attach(cust); this.DataContext.Customers.DeleteOnSubmit(cust); } Calling WCF RIA Services Operations From Silverlight Once a domain service class is created it can be called from a Silverlight application without having to go through the process of generating a client-side proxy object using Add Service Reference. This is possible by the link between the Silverlight project and the Web project. After compiling the solution the Silverlight project will have a new folder added into it named Generated_Code (you'll need to click the Show All Files icon at the top of the Solution Explorer to see this folder). The code within the Generated_Code folder is automatically created during the build process and can be used to call the service. When the server-side code changes you don't have to update any service reference code like you would with a WCF service proxy. To call a WCF RIA Services operation, a client-side domain context class can be used that will be named after the domain service class that lives on the server-side. This client-side class is automatically generated and added to the Generated_Code folder mentioned earlier. If the server-side class is named NorthwindDomainService then the client-side domain context class will be named NorthwindDomainContext by default. The domain context class can be used directly in the Silverlight code-beside file or can be integrated into a ViewModel class in cases where the Model-View-ViewModel (MVVM) pattern is being used (see my blog post if you're interested in getting started with the MVVM pattern). Listing 3 is an example of using the domain context class within a ViewModel class named CustomersViewModel to call the WCF RIA Service and assign data returned from the service to Customers and Orders properties. using System.Linq; using System.Windows.Ria; using StarterSample.Web; namespace StarterSample.ViewModel { public class CustomersViewModel : ViewModelBase { EntitySet<Customer> _Customers; EntitySet<Order> _Orders; Order _CurrentOrder; NorthwindDomainContext _Context = null; public CustomersViewModel() { _Context = new NorthwindDomainContext(); this.Customers = _Context.Customers; this.Orders = _Context.Orders; GetCustomers(); } #region Properties public Order CurrentOrder { get { return _CurrentOrder; } set { if (_CurrentOrder != value) { _CurrentOrder = value; OnPropertyChanged("CurrentOrder"); } } } public EntitySet<Customer> Customers { get { return _Customers; } set { if (_Customers != value) { _Customers = value; OnPropertyChanged("Customers"); } } } public EntitySet<Order> Orders { get { return _Orders; } set { if (_Orders != value) { _Orders = value; OnPropertyChanged("Orders"); } } } #endregion private void GetCustomers() { _Context.Load<Customer>(_Context.GetCustomersQuery()); } public void GetOrders(string custID){ _Context.Orders.Clear(); _Context.Load<Order>(_Context.GetOrdersQuery(custID), lo => { if (lo.TotalEntityCount > 0) { this.CurrentOrder = this.Orders.Take(1).SingleOrDefault(); } }, null); } public void UpdateOrder() { _Context.SubmitChanges(); } } } Listing 3 Looking through the code you'll see that the Customers and Orders collection properties store an EntitySet<T> type as opposed to ObservableCollection<T>. EntitySet<T> is provided by WCF RIA Services and used to track changes that are made to objects as discussed later in the article. You'll also see that as the CustomersViewModel object's constructor is called an instance of the domain context class is created and used to access Customer and Order entities exposed by the service and assign them to the CustomersViewModel properties. Once the entities are assigned a call is made to GetCustomers which invokes the domain context object's Load<T> method. The type of query to load is passed into the method (GetCustomersQuery in this example which is automatically generated based upon the service query named GetCustomers; see Listing 1). Although the call to Load<T> looks synchronous it's actually asynchronous behind the scenes. As data is returned from the service it will be assigned to the CustomersViewModel object's Customers property due to the association created in the constructor. As a customer is selected in the Silverlight interface (see Figure 5) the GetOrders method in Listing 3 is called which handles loading all of the orders for the customer by calling Load<Order> and passing in the GetOrdersQuery that's automatically generated when the solution is compiled. Once the orders are returned back to the Silverlight client an inline callback method is invoked within the GetOrders method which accepts a LoadOptionsj parameter. LoadOptions provides a way to check for errors and access entities that were returned from the service. In this example a check is made to see if the LoadOptions object's TotalEntityCount property is greater than 0. If that condition is met the first order is assigned to the CustomersViewModel object's CurrentOrder property which displays in the DataFormcontrol shown to the end user (see Figure 5). Figure 5: The Silverlight interface gets its data from WCF RIA Services. The DataForm allows order data to be edited by the end user. In a typical Silverlight application that uses WCF or ASMX services, code would have to be written to track object changes and then send them back to a custom service operation. WCF RIA Services simplifies this process by tracking all objects defined in an EntitySet. As changes are made the data context object's SubmitChanges method can be called to send all changes back to the server for processing. An example of using SubmitChanges is shown next: public void UpdateOrder() { _Context.SubmitChanges(); } The appropriate Insert, Update or Delete methods defined in the domain service will be called after SubmitChanges is called in the Silverlight application. The sample application available here demonstrates other features such as the ability to access a customer's orders and edit the data using a DataForm control. Validating Data using WCF RIA Services WCF RIA Services provides a simple way to leverage .NET 3.5 data annotations to validate data as it is assigned to properties in entities. Data annotations located in the System.ComponentModel.DataAnnotations namespace such as Required, RegularExpression, StringLength, and CustomValidation can be added into a metadata class and used to validate data. The metadata class is added to the Web project automatically if the Generate associated classes for metadata checkbox is checked when the domain service is initially created (see Figure 4). Listing 5 shows a portion of an OrderMetadata class that is generated by WCF RIA Services. Some of the fields within the class are decorated with the Required and CustomValidation data annotation attributes: internal sealed class OrderMetadata { [Required] public string CustomerID; [Required] public int OrderID; public string ShipAddress; public string ShipCity; public string ShipCountry; public string ShipName; [CustomValidation(typeof(StarterSample.Web.DateValidator), "ValidateDate")] public Nullable<DateTime> ShippedDate; } Listing 5: A metadata class generated by WCF RIA Services. The CustomValidation attribute added above the ShippedDate field allows custom validation logic to be applied as data is assigned to the ShippedDate property in the Order entity. As data is set the DateValidator class's ValidateDate method is called which ensures that the year entered is less than or equal to the current year. If the year is correct a ValidationResult success value is returned whereas if the year is wrong a new ValidationResult object is returned containing a custom error message. The code for the DateValidator class is shown in Listing 6. The class is located in a file named NorthwindDomainService.shared.cs. Any files ending with "shared.cs" are automatically copied to the Silverlight project when the solution is built. public static class DateValidator { public static ValidationResult ValidateDate(DateTime dt, ValidationContext context) { if (dt.Year <= DateTime.Now.Year) { return ValidationResult.Success;} else { return new ValidationResult("The date must be less than or equal to the current year."); } } } Listing 6 Once the project is compiled the data annotations (including the custom annotation) will be included in the Silverlight project. Controls such as the DataForm can detect if the validation is valid or not for a given property and show error messages as appropriate as in Figure 6. Conclusion WCF RIA Services provides a framework for exchanging data between Silverlight applications and services. In this article you've been introduced to some of the fundamentals of WCF RIA Services including creating a domain service class, using a domain context class to call remote service operations and validating property data. WCF RIA Services supports additional objects and features that weren't covered such as using the DomainDataSource control and performing authentication
gursu on Monday February 8, 2010
gursu on Thursday February 11, 2010
Alfons you are sore loser and a fukn liar. I have never PGA'ed with anyone. Just had a quick look at your reviews , obviously you have some mental/emotional issues and there are some medications available that may be beneficial to you.Please see a doctor , take your pills , lie down and go fuck yourself . Cheers Peter.Get well soon.
peterpeter on Tuesday February 9, 2010 Alfons is just a liar.shame on you
okaym on Tuesday February 9, 2010 are u ok?
flag under me on Monday February 8, 2010 |