WPF - передать значение одного элемента управления конвертеру для установки ширины на другом элементе управления
Я хочу установить ширину TextBlock на основе ширины своего контейнера, минус поля, установленные в TextBlock.
Вот мой код
<TextBlock x:Name="txtStatusMessages"
Width="{Binding ElementName=LayoutRoot,Path=ActualWidth }"
TextWrapping="WrapWithOverflow"
Foreground="White"
Margin="5,5,5,5">This is a message
</TextBlock>
И это отлично работает, за исключением того факта, что TextBlock имеет 10 единиц, слишком больших из-за того, что значение Left и Right Margins установлено равным 5.
ОК, поэтому я подумал... Позвольте использовать конвертер. Но я не знаю, как передать ActualWidth моего элемента управления контейнером (СМ. ВЫШЕ: LayoutRoot).
Я знаю, как использовать преобразователи и даже преобразователи с параметрами, просто не такой параметр, как... Binding ElementName = LayoutRoot, Path = ActualWidth
Например, я не могу сделать эту работу...
Width="{Binding Converter={StaticResource PositionConverter},
ConverterParameter={Binding ElementName=LayoutRoot,Path=ActualWidth }}"
Надеюсь, я сделал это достаточно ясно и надеюсь, что вы сможете помочь, потому что Google не помогает мне сегодня вечером.
ТИА!
Дуга
Ответы
Ответ 1
вы должны использовать другой элемент управления как источник, а не параметр.
Параметр должен быть константой и в вашем случае может быть -5.
Я не близок к VS на данный момент, поэтому синтаксис может быть неточным, однако это что-то вроде:
Width="{Binding ElementName=LayoutRoot, Path=ActualWidth,
Converter={StaticResource PositionConverter}, ConverterParameter=-5}"
(Конвертер получит -5 как строку и должен будет преобразовать его в число перед его использованием.)
По моему опыту лучше использовать обратный вызов OnXXXChanged DependecyProperty XXX и не связывать элементы управления внутри одного и того же окна/корневого элемента управления друг с другом.
Одной из причин этого является то, что позже вы можете связать их с внешним элементом.
Или, альтернативно, используйте 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>
и конвертер, который преобразует два параметра в нужное значение.
Ответ 2
yes..multi binding работает для меня.. на самом деле я попытался отправить элемент в качестве конвертерного параметра, но его не принимаю. поэтому я передал элемент как значение классу преобразователя.
ниже - мой пример.
<ListView ... >
<ListView.View>
<GridView>
<GridViewColumn Header="xyz" >
<GridViewColumn.Width>
<MultiBinding Converter="{StaticResource GetWidthfromParentControl}">
<MultiBinding.Bindings>
<Binding ElementName="lstNetwork" Path="ActualWidth"/>
<Binding ElementName="MyGridView"/>
</MultiBinding.Bindings>
</MultiBinding>
</GridViewColumn.Width>
....
</GridViewColumn>
<GridViewColumn ...>
....
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
В окне resize мой первый gridviewcolumn должен быть изменен, а не два других gridviewcolumns.
я передал Actualwidth списка, а также общий объект gridview как элемент.
если вы перейдете код конвертера...
class GetWidthfromParentControl : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
GridView view = values[1] as GridView;
GridViewColumnCollection collc = view.Columns;
double actualWidths = collc[1].ActualWidth + collc[2].ActualWidth;
return ((double)values[0] - actualWidths );
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
#endregion
}
это сработало для меня...:)
Ответ 3
Хотя я подозреваю, что может быть лучший способ решить вашу проблему, я думаю, что у меня есть ответ на то, что вы хотите сделать. (Вы не указали, какой тип вашего контейнера. Например, StackPanel выполняет расчет ширины для вас. См. TextBox № 2 ниже)
Сначала 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>
Далее конвертер. У нас здесь проблема. Поскольку то почему-то преобразователь для методов Convert не может быть динамическим значением. Итак, мы крадуемся в поле "Текстовое поле" через общедоступное свойство конвертера, которое мы установили в Window 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;
}
НТН. Спасибо за упражнение:)
Ответ 4
Если ваше текстовое поле является прямым дочерним элементом LayoutRoot, просто установите в своем текстовом поле следующее свойство
HorizontalAlignment="Stretch"
Ответ 5
Согласно http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/7298ceb5-bf56-47aa-a161-5dd99189408b, вы можете добавить свойство Dependency к своему пользовательскому конвертеру, если ваш конвертер получен из DependencyObject.
В этом случае вы даже можете использовать привязку данных для передачи значений к тем свойствам, где вы определяете конвертер (в словаре ресурсов) в XAML.