Introduction

This project shows how to use a Static Bridge or Relay to share a property between Visual Tree elements and elements that have been removed from the UI, due to source data changes. In this example, a forum poster wondered why they got the following error when they deleted an item from the data bound to a DataGrid.
 

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor,AncestorType='System.Windows.Controls.DataGrid', AncestorLevel='1''. BindingExpression:Path=CanUserAddRows; DataItem=null; target element is 'DataGridCell' (Name=''); target property is 'NoTarget' (type 'Object')

 

Building the Sample

Just download, build and run.
 
Description
The problem was being caused by the following, perfectly acceptable trigger on the DataGridCell...
XAML
Edit|Remove
<MultiDataTrigger    <MultiDataTrigger.Conditions        <Condition Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=CanUserAddRows}" Value="False" /> 
        <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True" /> 
    </MultiDataTrigger.Conditions> 
    <Setter Property="Background" Value="Gold"/> 
</MultiDataTrigger>
The RelativeSource was using FindAncestor to traverse up the Visual Tree to find the DataGrid.
 
When an item was removed from the source collection, the DataGrid removes the row.
 
However, when the row is removed, it triggers the IsSelected binding to update, which causes the MultiDataTrigger to go check the CanUserAddRows property of the DataGrid. But the row is now "orphaned" from the parent control, so FindAncestor cannot find the source. That is what causes the error.
 
  

The answer is a Static Bridge or Relay, whatever you want to call it, there are many uses, this article is to explain the concept for you to adapt as you need.

 

C#
Edit|Remove
    public class Bridge : FrameworkElement, INotifyPropertyChanged 
    { 
        public Bridge() 
        { 
            DataContext = this; 
        } 
 
        bool _BoolUserAddRows; 
        public bool BoolUserAddRows 
        { 
            get 
            { 
                return _BoolUserAddRows; 
            } 
            set 
            { 
                if (_BoolUserAddRows != value) 
                { 
                    _BoolUserAddRows = value; 
                    RaisePropertyChanged("BoolUserAddRows"); 
                } 
            } 
        } 
 
        void RaisePropertyChanged(string prop) 
        { 
            if (PropertyChanged != null) 
                PropertyChanged(thisnew PropertyChangedEventArgs(prop)); 
        } 
 
        public event PropertyChangedEventHandler PropertyChanged; 
    }
 
It inherits FrameworkElement simply for easy use in XAML and DataContext.
This is then made available to all the Window's controls in the Resources:
XAML
Edit|Remove
    <Window.Resources> 
        <local:Bridge x:Key="MyBridge"/> 
    </Window.Resources>
 
In this example, it is used in the DataGrid to pass out and control the CanUserAddRowsProperty, and is available to the outgoing, orphaned row control triggers via the same StaticResource MyBridge.
 
XAML
Edit|Remove
        <DataGrid x:Name="dataGrid2" ItemsSource="{Binding AllItems2}" CanUserAddRows="{Binding BoolUserAddRows, Source={StaticResource MyBridge}}" HorizontalAlignment="Left" VerticalAlignment="Top" > 
            <DataGrid.CellStyle> 
                <Style TargetType="{x:Type DataGridCell}"> 
                    <Style.Triggers> 
                        <MultiDataTrigger> 
                            <MultiDataTrigger.Conditions> 
                                <Condition Binding="{Binding BoolUserAddRows, Source={StaticResource MyBridge}}" Value="False" /> 
                                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True" /> 
                            </MultiDataTrigger.Conditions> 
                            <Setter Property="Background" Value="Gold"/> 
                        </MultiDataTrigger> 
                    </Style.Triggers> 
                </Style> 
            </DataGrid.CellStyle> 
        </DataGrid>
 
  
 

Source Code Files