水平对齐 = 拉伸,最大宽度,和左对齐在同一时间?

这看起来应该很容易,但我被难住了。在 WPF 中,我希望 TextBox 能够延伸到它的父级宽度,但是只能延伸到最大宽度。问题是,我希望它在其父代中保持正当性。为了让它伸展,你必须使用 HorizontalAlign = “ Stretch”,但是结果是居中的。我已经试验过 HorizontalContentAlign,但它似乎没有任何作用。

如何使这个蓝色文本框随着窗口的大小增长,最大宽度为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>

秘诀是什么?

105027 次浏览
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MaxWidth="200"/>
</Grid.ColumnDefinitions>


<TextBox Background="Azure" Text="Hello" />
</Grid>

You can set HorizontalAlignment to Left, set your MaxWidth and then bind Width to the ActualWidth of the parent element:

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

Both answers given worked for the problem I stated -- Thanks!

In my real application though, I was trying to constrain a panel inside of a ScrollViewer and Kent's method didn't handle that very well for some reason I didn't bother to track down. Basically the controls could expand beyond the MaxWidth setting and defeated my intent.

Nir's technique worked well and didn't have the problem with the ScrollViewer, though there is one minor thing to watch out for. You want to be sure the right and left margins on the TextBox are set to 0 or they'll get in the way. I also changed the binding to use ViewportWidth instead of ActualWidth to avoid issues when the vertical scrollbar appeared.

You can use this for the Width of your DataTemplate:

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

Make sure your DataTemplate root has Margin="0" (you can use some panel as the root and set the Margin to the children of that root)

I would use 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>

Maybe I can still help somebody out who bumps into this question, because this is a very old issue.

I needed this as well and wrote a behavior to take care of this. So here is the behavior:

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

Then you can use it like so:

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

Note: don't forget to use the System.Windows.Interactivity namespace to use the behavior.

Functionally similar to the accepted answer, but doesn't require the parent element to be specified:

<TextBox
Width="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type FrameworkElement}}}"
MaxWidth="500"
HorizontalAlignment="Left" />

In my case I had to put textbox into a stack panel in order to stretch textbox on left side. Thanks to previous post. Just for an example I did set a background color to see what’s happens when window size is changing.

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

These answers didn't work for me, because I needed a TextBox to stretch (i.e. consume all available space) until it reaches it's MaxWidth and, if more space is available, align to the right.

I created this simple control that works along the lines of Y C's answer, but doesn't require System.Windows.Interactivity:

public class StretchAlignmentPanel : ContentControl
{
public StretchAlignmentPanel()
{
this.SizeChanged += StretchAlignmentPanel_SizeChanged;
}


public static readonly DependencyProperty HorizontalFallbackAlignmentProperty = DependencyProperty.Register(
nameof(HorizontalFallbackAlignment), typeof(HorizontalAlignment), typeof(StretchAlignmentPanel), new PropertyMetadata(HorizontalAlignment.Stretch));


public HorizontalAlignment HorizontalFallbackAlignment
{
get { return (HorizontalAlignment)GetValue(HorizontalFallbackAlignmentProperty); }
set { SetValue(HorizontalFallbackAlignmentProperty, value); }
}


public static readonly DependencyProperty VerticalFallbackAlignmentProperty = DependencyProperty.Register(
nameof(VerticalFallbackAlignment), typeof(VerticalAlignment), typeof(StretchAlignmentPanel), new PropertyMetadata(VerticalAlignment.Stretch));


public VerticalAlignment VerticalFallbackAlignment
{
get { return (VerticalAlignment)GetValue(VerticalFallbackAlignmentProperty); }
set { SetValue(VerticalFallbackAlignmentProperty, value); }
}


private void StretchAlignmentPanel_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
{
var fe = this.Content as FrameworkElement;
if (fe == null) return;
        

if(e.WidthChanged) applyHorizontalAlignment(fe);
if(e.HeightChanged) applyVerticalAlignment(fe);
}


private void applyHorizontalAlignment(FrameworkElement fe)
{
if (HorizontalFallbackAlignment == HorizontalAlignment.Stretch) return;


if (this.ActualWidth > fe.MaxWidth)
{
fe.HorizontalAlignment = HorizontalFallbackAlignment;
fe.Width = fe.MaxWidth;
}
else
{
fe.HorizontalAlignment = HorizontalAlignment.Stretch;
fe.Width = double.NaN;
}
}


private void applyVerticalAlignment(FrameworkElement fe)
{
if (VerticalFallbackAlignment == VerticalAlignment.Stretch) return;


if (this.ActualHeight > fe.MaxHeight)
{
fe.VerticalAlignment = VerticalFallbackAlignment;
fe.Height= fe.MaxHeight;
}
else
{
fe.VerticalAlignment = VerticalAlignment.Stretch;
fe.Height= double.NaN;
}
}
}

It can be used like this:

<controls:StretchAlignmentPanel HorizontalFallbackAlignment="Right">
<TextBox MaxWidth="200" MinWidth="100" Text="Example"/>
</controls:StretchAlignmentPanel>