2

Note: I read over this question and its answers: HorizontalAlignment=Stretch, MaxWidth, and Left aligned at the same time?. None of them do what I am looking for.


I have the following xaml:

<Grid ShowGridLines="True" x:Name="_testGrid" Height="30" >
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"></ColumnDefinition>
    <ColumnDefinition Width="*"></ColumnDefinition>
    <ColumnDefinition Width="*"></ColumnDefinition>
  </Grid.ColumnDefinitions>

  <TextBox Text="Text 1" HorizontalAlignment="Stretch"
          MaxWidth="75" Margin="5"/>
  <TextBox Grid.Column="1" Text="Text 2" Margin="5"                 
       HorizontalAlignment="Stretch" MaxWidth="130"/>
  <TextBox Grid.Column="2"  Text="Text 3" Margin="5"               
       HorizontalAlignment="Stretch" MaxWidth="100"/>
</Grid>

It produces this:

Three Text Boxes Centered in their columns

This setup has great resizing support. If the window shrinks then the TextBoxes will shrink too.

The only problem is I need them left aligned:

Show where I want the textboxes

All the solutions I see end up chopping off part of the textbox (not shrinking it).

Is what I am looking for possible with WPF?

Community
  • 1
  • 1
Vaccano
  • 78,325
  • 149
  • 468
  • 850

3 Answers3

5

Found an answer here.

It works only with a grid. Here is the updated xaml:

<Grid ShowGridLines="True" x:Name="_testGrid" Height="30" >
  <Grid.ColumnDefinitions>
    <ColumnDefinition MaxWidth="75" Width="*"/>
    <ColumnDefinition Width="0.01*" />
    <ColumnDefinition MaxWidth="130" Width="*"/>
    <ColumnDefinition Width="0.01*" />
    <ColumnDefinition MaxWidth="100" Width="*"/>
    <ColumnDefinition Width="0.01*" />
  </Grid.ColumnDefinitions>

  <TextBox Grid.Column="0" Text="Text 1" Margin="5"/>
  <TextBox Grid.Column="2" Text="Text 2" Margin="5"  />
  <TextBox Grid.Column="4" Text="Text 3" Margin="5" />
</Grid>
Vaccano
  • 78,325
  • 149
  • 468
  • 850
2

You might also put your TextBoxes in a specialized Panel like this:

public class LeftStretchPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        foreach (UIElement element in InternalChildren)
        {
            element.Measure(availableSize);
        }

        return new Size();
    }

    protected override Size ArrangeOverride(Size arrangeBounds)
    {
        foreach (UIElement element in InternalChildren)
        {
            double width = arrangeBounds.Width;
            FrameworkElement fwElement = element as FrameworkElement;

            if (fwElement != null && width > fwElement.MaxWidth)
            {
                width = fwElement.MaxWidth;
            }

            element.Arrange(new Rect(0, 0, width, arrangeBounds.Height));
        }

        return arrangeBounds;
    }
}

Your XAML would then look like this:

<Grid ShowGridLines="True" Height="30">
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <local:LeftStretchPanel Grid.Column="0" Margin="5">
        <TextBox Text="Text 1" MaxWidth="75"/>
    </local:LeftStretchPanel>
    <local:LeftStretchPanel Grid.Column="1" Margin="5">
        <TextBox Text="Text 2" MaxWidth="130"/>
    </local:LeftStretchPanel>
    <local:LeftStretchPanel Grid.Column="2" Margin="5">
        <TextBox Text="Text 3" MaxWidth="100"/>
    </local:LeftStretchPanel>
</Grid>
Clemens
  • 123,504
  • 12
  • 155
  • 268
0

What you are doing is actually quite complex.

You actually want it left aligned. That is easy. Set it to HorizontalAlignment="Left".

You want a min size and max size and the ability to grow in between those sizes when the window is resized.

First, you need the TextBox to have a parent between it and the Column that will expand to the full width of the Column.

<Window x:Class="TestTextAlignment.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:loc="clr-namespace:TestTextAlignment"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
    <Grid Name="MainGrid" ShowGridLines="True" Height="30" >
        <Grid.Resources>
            <loc:ColumnSizeToTextBoxSizeConverter x:Key="SizeConverter" LeftMargin="5" RightMargin="25"/>
        </Grid.Resources>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Name="ColDef1" Width="*"></ColumnDefinition>
            <ColumnDefinition Name="ColDef2" Width="*"></ColumnDefinition>
            <ColumnDefinition Name="ColDef3" Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <DockPanel Name="Col1">
            <TextBox Text="Text 1" Margin="5" HorizontalAlignment="Left" MinWidth="100" MaxWidth="300" 
                     Width="{Binding ElementName=Col1, Path=ActualWidth, Mode=OneWay, Converter={StaticResource SizeConverter}}" />
        </DockPanel>
        <DockPanel Name="Col2" Grid.Column="1">
            <TextBox Text="Text 2" Margin="5" HorizontalAlignment="Left" MinWidth="100" MaxWidth="300"  
                     Width="{Binding ElementName=Col2, Path=ActualWidth, Mode=OneWay, Converter={StaticResource SizeConverter}}" />
        </DockPanel>
        <DockPanel Name="Col3" Grid.Column="2" >
            <TextBox Text="Text 3" Margin="5" HorizontalAlignment="Left" MinWidth="100" MaxWidth="300"  
                     Width="{Binding ElementName=Col3, Path=ActualWidth, Mode=OneWay, Converter={StaticResource SizeConverter}}" />
        </DockPanel>
    </Grid>
</Window>

Then as you see in the XAML, you need a converter, that will set the TextBox size to the parent object minus the left and right margins.

using System;
using System.Windows.Data;

namespace TestTextAlignment
{
    public class ColumnSizeToTextBoxSizeConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (double)value - LeftMargin - RightMargin;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion

        public double LeftMargin { get; set; }
        public double RightMargin { get; set; }
    }
}

Note: You could enhance the converter to take the left and right margins in as Convert Parameters so one converter can be used to send different sizes to any element.

Rhyous
  • 6,510
  • 2
  • 44
  • 50