Home > WPF > >How to Reference Named Elements Within CellTemplate?

>How to Reference Named Elements Within CellTemplate?

>

Getting reference to the named elements within data template is a commonly requested feature of WPF. In the current version of WPF, there is no intuitive and straightforward way to do it, you need to either traverse the visual tree to compare the Name property of each FrameworkElements within the tree, or alternatively you can first off grab the reference to the ContentPresenter within the ControlTemplate, and call DataTemplate.FindName() passing in the ContentPresenter reference as the "templatedParent" argument. Accessing named elements within CellTemplate complicates the things a bit since each Cell will have different instantiation of CellTemplate, the following helper class gives a possible solution to this problem (I also posted it in this WPF MSDN forum thread):

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace Sheva.Windows.Component
{
    public static class ListViewHelper
  
{
        /// <summary>
        ///
Finds an element that has the provided identifier name within the specified cell template identified by the cellColumn and cellRow
      
/// </summary>
        /// <param name="listView">
the referenced ListView control</param>
        /// <param name="cellColumn">
the index of column from which the CellTemplate will be retrieved</param>
        /// <param name="cellRow">
the index of the row from which the specified ListViewItem will be retrieved</param>
        /// <param name="name">
The name of the requested element.</param>
        /// <returns>
The requested element. This can be null reference if no matching element was found.</returns>
      
public static FrameworkElement FindNameFromCellTemplate(ListView listView, Int32 cellColumn, Int32 cellRow, Stringname)
        {
            if(listView == null)
            {
                throw newArgumentNullException("listView");
            }

            if(!listView.IsLoaded)
            {
                throw new InvalidOperationException("ListView is not yet loaded");
            }

            if (cellRow >= listView.Items.Count || cellRow < 0)
            {
                throw new ArgumentOutOfRangeException("row");
            }

            GridView gridView = listView.View as GridView;
            if (gridView == null)
            {
                return null;
            }

            if (cellColumn >= gridView.Columns.Count || cellColumn < 0)
            {
                throw new ArgumentOutOfRangeException("column");
            }

            ListViewItem item = listView.ItemContainerGenerator.ContainerFromItem(listView.Items[cellRow]) as ListViewItem;
            if (item != null)
            {
                if (!item.IsLoaded)
                {
                    item.ApplyTemplate();
                }
                GridViewRowPresenter rowPresenter = GetFrameworkElementByName<GridViewRowPresenter>(item);

                if(rowPresenter != null)
                {
                    ContentPresenter templatedParent = VisualTreeHelper.GetChild(rowPresenter, cellColumn) as ContentPresenter;
                    DataTemplate dataTemplate = gridView.Columns[cellColumn].CellTemplate;
                    if(dataTemplate != null && templatedParent != null)
                    {
                        return dataTemplate.FindName(name, templatedParent) as FrameworkElement;
                    }
                }
            }

            return null;
        }

        private static T GetFrameworkElementByName<T>(FrameworkElement referenceElement) where T : FrameworkElement
      
{
            FrameworkElementchild = null;
            for(Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceElement); i++)
            {
                child = VisualTreeHelper.GetChild(referenceElement, i) as FrameworkElement;
                if(child != null && child.GetType() == typeof(T))
                {
                    break;
                }
                else if(child != null)
                {
                    child = GetFrameworkElementByName<T>(child);
                    if(child != null && child.GetType() == typeof(T))
                    {
                        break;
                    }
                }
            }
            returnchild asT;
        }
    }
}

This actually requires a bit of coding, hopefully future version of WPF in particular the ListView control could has a much better content model to make it more flexible and extensible than it is right now.

About these ads
Categories: WPF
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: