Click here to Skip to main content
10,500,000 members (72,504 online)
Click here to Skip to main content
Add your own
alternative version

Item-Level Presentation Models for WPF

, 2 Apr 2011 GPL3 54.6K 6 75
Make your life easier by inserting a Presentation Model layer (aka ViewModel) between your domain-model collection contents and template-generated WPF objects.
using System;
using System.Collections.Generic;

namespace HappyNomad.Outlining {

	/// <summary>Provides utility methods for manipulating tree structures.</summary>
	public static class OutliningUtil {
		#region Tree Manipulation Methods

		/// <summary>Inserts a new node into a tree structure</summary>
		/// <param name="newItem"></param>
		/// <param name="relativePos"></param>
		public static void Insert<T>( T newItem, RelativePosition<T> relativePos ) {
			IList<T> subItems =
			  (IList<T>)ReflectionUtil.NavigateToManySide<T>( relativePos.parent, relativePos.subItemsPropName );
			int newIndex = -1;

			if ( relativePos.command == OutliningCommands.NewSiblingBefore )
				newIndex = MinimumIndex<T>( subItems, relativePos.insertRelativeTo );
			else if ( relativePos.command == OutliningCommands.NewSiblingAfter )
				newIndex = MaximumIndex<T>( subItems, relativePos.insertRelativeTo ) + 1;
				//((Topic)parent).SubTopics.Insert( newIndex, (Topic)newItem );
			else if ( relativePos.command == OutliningCommands.NewChild ) {
				if ( relativePos.childIndex >= 0 ) newIndex = relativePos.childIndex;
				else newIndex = subItems.Count; //Insert the new item at the end of the sub-items list
			} else if ( relativePos.command == OutliningCommands.NewParent ) {
				if ( relativePos.childIndex >= 0 ) newIndex = relativePos.childIndex;
				else //Insert the new item at the same position where the first selected item was located:
					newIndex = MinimumIndex( subItems, relativePos.insertRelativeTo );
				IList<T> newSubItems =
				  (IList<T>)ReflectionUtil.NavigateToManySide<T>( newItem, relativePos.subItemsPropName );
				foreach ( T item in relativePos.insertRelativeTo ) { //loop thru selected items:
					if ( !subItems.Contains(item) )
						throw new Exception( "Parent's subitems must contain new item's children" );
					subItems.Remove( item ); //remove item from parent's sub-topics list
					newSubItems.Add( item ); //add it as child of the new item
				}
			}
			subItems.Insert( newIndex, newItem );
		}

		private static int MinimumIndex<T>( IList<T> parentList, IList<T> subItems ) {
			int result = parentList.Count;
			foreach ( T item in subItems ) {
				int index = parentList.IndexOf( item );
				if ( index < result ) result = index;
			}
			return result;
		}

		private static int MaximumIndex<T>( IList<T> parentList, IList<T> subItems ) {
			int result = 0;
			foreach ( T item in subItems ) {
				int index = parentList.IndexOf( item );
				if ( index > result ) result = index;
			}
			return result;
		}

		#endregion

		#region 'GenerateUniqueName' Method

		public static string GenerateUniqueName<T>(string newItemType , string nameProperty, ICollection<T> parentCollection) {
			string result = null;
			bool isNameUnique = false;

			for ( int i = 0; !isNameUnique; i++ ) { //find a unique name to use
				result = (i == 0) ? "New "+newItemType : "New "+newItemType+" (" + i + ")";
				isNameUnique = true;
				foreach ( T existingItem in parentCollection )
					if ( result.Equals(ReflectionUtil.NavigateToOneSide(existingItem, nameProperty)) )
						isNameUnique = false;
			}
			return result;
		}

		#endregion
	}
}

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 GNU General Public License (GPLv3)

Share

About the Author

Adrian Alexander
United States United States
Adrian loves facilitating suave user experiences via the latest and greatest GUI technologies such as Windows 8 Metro-style apps as well as WPF. More generally, he finds joy in architecting software that is easy to comprehend and maintain. He does so by applying design patterns at the top-level, and by incessantly refactoring code at lower levels. He's always interested in hearing about opportunities for full or part-time development work. He resides in Pennsylvania but can potentially travel anywhere in the country. (Writing about himself in the third-person is Adrian's new hobby.)

You may also be interested in...

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150603.1 | Last Updated 2 Apr 2011
Article Copyright 2008 by Adrian Alexander
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid