Click here to Skip to main content
15,881,882 members
Articles / Desktop Programming / WPF

Developing an Autofilter ListView

Rate me:
Please Sign up or sign in to vote.
4.97/5 (26 votes)
8 Jul 2008CPOL7 min read 161K   5.4K   100  
This article describes the development of an Excel-like Autofilter ListView.
// _________________________________________________________________________________________
//  Name:       BaseWPHHelpers
//  Purpose:    Common helpers for tree walking etc
//  Author:     Andrew Whiddett
//  (c) Copyright 2006 REZN8 Productions Inc
// _________________________________________________________________________________________

#region Using
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Configuration;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using System.IO;
using System.Windows.Media.Imaging;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
#endregion


namespace BaseWPFHelpers
{
    public class Helpers
    {
        /// <summary>
        /// Helper method to create a snapshot of a visual item as a bitmap image. Typically used for things like drag and drop
        /// or any time we want to do something where we don't want the hit of a video running in an animating object
        /// </summary>
        /// <param name="element">Element to take a snapshot of</param>
        /// <returns>Bitmap image of the element</returns>
        public static RenderTargetBitmap CreateImageBrushFromVisual(FrameworkElement element)
        {

            RenderTargetBitmap bitmapImage =
                new RenderTargetBitmap((int)element.ActualWidth,
                            (int)element.ActualHeight,
                            96, 96,
                            PixelFormats.Pbgra32);
            bitmapImage.Render(element);

            return bitmapImage;
        }

        /// <summary>
        /// Base Interface that describes the visual match pattern
        /// Part of the Visual tree walkers
        /// </summary>
        public interface IFinderMatchVisualHelper
        {
            /// <summary>
            /// Does this item match the input visual item
            /// </summary>
            /// <param name="item">Item to check </param>
            /// <returns>True if matched, else false</returns>
            bool DoesMatch(DependencyObject item);

            /// <summary>
            /// Property that defines if we should stop walking the tree after the first match is found
            /// </summary>
            bool StopAfterFirst
            {
                get;
                set;
            }
        }

        /// <summary>
        /// Visual tree walker class that matches based on Type
        /// </summary>
        public class FinderMatchType : IFinderMatchVisualHelper
        {
            private Type _ty = null;
            private bool _stopafterfirst = false;

            public FinderMatchType(Type ty)
            {
                _ty = ty;
            }

            public FinderMatchType(Type ty, bool StopAfterFirst)
            {
                _ty = ty;
                _stopafterfirst = StopAfterFirst;
            }

            public bool DoesMatch(DependencyObject item)
            {
                return _ty.IsInstanceOfType(item);
            }

            public bool StopAfterFirst
            {
                get
                {
                    return _stopafterfirst;
                }
                set
                {
                    _stopafterfirst = value;
                }
            }
        }

        /// <summary>
        /// Visual tree walker function that matches on name of an element
        /// </summary>
        public class FinderMatchName : IFinderMatchVisualHelper
        {
            private String _name = "";

            public FinderMatchName(String name)
            {
                _name = name;
            }

            public bool DoesMatch(DependencyObject item)
            {
                bool bMatch = false;

                if (item is FrameworkElement)
                {
                    if ((item as FrameworkElement).Name == _name) bMatch = true;
                }

                return bMatch;
            }

            /// <summary>
            /// StopAfterFirst Property.. always true, you can't have more than one of the same name..
            /// </summary>
            public bool StopAfterFirst
            {
                get
                {
                    return true;
                }
                set
                {
                }
            }
        }

        /// <summary>
        /// Visual tree helper that matches if the item is focused
        /// </summary>
        public class FinderMatchFocused : IFinderMatchVisualHelper
        {
            public bool DoesMatch(DependencyObject item)
            {
                bool bMatch = false;

                if (item is FrameworkElement)
                {
                    if ((item as FrameworkElement).IsFocused) bMatch = true;
                }

                return bMatch;
            }

            /// <summary>
            /// StopAfterFirst Property.. always true, you can't have more than one item in focus..
            /// </summary>
            public bool StopAfterFirst
            {
                get
                {
                    return true;
                }
                set
                {
                }
            }
           
        }

        /// <summary>
        /// Visual tree helper that matches is the item is an itemshost. Typically used in ItemControls
        /// </summary>
        public class FinderMatchItemHost : IFinderMatchVisualHelper
        {
            public bool DoesMatch(DependencyObject item)
            {
                bool bMatch = false;

                if (item is Panel)
                {
                    if ((item as Panel).IsItemsHost) bMatch = true;
                }

                return bMatch;
            }

            /// <summary>
            /// StopAfterFirst Property.. always true, you can't have more than one item host in an item control..
            /// </summary>
            public bool StopAfterFirst
            {
                get
                {
                    return true;
                }
                set
                {
                }
            }

        }

        /// <summary>
        /// Typically used method that walks down the visual tree from a given point to locate a given match only
        /// once. Typically used with Name/ItemHost etc type matching.
        /// 
        /// Only returns one element
        /// </summary>
        /// <param name="parent">Start point in the tree to search</param>
        /// <param name="helper">Match Helper to use</param>
        /// <returns>Null if no match, else returns the first element that matches</returns>
        public static FrameworkElement SingleFindDownInTree(Visual parent, IFinderMatchVisualHelper helper)
        {
            helper.StopAfterFirst = true;

            List<FrameworkElement> lst = FindDownInTree(parent, helper);

            FrameworkElement feRet = null;

            if (lst.Count > 0) feRet = lst[0];

            return feRet;
        }

        /// <summary>
        /// All way visual tree helper that searches UP and DOWN in a tree for the matching pattern.
        /// 
        /// This is used to walk for name matches or type matches typically.
        /// 
        /// Returns only the first matching element
        /// </summary>
        /// <param name="parent">Start point in the tree to search</param>
        /// <param name="helper">Match Helper to use</param>
        /// <returns>Null if no match, else returns the first element that matches</returns>
        public static FrameworkElement SingleFindInTree(Visual parent, IFinderMatchVisualHelper helper)
        {
            helper.StopAfterFirst = true;

            List<FrameworkElement> lst = FindInTree(parent, helper);

            FrameworkElement feRet = null;

            if (lst.Count > 0) feRet = lst[0];

            return feRet;
        }

        /// <summary>
        /// Walker that looks down in the visual tree for any matching elements, typically used with Type
        /// </summary>
        /// <param name="parent">Start point in the tree to search</param>
        /// <param name="helper">Match Helper to use</param>
        /// <returns>List of matching FrameworkElements</returns>
        public static List<FrameworkElement> FindDownInTree(Visual parent, IFinderMatchVisualHelper helper)
        {
            List<FrameworkElement> lst = new List<FrameworkElement>();

            FindDownInTree(lst, parent, null, helper);

            return lst;
        }

        /// <summary>
        /// Walker that looks both UP and down in the visual tree for any matching elements, typically used with Type
        /// </summary>
        /// <param name="parent">Start point in the tree to search</param>
        /// <param name="helper">Match Helper to use</param>
        /// <returns>List of matching FrameworkElements</returns>
        public static List<FrameworkElement> FindInTree(Visual parent, IFinderMatchVisualHelper helper)
        {
            List<FrameworkElement> lst = new List<FrameworkElement>();

            FindUpInTree(lst, parent, null, helper);

            return lst;
        }

        /// <summary>
        /// Really a helper for FindDownInTree, typically not called directly.
        /// </summary>
        /// <param name="lst"></param>
        /// <param name="parent"></param>
        /// <param name="ignore"></param>
        /// <param name="helper"></param>
        public static void FindDownInTree(List<FrameworkElement> lst, DependencyObject parent, DependencyObject ignore, IFinderMatchVisualHelper helper)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
            {
                if (lst.Count > 0 && helper.StopAfterFirst) break;

                DependencyObject visual = VisualTreeHelper.GetChild(parent, i);

                if (visual is FrameworkElement)
                {
                    (visual as FrameworkElement).ApplyTemplate();
                }

                if (helper.DoesMatch(visual))
                {
                    lst.Add(visual as FrameworkElement);
                }

                if (lst.Count > 0 && helper.StopAfterFirst) break;

                if (visual != ignore)
                {
                    FindDownInTree(lst, visual, ignore, helper);
                }
            }
        }

        /// <summary>
        /// Really a helper to look Up in a tree, typically not called directly.
        /// </summary>
        /// <param name="lst"></param>
        /// <param name="parent"></param>
        /// <param name="ignore"></param>
        /// <param name="helper"></param>
        public static void FindUpInTree(List<FrameworkElement> lst, Visual parent, Visual ignore, IFinderMatchVisualHelper helper)
        {
            // First thing to do is find Down in the existing node...
            //FindDownInTree(lst, parent, ignore, helper);

            if (helper.DoesMatch(parent))
            {
                lst.Add(parent as FrameworkElement);
            }


            // Ok, now check to see we are not at a stop.. i.e. got it.
            if (lst.Count > 0 && helper.StopAfterFirst)
            {
                // Hum, don't think we need to do anything here: yet.
            }
            else
            {
                // Ok, now try to get a new parent...
                FrameworkElement feCast = parent as FrameworkElement;
                if (feCast != null)
                {
                    FrameworkElement feNewParent = feCast.Parent as FrameworkElement;
                    if (feNewParent == null || feNewParent == feCast)
                    {
                        // Try to get the templated parent
                        feNewParent = feCast.TemplatedParent as FrameworkElement;
                    }

                    // Now check to see that we have a valid parent
                    if (feNewParent != null && feNewParent != feCast)
                    {
                        // Pass up
                        FindUpInTree(lst, feNewParent, feCast, helper);
                    }
                }
            }
        }

        /// <summary>
        /// Simple form call that returns all elements of a given type down in the visual tree
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="ty"></param>
        /// <returns></returns>
        public static List<FrameworkElement> FindElementsOfType(Visual parent, Type ty)
        {
            return FindDownInTree(parent, new FinderMatchType(ty));

        }

        /// <summary>
        /// Simple form call that returns the first element of a given type down in the visual tree
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="ty"></param>
        /// <returns></returns>
        public static FrameworkElement FindElementOfType(Visual parent, Type ty)
        {
            return SingleFindDownInTree(parent, new FinderMatchType(ty));
        }

        /// <summary>
        /// Simple form call that returns the first element of a given type up in the visual tree
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="ty"></param>
        /// <returns></returns>
        public static FrameworkElement FindElementOfTypeUp(Visual parent, Type ty)
        {
            return SingleFindInTree(parent, new FinderMatchType(ty));
        }
        
        /// <summary>
        /// Helper to pause any media elements down in the visual tree
        /// </summary>
        /// <param name="parent"></param>
        public static void TurnOffMediaElements(Visual parent)
        {
            List<FrameworkElement> lst = FindElementsOfType(parent,typeof(MediaElement));

            foreach (FrameworkElement me in lst)
            {
                MediaElement meCast = me as MediaElement;

                if (meCast != null)
                {
                    if (meCast.CanPause)
                    {
                        try
                        {
                            meCast.Pause();
                        }
                        catch (Exception e)
                        {
                        }
                    }
                }
            }

        }

        /// <summary>
        /// Helper to resume playing any media elements down in the visual tree
        /// </summary>
        /// <param name="parent"></param>
        public static void TurnOnMediaElements(Visual parent)
        {
            List<FrameworkElement> lst = FindElementsOfType(parent, typeof(MediaElement));

            foreach (FrameworkElement me in lst)
            {
                MediaElement meCast = me as MediaElement;

                if (meCast != null)
                {
                    try
                    {
                        meCast.Play();
                    }
                    catch (Exception e)
                    {
                    }
                }
            }
        }


        /// <summary>
        /// Helper to find the currently focused element
        /// </summary>
        /// <param name="parent"></param>
        /// <returns></returns>
        public static FrameworkElement FindFocusedElement(Visual parent)
        {
            return SingleFindInTree(parent, new FinderMatchFocused());
        }

        /// <summary>
        /// Helper to find a items host (e.g. in a listbox etc) down in the tree
        /// </summary>
        /// <param name="parent"></param>
        /// <returns></returns>
        public static FrameworkElement FindItemsHost(Visual parent)
        {
            return SingleFindDownInTree(parent, new FinderMatchItemHost());
        }

        /// <summary>
        /// Helper to find the given named element down in the visual tree
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="ElementName"></param>
        /// <returns></returns>
        public static FrameworkElement FindVisualElement(Visual parent, String ElementName)
        {
            return SingleFindDownInTree(parent, new FinderMatchName(ElementName));
        }

        /// <summary>
        /// Helper to find the given named element up in the visual tree
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="ElementName"></param>
        /// <returns></returns>
        public static FrameworkElement FindVisualElementUp(Visual parent, String ElementName)
        {
            return SingleFindInTree(parent, new FinderMatchName(ElementName));
        }

    }

}

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
Architect Scott Logic
United Kingdom United Kingdom
I am CTO at ShinobiControls, a team of iOS developers who are carefully crafting iOS charts, grids and controls for making your applications awesome.

I am a Technical Architect for Visiblox which have developed the world's fastest WPF / Silverlight and WP7 charts.

I am also a Technical Evangelist at Scott Logic, a provider of bespoke financial software and consultancy for the retail and investment banking, stockbroking, asset management and hedge fund communities.

Visit my blog - Colin Eberhardt's Adventures in .NET.

Follow me on Twitter - @ColinEberhardt

-

Comments and Discussions