Передайте значение одного элемента управления преобразователю, чтобы установить ширину другого элемента управления.

Я хочу установить ширину 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 единиц больше из-за того, что левое и правое поля установлены на 5.

Итак, я подумал... Давайте использовать конвертер. Но я не знаю, как передать ActualWidth моего элемента управления контейнером (СМ. ВЫШЕ: LayoutRoot).

Я знаю, как использовать преобразователи, и даже преобразователи с параметрами, только не с параметром вроде... Binding ElementName=LayoutRoot,Path=ActualWidth

Например, я не могу заставить это работать:

Width="{Binding Converter={StaticResource PositionConverter},  
       ConverterParameter={Binding ElementName=LayoutRoot,Path=ActualWidth }}"

Я надеюсь, что сделал это достаточно ясно, и надеюсь, что вы можете помочь, потому что Google сегодня мне не поможет.


person Doug    schedule 23.11.2008    source источник


Ответы (5)


вы должны использовать другой элемент управления в качестве источника, а не параметра. Параметр должен быть постоянным и в вашем случае может быть -5.

В данный момент я не рядом с VS, поэтому синтаксис может быть неточным, однако это что-то вроде:

Width="{Binding ElementName=LayoutRoot, Path=ActualWidth,
Converter={StaticResource PositionConverter}, ConverterParameter=-5}"

(Преобразователь получит -5 в виде строки и перед использованием должен будет преобразовать его в число.)

По моему опыту, лучше использовать обратный вызов OnXXXChanged для DependecyProperty XXX, а не привязывать элементы управления в одном окне/корневом элементе управления друг к другу. Одна из причин этого заключается в том, что вы можете захотеть привязать их к внешнему элементу позже.

Или, альтернативно, используйте мультибиндинг:

<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>

и преобразователь, который преобразует два параметра в желаемое значение.

person Danny Varod    schedule 23.11.2008
comment
Спасибо Дэнни. Это сработало просто отлично. Но я надеялся, что мне не придется жестко кодировать значение параметра. Я не знал, что параметр должен быть константой. Спасибо! - person Doug; 23.11.2008
comment
Большое спасибо, так полезно! - person Jacob; 08.09.2014

да .. у меня работает мульти-привязка .. на самом деле я пытался отправить элемент в качестве параметра преобразования, но он не принимается. вот почему я передал элемент как значение классу преобразователя.

ниже мой пример..

<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>

При изменении размера окна необходимо изменить размер моего первого столбца gridview, а не двух других столбцов gridview. Я передал 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
}

это сработало для меня... :)

person Community    schedule 30.07.2009

Хотя я подозреваю, что может быть лучший способ решить вашу проблему, я думаю, что у меня есть ответ на то, что вы хотите сделать. (Вы не упомянули тип вашего контейнера. Например, 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>

Далее Конвертер. У нас возникла проблема... поскольку ConverterParameter для методов Convert не может быть динамическим значением по какой-то причине. Таким образом, мы проникаем в Textbox Margin через общедоступное свойство Converter, которое мы установили в 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;
        }

ХТН. Спасибо за упражнение :)

person Gishu    schedule 23.11.2008
comment
Спасибо Гишу! Ваш образец помог мне узнать больше о преобразователях. Хотя ваш ответ сработал, я закончил отмечать ответ Дэнни как ответ, потому что это было решение, которое я использовал. Я был уставшим и ленивым, а его, хотя и менее гибким, было меньше кода. Спасибо! - person Doug; 23.11.2008
comment
Как меня преследовали многие решения, которые не сработали, пока я не нашел это! Спасибо - person nemesisfixx; 27.01.2014

Если ваше текстовое поле является прямым дочерним элементом LayoutRoot, просто установите следующее свойство в своем текстовом поле.

HorizontalAlignment="Stretch"
person viggity    schedule 05.01.2009

Согласно http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/7298ceb5-bf56-47aa-a161-5dd99189408b, вы можете добавить свойство Dependency к своему пользовательскому преобразователю, если ваш преобразователь является производным от DependencyObject.

В этом случае вы даже можете использовать привязку данных для передачи значений тем свойствам, где вы определяете преобразователь (в словаре ресурсов) в XAML.

person George Birbilis    schedule 03.07.2012