Search code examples
wpfxamldatatemplatecontroltemplateresourcedictionary

Set width of first column equal to width of grid minus second column in xaml


How could I set the width of the first column equal to the width of the grid minus the width of the second column in XAML? I need to do this because I'll make a custom TextBox with a pencil.

The code in my resource dictionary (at the bottom of my question) gives me this result where I have add some cases. The First four are how the TextBox is for this moment. The last one is how I would like how the TextBox must look like. Note that this is temporary solved by set the text equal to a lot white spaces.

(Click on image to see in full screen)

Here you see the code for image above:

<TextBox Grid.Row="0" Margin="5" Text=""/>
<TextBox Grid.Row="1" Margin="5" Text="Plop"/>
<TextBox Grid.Row="2" Margin="5" Text="Ploperdeplop"/>
<TextBox Grid.Row="3" Margin="5" Text="Ploperdeploperdeploperdeplop"/>
<TextBox Grid.Row="4" Margin="5" Text="                                             ">

Note also that the first column in ControlTemplate below must be stretch over the hole Grid. If the ControlTemplate has a width of 150px and the second column (column with the pencil) is 50px, the first column (column with the TextBox) must have a width of 100px. If the grid is 300px and the second column is the same again (50px), the first column must be 250px width.

Here you've a part of my resource dictionary.

<Style TargetType="{x:Type TextBox}">
    <Setter Property="Foreground" Value="#FF333333"/>
    <Setter Property="Background" Value="White"/>
    <Setter Property="Padding" Value="5"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}">
                    <VisualStateManager.VisualStateGroups...>

                    <Grid x:Name="grdRoot" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="Stretch">

                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/> <!-- this column (index zero) must have a width of the width of the grid minus the second column (index one)-->
                            <ColumnDefinition Width="auto"/>
                        </Grid.ColumnDefinitions>

                        <TextBox x:Name="txbText" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBox}}, Path=Text}" Style="{x:Null}" BorderBrush="{x:Null}" 
                                 Grid.Column="0" Focusable="{TemplateBinding Focusable}" Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch"/>

                        <Button x:Name="btnPencil" Grid.Column="1"  Focusable="False" HorizontalAlignment="Left" Margin="3,0,3,0" Grid.Row="0"  VerticalAlignment="Top" Width="20">
                            <Button.Content>
                                <fa:ImageAwesome Icon="Pencil"/>
                            </Button.Content>
                        </Button>

                    </Grid>
                </Border>
                <ControlTemplate.Triggers...>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

(... in the code will mean that the section is collapsed)


Solution

  • grdRoot HorizontalAlignment is bound to TextBox HorizontalContentAlignment which is Left by default. Change HorizontalAlignment to Stretch to get desired effect

    <Grid x:Name="grdRoot" 
    HorizontalAlignment="Stretch"
    VerticalAlignment="Stretch">
    

    I would apply HorizontalContentAlignment later, for txbText element

    <TextBox x:Name="txbText" 
             HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" ...