Click here to Skip to main content
15,885,914 members
Articles / Desktop Programming / WPF

Item-Level Presentation Models for WPF

Rate me:
Please Sign up or sign in to vote.
4.65/5 (18 votes)
2 Apr 2011GPL39 min read 79.8K   6   74  
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.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;
using System.Xml;

namespace HappyNomad {
	public static class WPFUtil {

		#region 'FindAncestor' Methods

		/// <summary>
		/// Finds the nearest ancestor of the given item, that has the given type.
		/// </summary>
		/// <typeparam name="T">The type of the desired result</typeparam>
		/// <param name="startNode">A descendant of the desired result,
		/// from where to begin the search</param>
		/// <returns>The first ancestor of type T encountered, or null if no match found</returns>
		public static T FindAncestor<T>( DependencyObject startNode ) where T : DependencyObject {
			if ( startNode == null ) return null; //we�ve reached the root of the tree
			T startNodeAsT = startNode as T;

			if ( startNodeAsT != null )
				return startNodeAsT; //return current level if of target type
			else
				return FindAncestor<T>( GetParent(startNode) ); //recurse to the next level
		}

		/// <summary>
		/// GetParent method that traverses through the visual tree, as well as content elements.
		/// [Source: http://code.logos.com/blog/2008/02/finding_ancestor_elements_in_w.html ]
		/// </summary>
		public static DependencyObject GetParent( DependencyObject obj ) {
			if ( obj == null )
				return null;

			ContentElement ce = obj as ContentElement;
			if ( ce != null ) {
				DependencyObject parent = ContentOperations.GetParent( ce );
				if ( parent != null )
					return parent;

				FrameworkContentElement fce = ce as FrameworkContentElement;
				return fce != null ? fce.Parent : null;
			}

			return VisualTreeHelper.GetParent( obj );
		}

		#endregion

		#region 'FindDescendant' Methods

		/// <summary>
		/// Finds the nearest visual descendant of the given item, that satisfies the given condition.
		/// [Source: http://blogs.msdn.com/wpfsdk/archive/2007/04/16/how-do-i-programmatically-interact-with-template-generated-elements-part-ii.aspx ]
		/// </summary>
		/// <param name="ancestor">An ancestor of the desired result, from where to begin the search</param>
		/// <param name="testNode">The condition which the result must satisfy</param>
		/// <returns>The first descendant that satisfies the given condition.
		/// If no matching item can be found, a null reference is returned.</returns>
		public static object FindDescendant( DependencyObject ancestor, Predicate<DependencyObject> testNode ) {
			for ( int i = 0; i < VisualTreeHelper.GetChildrenCount( ancestor ); i++ ) {
				DependencyObject child = VisualTreeHelper.GetChild( ancestor, i );
				if ( child != null && testNode(child) ) //child is T )
					return child;
				else {
					object childOfChild = FindDescendant( child, testNode );
					if ( childOfChild != null )
						return childOfChild;
				}
			}
			return null;
		}

		public static OfType FindDescendant<OfType>( DependencyObject ancestor )
		  where OfType : DependencyObject {
			Predicate<DependencyObject> testNode = delegate( DependencyObject nodeToTest ) {
				return nodeToTest is OfType;
			};
			return (OfType)FindDescendant( ancestor, testNode );
		}

		public static OfType FindDescendant<OfType>( DependencyObject ancestor, string withName )
		  where OfType : FrameworkElement {
			Predicate<DependencyObject> testNode = delegate( DependencyObject nodeToTest ) {
				OfType n = nodeToTest as OfType;
				return n == null ? false : n.Name == withName;
			};
			return (OfType)FindDescendant( ancestor, testNode );
		}

		#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)


Written By
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.)

Comments and Discussions