Jeff Dege Jeff Dege - 1 year ago 102
C# Question

Error: "This operation is valid only on elements that have this template applied"

I have a C# WPF application that contains a user control:

<UserControl
x:Name="payrollEntryControl"
x:Class="MyNamespace.PayrollEntryControl"
[...]
>
[...]
</UserControl>


Within the user control, I have a Telerik
RadDataForm
:

<telerik:RadDataForm
x:Name="payrollAddForm"
CurrentItem="[...]"
EditTemplate="{StaticResource myEditTemplate}"
/>


The template contains a Telerik
RadGridView
and a
Button
:

<telerik:RadGridView Grid.Row="0" Grid.Column="0"
x:Name="workGridView"
[...]
ItemsSource="{Binding [...]}"
>
<telerik:RadGridView.Columns>
[...]
</telerik:RadGridView.Columns>
</telerik:RadGridView>
<Button Grid.Row="1" Grid.Column="0"
Command="{Binding addWorkCommand, ElementName=payrollEntryControl}"
>
Add
</Button>


I want the command to do is call
BeginInsert()
on
workGridView
. But I can't seem to get access to
workGridView
.

My command, so far:

private DelegateCommand addWorkCommand_ = null;
public DelegateCommand addWorkCommand
{
get
{
if (this.addWorkCommand_ == null)
{
this.addWorkCommand_ = new DelegateCommand(
o => addWork(o)
);
}

return this.addWorkCommand_;
}
}

private void addWork(object o)
{
var addForm = this.payrollAddForm;
var editTemplate = addForm.EditTemplate;
var workGrid = editTemplate.FindName("workGridView", addForm);
}


My problem? When I make the call to
editTemplate.FindName()
, I get an exception:


This operation is valid only on elements that have this template applied.


I don't understand. I'm getting the template from the form. How can it not be applied?

Answer Source

Peter Duniho's comment pointed me to this answer, which addressed my problem.

This method will help you:

public T FindElementByName<T>(FrameworkElement element, string sChildName) where T : FrameworkElement
{
    T childElement = null;
    var nChildCount = VisualTreeHelper.GetChildrenCount(element);
    for (int i = 0; i < nChildCount; i++)
    {
        FrameworkElement child = VisualTreeHelper.GetChild(element, i) as FrameworkElement;

        if (child == null)
            continue;

        if (child is T && child.Name.Equals(sChildName))
        {
            childElement = (T)child;
            break;
        }

        childElement = FindElementByName<T>(child, sChildName);

        if (childElement != null)
            break;
    }

    return childElement;
}

And, how I use it, just add button, and on button Click:

private void Button_OnClick(object sender, RoutedEventArgs e)
{
    var element = FindElementByName<ComboBox>(ccBloodGroup, "cbBloodGroup");
}
 [1]: http://stackoverflow.com/a/19907800/243563

An alternative is to pass the workGridView as a CommandParameter:

<Button Grid.Row="1" Grid.Column="0"
    CommandParameter="{Binding ElementName=workGridView}"
    Command="{Binding addWorkCommand}" >
 ....

private void addWork(object o)
{
    RadGridView grid = o as RadGridView;
    grid.BeginInsert();
}