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..

Tuesday, April 12, 2011

Implementing RelayCommand in easiest way

public class RelayCommand<T> : ICommand
{
        Action<T> _TargetExecuteMethod;

        Func<T, bool> _TargetCanExecuteMethod;

        public RelayCommand(Action<T> executeMethod)
        {
            _TargetExecuteMethod = executeMethod;
        }

        public RelayCommand(Action<T> executeMethod, Func<T,bool> canExecuteMethod)
        {
            _TargetExecuteMethod = executeMethod;
            _TargetCanExecuteMethod = canExecuteMethod;
        }

        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }

        #region ICommand Members
        bool ICommand.CanExecute(object parameter)
        {
            if (_TargetCanExecuteMethod != null)
            {
                T tparm = (T)parameter;

                return _TargetCanExecuteMethod(tparm);
            }

            if (_TargetExecuteMethod != null)
            {
                return true;
            }

            return false;
        }

        // Beware - should use weak references if command instance lifetime is longer than lifetime of UI objects that get hooked up to command

        // Prism commands solve this in their implementation

        public event EventHandler CanExecuteChanged = delegate { };

        void ICommand.Execute(object parameter)
        {
            if (_TargetExecuteMethod != null)
            {
               _TargetExecuteMethod((T)parameter);
            }
        }
        #endregion

}