WPF - передать значение одного элемента управления в конвертер, чтобы установить ширину для другого элемента управления - PullRequest
12 голосов
/ 23 ноября 2008

Я хочу установить ширину 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 не поможет мне сегодня вечером.

ТИА!

Doug

Ответы [ 5 ]

13 голосов
/ 23 ноября 2008

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

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

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

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

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

Или, альтернативно, используйте мультисвязывание:

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

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

6 голосов
/ 30 июля 2009

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

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

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

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

3 голосов
/ 23 ноября 2008

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

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

0 голосов
/ 03 июля 2012

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

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

0 голосов
/ 05 января 2009

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

HorizontalAlignment="Stretch"
...