Showing posts with label RIA. Show all posts
Showing posts with label RIA. Show all posts

Saturday, April 16, 2011

Datapager: Paging in RIA Application with MVVM

PagedEntitySet

This will help creating List of Entities that can be paged.

public class PagedEntitySet : INotifyPropertyChanged, INotifyCollectionChanged, IPagedCollectionView, IEnumerable
	where T : Entity, new()
{

	#region Private Members

	private IPagedCollectionView _pagingView;

	private IEnumerable Enumerable { get { return this._entityList; } }

	private EntitySet _entityList;

	#endregion

	#region IEnumerable Members

	public IEnumerator GetEnumerator()
	{
		return this._entityList.GetEnumerator();
	}

	#endregion

	#region IEnumerable Members

	IEnumerator IEnumerable.GetEnumerator()
	{
		return this.GetEnumerator();
	}

	#endregion

	#region Constructor

	public PagedEntitySet(EntitySet entityList, IPagedCollectionView delegatePagingView)
	{
		_entityList = entityList;
		INotifyCollectionChanged collectionChanged = _entityList as INotifyCollectionChanged;
		if (collectionChanged != null)
			collectionChanged.CollectionChanged += (s, e) => CollectionChanged(this, e);
		_pagingView = delegatePagingView;
		_pagingView.PageChanging += PageChanging;
		_pagingView.PageChanged += PageChanged;
		INotifyPropertyChanged propertyChanged = _pagingView as INotifyPropertyChanged;
		if (propertyChanged != null)
			propertyChanged.PropertyChanged += (s, e) => PropertyChanged(this, e);
	}

	#endregion

	#region INotifyPropertyChanged Members

	public event PropertyChangedEventHandler PropertyChanged = delegate { };

	#endregion

	#region INotifyCollectionChanged Members

	public event NotifyCollectionChangedEventHandler CollectionChanged = delegate { };

	#endregion

	#region IPagedCollectionView Members

	public bool CanChangePage
	{
		get { return _pagingView.CanChangePage; }
	}

	public bool IsPageChanging
	{
		get { return _pagingView.IsPageChanging; }
	}

	public int ItemCount
	{
		get { return _pagingView.ItemCount; }
	}

	public bool MoveToFirstPage()
	{
		return _pagingView.MoveToFirstPage();
	}

	public bool MoveToLastPage()
	{
		return _pagingView.MoveToLastPage();
	}

	public bool MoveToNextPage()
	{
		return _pagingView.MoveToNextPage();
	}

	public bool MoveToPage(int pageIndex)
	{
		return _pagingView.MoveToPage(pageIndex);
	}

	public bool MoveToPreviousPage()
	{
		return _pagingView.MoveToPreviousPage();
	}

	public event EventHandler PageChanged = delegate { };

	public event EventHandler PageChanging = delegate { };

	public int PageIndex
	{
		get { return _pagingView.PageIndex; }
	}

	public int PageSize
	{
		get { return _pagingView.PageSize; }
		set { _pagingView.PageSize = value; }
	}

	public int TotalItemCount
	{
		get { return _pagingView.TotalItemCount; }
	}

	#endregion

}

PagedViewModelBase
This abstract class will help binding your view model to view page with paging functionality.

public abstract class PagedViewModelBase: IPagedCollectionView, INotifyPropertyChanged
{

	#region Member Properties

	private static PropertyChangedEventArgs IsPageChangingChangedEventArgs = new PropertyChangedEventArgs("IsPageChanging");

	private static PropertyChangedEventArgs ItemCountChangedEventArgs = new PropertyChangedEventArgs("ItemCount");

	private static PropertyChangedEventArgs PageIndexChangedEventArgs = new PropertyChangedEventArgs("PageIndex");

	private static PropertyChangedEventArgs PageSizeChangedEventArgs = new PropertyChangedEventArgs("PageSize");

	private static PropertyChangedEventArgs TotalItemCountChangedEventArgs = new PropertyChangedEventArgs("TotalItemCount");

	private static PropertyChangedEventArgs IsLoadingChangedEventArgs = new PropertyChangedEventArgs("IsLoading");

	private bool _isLoading;

	public bool IsLoading
	{
		get { return _isLoading; }
		set
		{
			if (_isLoading != value)
			{
				_isLoading = value;
				RaisePropertyChanged(IsLoadingChangedEventArgs);
			}
		}
	}

	#endregion

	#region Member Functions

	public abstract void LoadData();

	#endregion

	#region INotifyPropertyChanged Members

	public event PropertyChangedEventHandler PropertyChanged;

	protected void RaisePropertyChanged(PropertyChangedEventArgs args)
	{
		if (PropertyChanged != null)
			PropertyChanged(this, args);
	}

	#endregion

	#region IPagedCollectionView Members

	public bool CanChangePage
	{
		get { return true; }
	}

	bool isPageChanging;

	public bool IsPageChanging
	{
		get { return isPageChanging; }
		private set
		{
			if (isPageChanging != value)
			{
				isPageChanging = value;
				RaisePropertyChanged(IsPageChangingChangedEventArgs);
			}

		}
	}

	int itemCount;

	public int ItemCount
	{
		get { return itemCount; }
		set
		{
			if (itemCount != value)
			{
				itemCount = value;
				RaisePropertyChanged(ItemCountChangedEventArgs);
			}
		}
	}

	public bool MoveToFirstPage()
	{
		return MoveToPage(0);
	}

	public bool MoveToLastPage()
	{
		return MoveToPage(TotalItemCount / PageSize);
	}

	public bool MoveToNextPage()
	{
		return MoveToPage(PageIndex + 1);
	}

	public bool MoveToPage(int index)
	{
		if (index == PageIndex || index < 0 || index > TotalItemCount / PageSize)
		{
			return false;
		}
		PageChangingEventArgs args = new PageChangingEventArgs(index);
		try
		{
			IsPageChanging = true;
			PageChanging(this, args);
			if (!args.Cancel)
			{
				pageIndex = index;
				LoadData();
				RaisePropertyChanged(PageIndexChangedEventArgs);
				PageChanged(this, EventArgs.Empty);
				return true;
			}
			return false;
		}
		finally
		{
			IsPageChanging = false;
		}
	}

	public bool MoveToPreviousPage()
	{
		return MoveToPage(PageIndex - 1);
	}

	public event EventHandler<EventArgs> PageChanged = delegate { };

	public event EventHandler<PageChangingEventArgs> PageChanging = delegate { };

	int pageIndex;

	public int PageIndex
	{
		get { return pageIndex; }
		set
		{
			if (pageIndex < 0 || pageIndex > totalItemCount / PageSize)
			{
				throw new ArgumentOutOfRangeException("PageIndex must be greater than or equal to 0 and less than the page count");
			}
			MoveToPage(value);
		}
	}

	int pageSize = 10; //default page size to 10

	public int PageSize
	{
		get { return pageSize; }
		set
		{
			if (pageSize != value)
			{
				pageSize = value;
				RaisePropertyChanged(PageSizeChangedEventArgs);
			}
		}
	}

	int totalItemCount;

	public int TotalItemCount
	{
		get { return totalItemCount; }
		set
		{
			if (totalItemCount != value)
			{
				totalItemCount = value;
				RaisePropertyChanged(TotalItemCountChangedEventArgs);
			}
		}
	}
	
	#endregion
}

This both Class will help you to easily bind your datagrid and datapager.
Just use PagedEntitySet type for binding data in your viewmodel for both datagrid and datapager.
Use constructor to initialize data in it.

This is the easiest way I find. If you have some more smart code please share it. Hope this will save a lot of your time. Happy Coding..

Friday, October 8, 2010

MVVM with WCF RIA Services

MVVM without RIA:
·         MVVM relies on the concept that View (XAML) will not contact your Model directly.
·         View will contact Model via ViewModel classes.
·         ViewModel talks with View using Data Binding and Commanding in XAML based applications.
·         ViewModel talks with Model via web service communication in case of Silverlight when we don’t use RIA Service.




MVVM with RIA:

·         RIA Service abstracts the web service layer from developer’s perspective and presents on client an identical set of classes that we have in model on server.
·         This simply means that under normal MVVM scenario we just change the communication between ViewModel and Model to go via the auto generated model classes on client side instead of explicitly calling web services (though internally it is still WCF communication).
·         In my opinion, this should not pose any problems to the MVVM pattern given that we keep the communication link same as above.



Cautions/DON’Ts:

·         We should never attach the auto generated client model classes of RIA with View directly. This link of View to Model should happen via ViewModel only. In a nutshell, these auto-generated model classes should never be considered as ViewModel.

·         We also have the availability of some RIA controls like DomainDataSource (in XAML). In case of MVVM we should NEVER use any such RIA controls in XAML since they break the very pillar of MVVM by contacting auto generated client side model of RIA directly (which is same as above point).

Friday, July 30, 2010

RIA Services - Presentation Model & POCO Objects

RIA Services handles any relationship other than Many to Many. If you have a Many to Many you will need to have a linking entity between the two tables.

Each Entity POCO on the server needs to have a primary key (you mark the key(s) with the KeyAttribute). Related entities need a foreign key property and you need to mark the relationships with AssociationAttributes.

RIA Services is good at lazy loading, but you have to manually trigger the loads it will not do it automatically. If you want to load the Companies and the Employees at the same time then you need to decorate the association properties with the IncludeAttribute. If you don't want to include them then you don't. Because RIA Services is based on keys and foreign keys, you can load the Companies up in one load and then later if you want them load up the Employees and the relationships between the two tables will automatically link back on on the client based on the values of the foreign keys.

A few good resources to look at what be documentation of what RIA Services calls a Presentation Model:

http://msdn.microsoft.com/en-us/library/ee707347(VS.91).aspx

and there is a simple example of how the attributes work here:

http://tech.rofas.net/post/Working-with-associated-POCO-objects-in-WCF-RIA-Services.aspx