How can I bind to a control without a Name or an x:Name?
binding, c#, controls, name-attribute, wpf
Solution
Other way apart from binding with `ElementName`, is using x:Reference but it also needs the target element to have `x:Name` defined on it. So, that's out of scope here.
Other approach what I can think of without defining name is to bind something like below (binding to parent and than indexer to get target child).
But this is tightly coupled to your Logical tree structure -
<StackPanel>
<TextBlock Text="Test"/>
<TextBlock Text="{Binding Parent.Children[0].Text,
RelativeSource={RelativeSource Mode=Self}}"/>
</StackPanel>
Also, this can be achieved using IValueConverter. As you mentioned that there is only one element of such type in your parent container, you can pass a parent to converter which will traverse the child using VisualTreeHelper class.
<StackPanel>
<TextBlock Text="Test"/>
<TextBlock Text="{Binding Parent, RelativeSource={RelativeSource Self},
Converter={StaticResource MyConverter}}"/>
</StackPanel>
Here is your converter code -
public class MyConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (value is DependencyObject)
{
var textBlock = FindChild<TextBlock>((DependencyObject)value, null);
return (textBlock == null)?string.Empty:textBlock.Text;
}
else
return String.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return Binding.DoNothing;
}
}
Here's the method to traverse using VisualTreeHelper. I have put this method in my Utility class, comes handy in many situations -
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject
{
// Confirm parent is valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not
// overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null
&& frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
Problem
Right, so I'm following a tutorial. This one, to be exact. Some code that it provides is this: ``` <TextBlock Margin="2" Foreground="Red" FontWeight="Bold" Text="{Binding ElementName=AddressBox, Path=(Validation.Errors), Converter={StaticResource eToMConverter}}" /> ``` As you can see, it binds to a `TextBox`'s validation errors, and that `TextBox`'s `x:Name` is `AddressBox`. Now, my problem is: I've got a `Window` a bit like this one. It also has only one `TextBox`. However, I'd rather not use `Name`s or `x:Name`s if possible. Is it possible to bind to another `Control`'s `Validation.Errors` without being that control being named, and that control being the only one of that type of `Control` on that same `Window`? The `TextBox` is on the same level as the `ListBox`.