Pass the value of one control to a Converter to set the width on another control
Solution 1
you're supposed to use the other control as the source, not the parameter. The parameter has to be a constant and in your case can be -5.
I'm not near VS at the moment so the syntax maybe inaccurate, however, it is something like:
Width="{Binding ElementName=LayoutRoot, Path=ActualWidth,
Converter={StaticResource PositionConverter}, ConverterParameter=-5}"
(The converter will receive -5 as a string and will have to convert it into a number before using it.)
From my experience it is better to use the OnXXXChanged callback of DependecyProperty XXX, and not bind controls within the same window/root control one to another. One of the reasons for this is that you may want to bind them to an external element later on.
Or alternatively, use multibinding:
<TextBlock>
<TextBlock.Width>
<MultiBinding Converter="{StaticResource yourConverter}">
<MultiBinding.Bindings>
<Binding /> <!-- Bind to parameter 1 here -->
<Binding /> <!-- Bind to parameter 2 here -->
</MultiBinding.Bindings>
</MultiBinding>
</TextBlock.Width>
</TextBlock>
and and a converter which converts the two parameters to the value you want.
Solution 2
Although I suspect there may be a better way to solve your problem, I think I have an answer for what you want to do. ( You didn't mention what type your container is. A StackPanel for instance takes care of the width calculation for you. See TextBox#2 below)
First the XAML
<Window x:Class="WpfApplication1.Window2" ...
xmlns:local="clr-namespace:WpfApplication1"
Title="Window2" Height="300" Width="300">
<Window.Resources>
<local:WidthSansMarginConverter x:Key="widthConverter" />
</Window.Resources>
<Grid>
<StackPanel x:Name="stack">
<TextBlock x:Name="txtStatusMessages"
Width="{Binding ElementName=stack,Path=ActualWidth,
Converter={StaticResource widthConverter}}"
TextWrapping="WrapWithOverflow"
Background="Aquamarine"
Margin="5,5,5,5">
This is a message
</TextBlock>
<TextBlock x:Name="txtWhatsWrongWithThis"
TextWrapping="WrapWithOverflow"
Background="Aquamarine"
Margin="5,5,5,5">
This is another message
</TextBlock>
</StackPanel>
</Grid>
</Window>
Next the Converter. We have a problem here.. since the ConverterParameter for the Convert methods cannot be a dynamic value for some reason. So we sneak in the Textbox Margin via a public property of the Converter that we set in Window's ctor. WidthSansMarginConverter.cs
public class WidthSansMarginConverter : IValueConverter
{
private Thickness m_Margin = new Thickness(0.0);
public Thickness Margin
{
get { return m_Margin; }
set { m_Margin = value; }
}
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (targetType != typeof(double)) { return null; }
double dParentWidth = Double.Parse(value.ToString());
double dAdjustedWidth = dParentWidth-m_Margin.Left-m_Margin.Right;
return (dAdjustedWidth < 0 ? 0 : dAdjustedWidth);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Window2.xaml.cs
public Window2()
{
InitializeComponent();
WidthSansMarginConverter obConverter = this.FindResource("widthConverter") as WidthSansMarginConverter;
obConverter.Margin = txtStatusMessages.Margin;
}
HTH. Thanks for the exercise :)
Doug
Updated on March 24, 2020Comments
-
Doug about 4 years
I want to set the width of a TextBlock based on the width of its container, minus the margins set on the TextBlock.
Here is my code:
<TextBlock x:Name="txtStatusMessages" Width="{Binding ElementName=LayoutRoot,Path=ActualWidth }" TextWrapping="WrapWithOverflow" Foreground="White" Margin="5,5,5,5">This is a message </TextBlock>
And that works great except for the fact that the TextBlock is 10 units too big due to the Left and Right Margins bbeing set to 5.
OK, so I thought... Let's use a Converter. But I don't know how to pass the ActualWidth of my container control (SEE ABOVE: LayoutRoot).
I know how to use converters, and even converters with parameters, just not a parameter like... Binding ElementName=LayoutRoot,Path=ActualWidth
For example, I can't make this work:
Width="{Binding Converter={StaticResource PositionConverter}, ConverterParameter={Binding ElementName=LayoutRoot,Path=ActualWidth }}"
I hope I made this clear enough and hope that you can help because Google is no help for me tonight.
-
Doug over 15 yearsThanks Danny. This worked just fine. But I was hoping to not have to hard code the Parameter value. I didn't know that the Parameter needed to be a constant. Thanks!
-
Doug over 15 yearsThnaks Gishu! Your sample helped me learn more about converters. Altough your answer worked, I ended marking danny's answer as THE answer because it was the solution that I used. I was tired and lazy and his, altough less flexible, was less code. Thanks!
-
JWL over 10 yearsHow I've been haunted by the many solutions that failed to work, til I found this one! Thanks
-
Jacob over 9 yearsThank you very much, so helpful !