HorizontalAlignment = Stretch, MaxWidth и Left выровнены одновременно?

96

Кажется, это должно быть легко, но я в тупике. В WPF мне бы хотелось, чтобы TextBox растягивался по ширине своего родителя, но только до максимальной ширины. Проблема в том, что я хочу, чтобы он оставался оправданным в пределах своего родителя. Чтобы заставить его растягиваться, вы должны использовать HorizontalAlignment = "Stretch", но тогда результат будет центрирован. Я экспериментировал с HorizontalContentAlignment, но, похоже, он ничего не делает.

Как сделать так, чтобы это синее текстовое поле увеличивалось с размером окна, имело максимальную ширину 200 пикселей и выравнивалось по левому краю?

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <StackPanel>  
    <TextBox Background="Azure" Text="Hello" HorizontalAlignment="Stretch" MaxWidth="200" />
  </StackPanel>
</Page>

Что за хитрость?

Скотт Бассинджер
источник

Ответы:

89

Вы можете установить HorizontalAlignmentзначение Left, установить, MaxWidthа затем привязать Widthк ActualWidthродительскому элементу:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <StackPanel Name="Container">   
    <TextBox Background="Azure" 
    Width="{Binding ElementName=Container,Path=ActualWidth}"
    Text="Hello" HorizontalAlignment="Left" MaxWidth="200" />
  </StackPanel>
</Page>
Нир
источник
7
Без автоматического изменения размера .. Кажется, подходит для содержания .. Я что-то упустил?
Gishu
Похоже, это
приводит
2
@Gishu, убедитесь , что вы установили HorizontalAlignment="Stretch"на Container элементе. (ps, я понимаю, что вы задали этот вопрос более 6 лет назад.)
Дэвид Мердок
51
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" MaxWidth="200"/>
    </Grid.ColumnDefinitions>

    <TextBox Background="Azure" Text="Hello" />
</Grid>
Кент Бугарт
источник
Я думаю, вам нужно установить VerticalAlignment = "Top" для текстового поля ... кажется, что по умолчанию растягивается.
Gishu
1
+1. Красиво и чисто. Каждый раз, когда я пытаюсь управлять макетом путем привязки к некоторой фактической ширине (как в принятом ответе), все становится беспорядочно.
Эрен Эрсонмез
1
Я только что столкнулся с этим вопросом, пытаясь решить ту же проблему. В моем случае это лучший ответ, поскольку он работает в WinRT. Другой ответ - нет, потому что вы не можете привязать ActualWidth в WinRT.
Slade
Slade - я только что сделал это в приложении Windows Store: MaxWidth = "{Binding ActualWidth, ElementName = Layout}", и он отлично работал для привязки MaxWidth к свойству ActualWidth других элементов. Я не уверен, почему это сработало для меня, но он сделал то, что я ожидал, и, как упоминалось ранее в ответе, в котором было решение для привязки ширины, он не менял размер элемента при изменении размера родительского элемента из-за увеличения окна или меньше.
Дэвид Ректор
8

Оба предоставленных ответа сработали для указанной мной проблемы - Спасибо!

Однако в моем реальном приложении я пытался ограничить панель внутри ScrollViewer, и метод Кента не справлялся с этим очень хорошо по какой-то причине, которую я не стал отслеживать. По сути, элементы управления могли выходить за пределы параметра MaxWidth, что противоречило моим намерениям.

Техника Нира работала хорошо и не имела проблем с ScrollViewer, хотя есть одна небольшая вещь, на которую следует обратить внимание. Вы должны быть уверены, что правое и левое поля в TextBox установлены на 0, иначе они будут мешать. Я также изменил привязку, чтобы использовать ViewportWidth вместо ActualWidth, чтобы избежать проблем при появлении вертикальной полосы прокрутки.

Скотт Бассинджер
источник
6

Вы можете использовать это для ширины вашего DataTemplate:

Width="{Binding ActualWidth,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollContentPresenter}}}"

Убедитесь, что ваш корень DataTemplate имеет Margin = "0" (вы можете использовать какую-либо панель в качестве корня и установить Margin для дочерних элементов этого корня)

Филип Скакун
источник
1

Функционально аналогичен принятому ответу, но не требует указания родительского элемента:

<TextBox
    Width="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type FrameworkElement}}}"
    MaxWidth="500"
    HorizontalAlignment="Left" />
maxp
источник
1

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

Мне это тоже было нужно, и я написал поведение, чтобы позаботиться об этом. Итак, вот поведение:

public class StretchMaxWidthBehavior : Behavior<FrameworkElement>
{        
    protected override void OnAttached()
    {
        base.OnAttached();
        ((FrameworkElement)this.AssociatedObject.Parent).SizeChanged += this.OnSizeChanged;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        ((FrameworkElement)this.AssociatedObject.Parent).SizeChanged -= this.OnSizeChanged;
    }

    private void OnSizeChanged(object sender, SizeChangedEventArgs e)
    {
        this.SetAlignments();
    }

    private void SetAlignments()
    {
        var slot = LayoutInformation.GetLayoutSlot(this.AssociatedObject);
        var newWidth = slot.Width;
        var newHeight = slot.Height;

        if (!double.IsInfinity(this.AssociatedObject.MaxWidth))
        {
            if (this.AssociatedObject.MaxWidth < newWidth)
            {
                this.AssociatedObject.HorizontalAlignment = HorizontalAlignment.Left;
                this.AssociatedObject.Width = this.AssociatedObject.MaxWidth;
            }
            else
            {
                this.AssociatedObject.HorizontalAlignment = HorizontalAlignment.Stretch;
                this.AssociatedObject.Width = double.NaN;
            }
        }

        if (!double.IsInfinity(this.AssociatedObject.MaxHeight))
        {
            if (this.AssociatedObject.MaxHeight < newHeight)
            {
                this.AssociatedObject.VerticalAlignment = VerticalAlignment.Top;
                this.AssociatedObject.Height = this.AssociatedObject.MaxHeight;
            }
            else
            {
                this.AssociatedObject.VerticalAlignment = VerticalAlignment.Stretch;
                this.AssociatedObject.Height = double.NaN;
            }
        }
    }
}

Тогда вы можете использовать это так:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>

    <TextBlock Grid.Column="0" Text="Label" />
    <TextBox Grid.Column="1" MaxWidth="600">
          <i:Interaction.Behaviors>                       
               <cbh:StretchMaxWidthBehavior/>
          </i:Interaction.Behaviors>
    </TextBox>
</Grid>

И, наконец, забыть использовать System.Windows.Interactivityпространство имен для использования поведения.

YC
источник
0

я хотел бы использовать SharedSizeGroup

<Grid>
    <Grid.ColumnDefinition>
        <ColumnDefinition SharedSizeGroup="col1"></ColumnDefinition>  
        <ColumnDefinition SharedSizeGroup="col2"></ColumnDefinition>
    </Grid.ColumnDefinition>
    <TextBox Background="Azure" Text="Hello" Grid.Column="1" MaxWidth="200" />
</Grid>
Патрик Кэрнс
источник
0

В моем случае мне пришлось поместить текстовое поле в панель стека, чтобы растянуть текстовое поле с левой стороны. Спасибо за предыдущий пост. Просто для примера я установил цвет фона, чтобы увидеть, что происходит при изменении размера окна.

<StackPanel Name="JustContainer" VerticalAlignment="Center" HorizontalAlignment="Stretch" Background="BlueViolet" >
    <TextBox 
       Name="Input" Text="Hello World" 
       MaxWidth="300"
       HorizontalAlignment="Right"
       Width="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type FrameworkElement}}}">
    </TextBox>
</StackPanel>
Sparedev
источник