{x:Reference ...}
-> returns just a reference of an object it doesn't create that "bridge" between two properties like binding would do. Behind all that a service is being used that searches for the given name in a specific scope which is usually the window itself.
{Binding ElementName="..." }
-> first of all it creates that binding object then it searches for the object name but not by using the same technique under the hood as x:Reference. The search algorithm moves up and/or down in VisualTree to find the desired element. Therefore a functional VisualTree is always needed. As example when used inside a Non-UiElement, it won't work. In the end the Binding stays and does its daily bread.
This won't work:
<StackPanel> <Button x:name="bttn1" Visibility="Hidden">Click me</Button> <DataGrid> <DataGrid.Columns> <DataGridTextColumn Visibility="{Binding ElementName=bttn1, Path=DataContext.Visibility}"/> ....
This works:
<StackPanel> <Button x:name="bttn1" Visibility="Hidden">Click me</Button> <DataGrid> <DataGrid.Columns> <DataGridTextColumn Visibility="{Binding Source={x:Reference bttn1} Path=DataContext.Visibility}"/> ....
Sort of like that :)