WPF Binding to ElementName inside ItemsControl

19,278

Solution 1

You are using RelativeSource, which can't be mixed with ElementName, but you once you have the correct RelativeSource, you can drill down deeper using path.

e.g.

Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MyView} }, Path=UI_BirthdayVisibleCB.IsChecked, Converter={StaticResource BoolToVis}}"

presumably you have some xaml like this:

<UserControl class="MyView" ... >...<CheckBox Name="UI_BirthdayVisibileCB"/> ...

The above binding should find this UserControl by type based on RelativeSource, then it will try to find a property named UI_BirthdayVisibleCB, which it won't find because WPF XAML implements this named element as a field.

The easy work around is to go into your codebehind and expose a property for it.

public object BirthdayVisibileCB_4_binding {
    get { return UI_BirthdayVisibileDB; }
}

and bind to it instead:

Visibility="{Binding RelativeSource={RelativeSource FindAncestor, 
AncestorType={x:Type local:MyView} }, 
Path=BirthdayVisibileCB_4_binding.IsChecked, Converter={StaticResource BoolToVis}}"

Yes, it kind of a pain to do this, but MVVM only matches WPF so far... its not a great fit, its only the best fit we have around.

Solution 2

If you want to try RelativeSource, you have to remove ElementName from the declaration:

However, only one of the three properties, ElementName, Source, and RelativeSource, should be set for each binding, or a conflict might occur. This property throws an exception if there is a binding source conflict.

http://msdn.microsoft.com/en-us/library/system.windows.data.binding.elementname.aspx

Your usage of ElementName seems correct, so I'll continue to look at the problem if you prefer that over RelativeSource.

Share:
19,278
bufferz
Author by

bufferz

while(true) { Facepalm(); } My view: studiostyles theme

Updated on June 17, 2022

Comments

  • bufferz
    bufferz almost 2 years

    I have a checkbox, and an ItemsControl populating several DataGrids the following way:

    <Checkbox Content="Birthday Column Visible" x:Name="UI_BirthdayVisibleCB" />
    
    <ItemsControl  ItemsSource="{Binding Path=ParentsCollection}">
       <ItemsControl.ItemTemplate>
          <DataTemplate>
             <DataGrid  AutoGenerateColumns="False" ItemsSource="{Binding Children}">
                <DataGrid.Columns>
                    <DataGridTemplateColumn Header="Birthday" Width="120" Visibility="{Binding IsChecked, ElementName=UI_BirthdayVisibleCB, Converter={StaticResource BoolToVis}}" >
    ...
                   </DataGridTemplateColumn>
                </DataGrid.Columns>
             </DataGrid>
    </Rest of closing tags>
    

    This creates binding output errors as it tries to find IsChecked on the DataGridTemplateColumn. If I try to search for a Relative Ancestor I receive the exception:

    Binding.RelativeSource cannot be set while using Binding.ElementName.
    

    I have a ViewModel, and stick to MVVM mostly, but in this case I'd really like to keep the column visibilities on the View layer. Note that BoolToVis just converts Boolean to Visibility.

    Edit

    Here is an example of what I'm trying to do:

     <DataGridTemplateColumn Header="Birthday" Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MyView} }, Path=IsChecked, ElementName=UI_BirthdayVisibleCB, Converter={StaticResource BoolToVis}}" />
    

    It compiles but doesn't run however, it throws the exception above.

  • bufferz
    bufferz over 13 years
    The problem is that I need both Element name and RelativeSource, since my DataContext is set to the current item of the ItemsControl.
  • McStretch
    McStretch over 13 years
    Post the code that uses both ElementName and RelativeSource please.
  • bufferz
    bufferz over 13 years
    Ok -- I edited my question to show what I'm attempting to do.
  • jrwren
    jrwren over 13 years
    I don't think you need both. Have you tried with just ElementName and without RelativeSource? it should work.
  • bufferz
    bufferz over 13 years
    @jrwren -- Here's the error I receive using just ElementName: "Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=IsChecked; DataItem=null; target element is 'DataGridTemplateColumn' (HashCode=36783718); target property is 'Visibility' (type 'Visibility')"
  • jrwren
    jrwren over 13 years
    Get rid of the DataItem=null in your binding expression too, or am I misunderstanding the error code?
  • aruno
    aruno over 12 years
    this is the best solution I found to this problem. one added bonus is it compile time safe
  • Henry Merriam
    Henry Merriam almost 12 years
    Thank you for this! I've been really frustrated trying to solve a similar issue. I'm amazed that WPF has such an oversight. Since posting this, have you encountered any other solutions?
  • jrwren
    jrwren almost 12 years
    @HenryMerriam nope, I've not found a better way. I also am no longer using WPF day to day :) Good luck.
  • AshbyEngineer
    AshbyEngineer about 9 years
    Great solution! Thanks!