How to find control in ContentTemplate

5 posts, 0 answers
  1. A
    A avatar
    6 posts
    Member since:
    Apr 2012

    Posted 06 Mar 2014 Link to this post

    I have RadTabControl with RadGridView in the ContentTemplate. I need bind this RadGridView as a command parameter to the button, that is outside the RadTabControl. Is there a way to do that? Looks like such feature is missing in your controls
  2. Martin
    Admin
    Martin avatar
    1099 posts

    Posted 10 Mar 2014 Link to this post

    Hi,

    When you define a visual element within a DataTemplate, this element is generated and loaded when the DataTemplate gets applied. Additionally as the element is not directly part of the visual tree (as it gets applied as part of a DataTemplate), it is not a straight-forward task to access it. Basically what you can do is implement a code-behind logic that traverses the visual tree to find the RadGridView after the ContentTemplate in which it is defined is applied. 

    For that purpose you first need to consider the fact that RadTabControl loads the Content of its tabs on demand. This means that if the first item is selected its Content will be loaded. Then when you select another item the Content of the first one will be removed from the visual tree and the Content of the currently selected item will be generated. 

    This is why in order to get the RadGridView you can either:
    • handle the RadGridView Loaded event. If you define a GridView in every tab then this would mean that the Loaded event will be invoked when the tab selection changes (when a new RadGridView instance is created). Then you can set the sender as a CommandParameter of a Button. You can see this implementation in the attached project. Also here is an example in code:
    private void gridView_Loaded(object sender, RoutedEventArgs e)
    {
        var gridView = sender as RadGridView;
        if (VisualTreeHelper.GetParent(gridView) != null)
        {
            this.btn.CommandParameter = gridView;
        }
    }

    <Window.Resources>
        <sys:String x:Key="charCollection">abcdef</sys:String>
         
        <DataTemplate x:Key="tabControlContentTemplate">
            <telerik:RadGridView x:Name="gridView" ItemsSource="{StaticResource charCollection}" Loaded="gridView_Loaded" />
        </DataTemplate>
    </Window.Resources>
     
    <Grid>
        <telerik:RadTabControl  Name="tabControl"
      ContentTemplate="{StaticResource tabControlContentTemplate}"
      ItemsSource="{StaticResource charCollection}" />
        <Button Name="btn"
                Content="Execute Command"
                Loaded="Button_Loaded"
                VerticalAlignment="Bottom" />
    </Grid>
    • handle the RadTabControl SelectionChanged event to get the RadGridView with the ChildrenOfType<T>() method:
    var gridViews = this.tabControl.ChildrenOfType<RadGridView>();

    Both options traverse the visual tree which sometimes can be a heavy task. This is why if you can share more information about your requirements and why you need to pass the RadGridView as a CommandParameter we might be able to suggest a different approach.

    For instance, if you need to use a GridViewCommand, you can place the Button on a RadToolBar. The ToolBar is a focus scope and therefore it doesn't steal the focus away from the other elements on the screen. This allows its buttons to detect other focused elements and use them as targets of their commands.
    <Window.Resources>
        <DataTemplate x:Key="tabControlContentTemplate">
            <telerik:RadGridView x:Name="gridView" ItemsSource="{Binding Products}"/>
        </DataTemplate>
        <DataTemplate x:Key="HeaderTemplate">
            <TextBlock Text="{Binding Header}"/>
        </DataTemplate>
    </Window.Resources>
     
        ............................
     
    <telerik:RadToolBar VerticalAlignment="Top">
        <Button 
            Content="Delete" Command="telerik:RadGridViewCommands.Delete"/>
    </telerik:RadToolBar>
    <telerik:RadTabControl IsContentPreserved="True" Name="tabControl" Grid.Row="1"
                           ContentTemplate="{StaticResource tabControlContentTemplate}"
                           ItemsSource="{Binding Items}" ItemTemplate="{StaticResource HeaderTemplate}"
                           SelectionChanged="tabControl_SelectionChanged" Loaded="tabControl_Loaded"/>

    Regards,
    Martin
    Telerik
     

    DevCraft Q1'14 is here! Watch the online conference to see how this release solves your top-5 .NET challenges. Watch on demand now.

     
  3. UI for WPF is Visual Studio 2017 Ready
  4. Petr
    Petr avatar
    1 posts
    Member since:
    May 2014

    Posted 22 May 2014 in reply to Martin Link to this post

    Hello, I have SalusRadTabConrol inherited from RadTabControl. Used like this with defined ContentTemplate.

    <controls:SalusRadTabControl BorderThickness="0" Grid.Column="0" HeaderBackground="{StaticResource VitalSignsMainColor}" Foreground="White"
                                             ItemsSource="{Binding MeasurementCategories}"
                                             SelectedItem="{Binding SelectedMeasurementCategory, Mode=TwoWay}"
                                             IsSynchronizedWithCurrentItem="True">                
     
                    <telerik:RadTabControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=Name, Converter={StaticResource TextToUpperCaseConverter}}" />
                        </DataTemplate>
                    </telerik:RadTabControl.ItemTemplate>
     
                    <telerik:RadTabControl.ContentTemplate>
                        <DataTemplate>
                            <Grid Background="Transparent" Margin="10" x:Name="contentGrid">
                                <views:ContentView/>
                            </Grid>
                        </DataTemplate>
                    </telerik:RadTabControl.ContentTemplate>
     
                </controls:SalusRadTabControl>

    Content view (used in content template) contains as one of his child element RadGridView.

    But when try to find RadGridView by ChildrenOfType method in OnSelectionChanged event callback on SalusRadTabControl, desired element is not found.

    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
     {
                base.OnSelectionChanged(e);
     
                var grid = this.FindChildByType<RadGridView>();
     }


    Could you please give me advice where is problem? Thanks
  5. Martin
    Admin
    Martin avatar
    1099 posts

    Posted 27 May 2014 Link to this post

    Hi Petr,

    Note that the content of the tab control may be loaded after the selection is executed. This is why in your case the FindChildByType<T> method cannot find the GridView. In order to get it you can set your code in Dispatcher. This will ensure that the content of the selected item is loaded before the execution of the search code.
    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        base.OnSelectionChanged(e);
     
        Dispatcher.BeginInvoke(new Action(() => {
            var grid = this.FindChildByType<RadGridView>();
        }));
         
    }

    Regards,
    Martin
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
  6. skrec
    skrec avatar
    10 posts
    Member since:
    Mar 2011

    Posted 31 Jul 2014 in reply to Martin Link to this post

    Late but ... thanks a lot for answer. Petr
Back to Top
UI for WPF is Visual Studio 2017 Ready