I am trying to implement a wpf user control that binds a text box to a list of doubles using a converter. How can i set the instance of user control to be the converter parameter?
the code for the control is shown below
Thanks
<UserControl x:Class="BaySizeControl.BaySizeTextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BaySizeControl"
>
<UserControl.Resources>
<local:BayListtoStringConverter x:Key="BaySizeConverter"/>
</UserControl.Resources>
<Grid>
<TextBox Name="Textbox_baysizes"
Text="{Binding RelativeSource={RelativeSource self},
Path=Parent.Parent.BaySizeItemsSource,
Converter={StaticResource BaySizeConverter}}"
/>
</Grid>
</UserControl>
The parameters are for constants needed by your converter. To provide an object instance to your converter, you can use MultiBinding.
Note: For this solution to work, you also need to modify your converter to implement IMultiValueConverter instead of IValueConverter. Fortunately, the modifications involved are fairly little. You will can add a validation for the number of values provided to your converter, 2 in your case.
<TextBox Name="Textbox_baysizes">
<TextBox.Text>
<MultiBinding Converter="{StaticResource BaySizeConverter}">
<Binding RelativeSource="{RelativeSource self}" Path="Parent.Parent.BaySizeItemsSource"/>
<Binding ElementName="Textbox_baysizes"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
Another way is making your converter inherit from DependencyObject (or FrameworkElement). This allows you to declare dependency properties, making it possible to set its values from XAML, even a Binding.
Example: A converter to multiply a value specifing the factor, which is obtained from a property (FactorValue) in a custom control (MyControl).
The converter:
public class MyConverter : DependencyObject, IValueConverter
{
// The property used as a parameter
public double Factor
{
get { return (double) GetValue(FactorProperty); }
set { SetValue(FactorProperty, value); }
}
// The dependency property to allow the property to be used from XAML.
public static readonly DependencyProperty FactorProperty =
DependencyProperty.Register(
"Factor",
typeof(double),
typeof(MyConverter),
new PropertyMetadata(1.15d));
#region IValueConverter Members
object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Use the property in the Convert method instead of "parameter"
return (double) value * Factor;
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Use in XAML:
<MyConverter x:Key="MyConv"
Factor={Binding ElementName=MyControl, Path=FactorValue}
/>
So, you can now declare a dependency property for each parameter you need in your converter and bind it.
I would name the control and then bind using ElementName:
<UserControl x:Class="BaySizeControl.BaySizeTextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BaySizeControl"
Name="Foobar"
>
<UserControl.Resources>
<local:BayListtoStringConverter x:Key="BaySizeConverter"/>
</UserControl.Resources>
<Grid>
<TextBox Name="Textbox_baysizes"
Text="{Binding RelativeSource={RelativeSource self},
Path=Parent.Parent.BaySizeItemsSource,
Converter={StaticResource BaySizeConverter,
ConverterParameter={Binding ElementName=Foobar} }}"
/>
</Grid>
</UserControl>
No, wait, that won't work because the ConverterParameter is not a Dependency Property, nor is the Binding a DependencyObject. A ReleativeSource markup extension should do what you want, though I've not used it nested inside other MarkupExtension - perhaps it is not well behaved in this case:
<TextBox Name="Textbox_baysizes"
Text="{Binding RelativeSource={RelativeSource self},
Path=Parent.Parent.BaySizeItemsSource,
Converter={StaticResource BaySizeConverter,
ConverterParameter={RelativeSource self} }}"
/>
I had the same problem, but I can't use MultiBindings since I need to correctly implement the ConvertBack method. Here is the solution I ended up implementing for a CheckBox's IsChecked property:
<CheckBox>
<CheckBox.IsChecked>
<Binding Converter="{StaticResource myConverter}" Path="Value">
<Binding.ConverterParameter>
<FrameworkElement DataContext="{TemplateBinding DataContext}" />
</Binding.ConverterParameter>
</Binding>
</CheckBox.IsChecked>
</CheckBox>
I'm not super familiar with TemplateBindings (or anything WPF for that matter), so maybe this only works because my CheckBox is in a DataTemplate...