Usually, the WPF controls are declared in the .xaml file and not in the code behind (.xaml.cs file). However, we might need to use some of those controls in the code behind in order to manipulate them. How can we get the handle of such a control if it “resides” in the xaml file? Take a look at the following xaml code:

<Window x:Class="WpfApplication2.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" MouseLeftButtonDown="window_Clicked">
    <Grid>
        <TextBlock x:Name="fullNameControl" FontSize="20" 
                   Text="{Binding Path=FullName}">
        </TextBlock>
    </Grid>
</Window>

There is a TextBlock called fullNameControl, in the code behind I change its background color to gold when the window is clicked:

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        this.DataContext = new DemoData();
    }

    void window_Clicked(object sender, MouseButtonEventArgs e)
    {
        this.fullNameControl.Background = Brushes.Gold;
    }
}

This is very straightforward, fullNameControl becomes a property of the window class so it is very simple to manipulate it. But what if we decided to create a DataTemplate which contain the TextBlock control, like this:

<Window x:Class="WpfApplication2.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:data="clr-namespace:WpfApplication2"
    Title="Window1" Height="300" Width="300" MouseLeftButtonDown="window_Clicked">
    <Window.Resources>
        <DataTemplate x:Name="myTemplate" DataType="{x:Type data:DemoData}">
            <TextBlock x:Name="fullNameControl" FontSize="20" 
                   Loaded="fullNameControl_Loaded"
                   Text="{Binding Path=FullName}">
        </TextBlock>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Label Content="{Binding}"></Label>
    </Grid>
</Window>


Now, when trying to compile the code, I get the following error: error CS1061: ‘WpfApplication2.Window1′ does not contain a definition for ‘fullNameControl’ and no extension method ‘fullNameControl’ accepting a first argument of type ‘WpfApplication2.Window1′ could be found (are you missing a using directive or an assembly reference?)”. OK, the window class doesn’t have fullNameControl property anymore because it is declared in the DataTemplate so there must be another way to do it.

Template.Find() doesn’t work with DataTemplates: Someone suggested that I can use the Template.Find() method, but it turns out that it doesn’t work for DataTemplates, Template.Find() is only good for ControlTemplates (read more about creation of new Control Templates in How to use Microsoft Expression Blend to modify a control).

So, I googled a little bit and didn’t find much about that issue, there were 2 entries where this issue is brought up:

  1. http://forums.msdn.microsoft.com/en-US/wpf/thread/e06a1d2b-f458-4e9b-8c71-04df332d5299/ – If you read this thread till the end, you will find out that the solution suggested requires our DataTemplate to have a x:key which means that we can’t define it for a data type (as defined in the example above). That is an unacceptable solution…
  2. http://webpurityltd.wordpress.com/2008/04/15/wpf-making-good-progress/ – the suggested solution is very specific and not general and it doesn’t work for me!

Finally, I came up with my own idea: subscribe to the ‘fullNameControl’ Load event (in the xaml) and save the sender as a TextBlock so from now on, we have our control handle as a class member called m_textBlock…

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        this.DataContext = new DemoData();
    }

    void fullNameControl_Loaded(object sender, RoutedEventArgs e)
    {
        m_textBlock = sender as TextBlock;
    }

    void window_Clicked(object sender, MouseButtonEventArgs e)
    {
        m_textBlock.Background = Brushes.Gold;
    }

    private TextBlock m_textBlock;
}

When the window Click event is raised, the background color of the text block is changed to gold. This is how I can use controls which are defined inside a DataTemplate in the code behind… What do you think about my solution? Do you know any better idea? I will be glad to hear your opinions.

Tags :

26 Responses to “How To Access A WPF Control Which Is Located In A DataTemplate”


  1. Russell Mull

    Said on August 8, 2008 :

    A clever workaround. But if you have to use it, you’re probably doing things wrong. In my ~1 year of doing WPF, I haven’t seen anything I couldn’t solve via either more clever databinding, or by making a custom control and binding to it. The second strategy, in particular, can save large amounts of code and pain if used judiciously.

    Really, if you’re using the XAML side correctly, you ought to be able to do anything you want without having to reach into the UI from the code-behind.

  2. Shahar Y

    Said on August 8, 2008 :

    @ Russell Mull
    I totally agree with you, if you use MVC pattern, there shall be no need to reach into the UI from the code-behind !
    But sometimes your bos can decide to give the ownership of a big control which was not designed by you, and you have no time for refactoring…

  3. Jon von Gillern

    Said on August 8, 2008 :

    So why not just add a trigger via a style to your template? The template doesn’t need to change (except where you want it) and you don’t have to touch code behind.

  4. Shahar Y

    Said on August 8, 2008 :

    @ Jon von Gillern
    Sometimes you need that a control in your DataTemplate will react to something that is in another Template…
    But, in general, I agree that you should do your best to avoid touching the code behind.
    If you have no other choice, you can use my “technique”

  5. Brian

    Said on October 8, 2008 :

    You have hit the nail on the head. I had a control buried inside a datatemplate that used multiple datatemplates, Viewports, storyboards and ContentPresenter. Multiple instances of this control are created in a parent using databinding but I needed to adjust the height and width of this control based on external data. Using your technique turned what seemed a daunting challenge of retrieving datatemplates and such into an elegant three line of code solution.

  6. Victor Ponomaryov

    Said on December 5, 2008 :

    Cool idea!

  7. Martin Cook

    Said on December 19, 2008 :

    I don’t understand how this can possibly work where you have a datatemplate reused many times for example as the itemtemplate of a listboxitem?

    I have a datatemplate which is 3D which has a viewport element. When the user clicks on a listbox item it spins the item on the x axis. I want the previously selected item to automatically spin back – but of course the viewport for this and other items are wrapped in each datatemplate.

    Cheers,
    Martin

  8. ross

    Said on December 30, 2008 :

    This technique may be useful for the PasswordBox sitting on a DataTemplate.

    It is very annoying because for security reasons you can’t bind to the PasswordBox.Password (its not a dependency property). Therefore the only way to get the value is by accessing the control from code, but of course you can’t easily get at the values of a datatemplate.

  9. Sergey Galich

    Said on February 23, 2009 :

    Use VisualTreeHelper.GetParent((UIElement)(TemplatedParent ?? Parent))

  10. Amit

    Said on March 13, 2009 :

    Guys , I have an issue with multiple resolution , Some areas get distorted on change of resoultion ,So I think to change the width , height and margin etc of inner controls dynamically , still there are few controls which lie in datatemplate and I need to access them .I just wonder how to resolve this issue !
    It works with trick of setting the parameters on load event.
    Can any one suggest with a better solution for the issue [Multiple Resolution] ?
    Thanks,
    Amit

  11. Hamish

    Said on March 18, 2009 :

    This is a fantastic solution for a problem I have been having with a data template inside rowdetails of the WPF toolkit datagrid. I wanted to add a button to show or hide data on the template and I was unable to reference any of the controls… well done!

  12. Amit

    Said on March 18, 2009 :

    @Amit & Hamish

    I think you should also read the following post:

    http://www.dev102.com/2009/03/02/tidy-up-your-xaml-and-code-behind-use-usercontrols-inside-templates/

    It might also help you.

  13. Hamish

    Said on March 20, 2009 :

    Thanks Amit, I did actually run into trouble with this solution as when there were multiple instances of the data plate the variable matching got very confused. I will try your suggestion.

  14. Derek

    Said on June 6, 2009 :

    Wow, thanks sooo very much for these posts guys. I swear, as I try to migrate some of the complicated pieces of our enterprise applications using WPF’s awesome capabilities to remove the need to code behind access, I ran into the same need for at least some references using the ContentPresenter and many datatemplates. This really helped along with providing the necessary other options to make me feel informed in my decisions for my project.

  15. Sudarsan Srinivasan

    Said on August 14, 2009 :

  16. Daniel

    Said on March 5, 2010 :

    This is kind o a kids “hack”. I mean what do you do if you have a library of custom controls? On OnApplyTemplate() this approach will fail.
    I agree more the binding approach, as this is walking instead of driving..
    Daniel

  17. neeraj

    Said on March 5, 2010 :

    Thanks Amit..that’s what i was searching for..you saved my time.
    Thanks again!
    God bless!

  18. Jeen

    Said on May 3, 2010 :

    Hi,
    But it always load the last record in TextBlock object. Can u explain how to load the selected record’s textBlock data in listbox.

  19. Bharathi

    Said on August 10, 2010 :

    hi, great idea, it was very useful for me. thanks.

  20. Richard

    Said on October 19, 2010 :

  21. moviepagal

    Said on November 18, 2010 :

    I was struggling with this problem for around 2 days. Your solution worked.

    You are a genius.

  22. Deckymcd

    Said on February 8, 2011 :

    You are a god. I’ll be thinking more like you from now on. Cheers.

  23. SLAndy

    Said on May 6, 2011 :

    I would also like to reiterate that you are a genius. Thanks for posting this!

  24. The Dude

    Said on June 13, 2012 :

    When working solely in the view there is absolutely nothing wrong with working in the code behind.

2 Trackback(s)

  1. Nov 5, 2008: Recent Links Tagged With "xaml" - JabberTags
  2. Apr 2, 2009: Don’t Use a WPF Control in Windows.Resource | Dev102.com

Post a Comment