Click here to Skip to main content
15,894,896 members
Articles / DevOps / Testing

Composite Application Reloaded

Rate me:
Please Sign up or sign in to vote.
4.88/5 (38 votes)
11 May 2011CPOL12 min read 118.2K   1.5K   95  
A much simpler composite application library.
using System;
using System.ComponentModel;
using System.Windows.Input;
using DemoApp.DataAccess;
using DemoApp.Model;
using DemoApp.Properties;
using Galador.Applications;
using Galador.Applications.Validation;

namespace DemoApp.ViewModel
{
	/// <summary>
	/// A UI-friendly wrapper for a Customer object.
	/// </summary>
	public class CustomerViewModel : WorkspaceViewModel
	{
		readonly Customer _customer;
		readonly ICustomerRepository _customerRepository;

		#region Constructor

		public CustomerViewModel(Customer customer, ICustomerRepository customerRepository)
		{
			if (customer == null)
				throw new ArgumentNullException("customer");

			if (customerRepository == null)
				throw new ArgumentNullException("customerRepository");

			_customer = customer;
			_customerRepository = customerRepository;
			_customer.PropertyChanged += delegate
			{
				if(_saveCommand != null)
					_saveCommand.RaiseCanExecuteChanged(); 
			};

			if (IsNewCustomer)
			{
				CustomerType = Strings.CustomerViewModel_CustomerTypeOption_NotSpecified;
			}
			else
			{
				CustomerType = Customer.IsCompany
					? Strings.CustomerViewModel_CustomerTypeOption_Company
					: Strings.CustomerViewModel_CustomerTypeOption_Person;
				TotalSales = Customer.TotalSales.ToString();
			}
		}

		#endregion // Constructor

		public Customer Customer { get { return _customer; } }

		#region CustomerType, CustomerTypeOptions, CustomerTypeError()

		/// <summary>
		/// Gets/sets a value that indicates what type of customer this is.
		/// This property maps to the IsCompany property of the Customer class,
		/// but also has support for an 'unselected' state.
		/// </summary>
		[DelegateValidation("CustomerTypeError")]
		public string CustomerType
		{
			get { return _customerType; }
			set
			{
				if (value == _customerType || String.IsNullOrEmpty(value))
					return;

				_customerType = value;

				if (_customerType == Strings.CustomerViewModel_CustomerTypeOption_Company)
				{
					_customer.IsCompany = true;
				}
				else if (_customerType == Strings.CustomerViewModel_CustomerTypeOption_Person)
				{
					_customer.IsCompany = false;
				}

				base.OnPropertyChanged(() => CustomerType);

				// Since this ViewModel object has knowledge of how to translate
				// a customer type (i.e. text) to a Customer object's IsCompany property,
				// it also must raise a property change notification when it changes
				// the value of IsCompany.  The LastName property is validated 
				// differently based on whether the customer is a company or not,
				// so the validation for the LastName property must execute now.
				_customer.RaisePropertyChanged(c => c.LastName);
			}
		}
		string _customerType;

		public string CustomerTypeError()
		{
			if (this.CustomerType == Strings.CustomerViewModel_CustomerTypeOption_Company ||
			   this.CustomerType == Strings.CustomerViewModel_CustomerTypeOption_Person)
				return null;

			return Strings.CustomerViewModel_Error_MissingCustomerType;
		}

		/// <summary>
		/// Returns a list of strings used to populate the Customer Type selector.
		/// </summary>
		public string[] CustomerTypeOptions
		{
			get
			{
				if (_customerTypeOptions == null)
				{
					_customerTypeOptions = new string[]
					{
						Strings.CustomerViewModel_CustomerTypeOption_NotSpecified,
						Strings.CustomerViewModel_CustomerTypeOption_Person,
						Strings.CustomerViewModel_CustomerTypeOption_Company
					};
				}
				return _customerTypeOptions;
			}
		}
		string[] _customerTypeOptions;

		#endregion

		#region TotalSales

		[ConversionValidation(typeof(double), ErrorMessageResourceType = typeof(Strings), ErrorMessageResourceName = "Customer_TotalSales_NotANumber")]
		[PropertyValidation("Customer.TotalSales")]
		public string TotalSales
		{
			get { return mTotalSales; }
			set
			{
				if (value == mTotalSales)
					return;
				mTotalSales = value;

				try { Customer.TotalSales = (decimal)ConversionValidationAttribute.TryConvert(value, typeof(decimal)); }
				catch { }

				OnPropertyChanged(() => TotalSales);
			}
		}
		string mTotalSales;

		#endregion

		#region DisplayName

		public override string DisplayName
		{
			get
			{
				if (this.IsNewCustomer)
				{
					return Strings.CustomerViewModel_DisplayName;
				}
				else if (_customer.IsCompany)
				{
					return _customer.FirstName;
				}
				else
				{
					return String.Format("{0}, {1}", _customer.LastName, _customer.FirstName);
				}
			}
		}

		#endregion

		#region IsSelected

		/// <summary>
		/// Gets/sets whether this customer is selected in the UI.
		/// </summary>
		public bool IsSelected
		{
			get { return _isSelected; }
			set
			{
				if (value == _isSelected)
					return;

				_isSelected = value;

				base.OnPropertyChanged(() => IsSelected);
			}
		}
		bool _isSelected;

		#endregion

		#region SaveCommand, Save()

		/// <summary>
		/// Returns a command that saves the customer.
		/// </summary>
		public ICommand SaveCommand
		{
			get
			{
				if (_saveCommand == null)
					_saveCommand = new DelegateCommand(Save, () => CanSave);
				return _saveCommand;
			}
		}
		DelegateCommand _saveCommand;

		/// <summary>
		/// Saves the customer to the repository.  This method is invoked by the SaveCommand.
		/// </summary>
		public void Save()
		{
			if (!_customer.IsValid)
				throw new InvalidOperationException(Strings.CustomerViewModel_Exception_CannotSave);

			if (this.IsNewCustomer)
				_customerRepository.AddCustomer(_customer);
			
			base.OnPropertyChanged("DisplayName");
		}

		#endregion

		#region private: IsNewCustomer, CanSave, PropertyErrors()

		/// <summary>
		/// Returns true if this customer was created by the user and it has not yet
		/// been saved to the customer repository.
		/// </summary>
		bool IsNewCustomer
		{
			get { return !_customerRepository.ContainsCustomer(_customer); }
		}

		/// <summary>
		/// Returns true if the customer is valid and can be saved.
		/// </summary>
		bool CanSave
		{
			get { return String.IsNullOrEmpty(this.ObjectErrors()) && _customer.IsValid; }
		}

		protected override string ObjectErrors()
		{
			var ce = ((IDataErrorInfo)_customer).Error;
			var my = base.ObjectErrors();
			if (ce == null && my == null)
				return null;
			if (ce == null)
				return my;
			if (my == null)
				return ce;
			return my + ", " + ce;
		}

		protected override string PropertyErrors(string propertyName)
		{
			// Dirty the commands registered with CommandManager,
			// such as our Save command, so that they are queried
			// to see if they can execute now.
			if (_saveCommand != null)
				_saveCommand.RaiseCanExecuteChanged();

			return base.PropertyErrors(propertyName);
		}

		#endregion // Private Helpers
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) http://www.ansibleww.com.au
Australia Australia
The Australia born French man who went back to Australia later in life...
Finally got over life long (and mostly hopeless usually, yay!) chronic sicknesses.
Worked in Sydney, Brisbane, Darwin, Billinudgel, Darwin and Melbourne.

Comments and Discussions