Yuchen
Yuchen

Reputation: 33116

How to make a TextBox same width as parent view

I have tried both with width="auto" and HorizontalAlignment="Stretch", but both of them do not give me the result I want. It seems that the width of the text box is always based on the size of the header of the text box. Why?

This is the XMAL:

<ListView Width="auto">
    <TextBox Width="auto"
             Header="Please Enter Email Address"/>
    <TextBox HorizontalAlignment="Stretch"
             Header="Please Enter Email address"/>
</ListView>

This is the output:

enter image description here

This is what I am looking for:

enter image description here

I get the above screenshot by setting the width to a fixed values. But I want to find a way to let the text box automatically resize base on the parent view (for example a ListView in this case).


Edit:

Based on Alan's answer, it works great in portrait mode. But still not taking the full width in landscape.

<ListView x:Name="lv" Width="auto">
    <TextBox Width="{Binding ElementName=lv, Path=ActualWidth}"
     Header="Please Enter Email Address"/>
    <TextBox Width="{Binding ElementName=lv, Path=ActualWidth}"
     Header="Please Enter Email address"/>
</ListView>

Left Image: portrait mode; Right Image: landscape mode.


Edit 2:

I notice that both @Alan's answer and @Jogy's answer are both okay if the parent view is <Page>. However, if the parent view is <ContentDialog>, neither of them works. As a matter of fact, if the parent view is <Page>, simple using this <TextBox Width="auto"/> will works as expected. There may be obvious thing about Windows Phone I don't understand.

Upvotes: 1

Views: 705

Answers (2)

Alan Yao - MSFT
Alan Yao - MSFT

Reputation: 3304

Bind the Width to its parent control's ActualWidth like below:

<ListView x:Name="lv" Width="auto">
    <TextBox Width="{Binding ElementName=lv, Path=ActualWidth}"
     Header="Please Enter Email Address"/>
    <TextBox Width="{Binding ElementName=lv, Path=ActualWidth}"
     Header="Please Enter Email address"/>
</ListView>

[Update]

Because the actualwidth property will not be updated on orientation change. Let's try a different way:

<Page.Resources>
    <Style TargetType="ListViewItem" x:Key="StretchedListViewItem">
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</Page.Resources>

<Grid>
    <ListView ItemContainerStyle="{StaticResource StretchedListViewItem}" x:Name="lv" Width="auto">
        <TextBox Width="auto"
         Header="Please Enter Email Address"/>
        <TextBox Width="auto"
         Header="Please Enter Email address"/>
    </ListView>

</Grid>

[Update 2]

[Why]

This is a very interesting topic, it's about how to override the Control's default style.

Let me explain why we cannot make our previous solution for Page to work in ContentDialog. It's because the ContentDialog has the following default style in generic.xaml(you can find in the windows phone 8.1 sdk):

<!-- Default style for Windows.UI.Xaml.Controls.ContentDialog -->
  <!-- NOTE: Because this type didn't ship in WinBlue, we use a prefix to trick the
         XAML parser to not only consider its own type table when parsing, even though
         this exists in a jupiter-owned namespace. -->
  <Style TargetType="controls:ContentDialog">
    <Setter Property="Background" Value="{ThemeResource ContentDialogBackgroundThemeBrush}" />
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="controls:ContentDialog">
          <Border x:Name="Container">
            <VisualStateManager.VisualStateGroups>
              <VisualStateGroup x:Name="Orientation">
                <VisualState x:Name="Portrait" />
                <VisualState x:Name="Landscape">
                  <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="ContentPanel" EnableDependentAnimation="True">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ContentDialogContentLandscapeWidth}" />
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="HorizontalAlignment" Storyboard.TargetName="ContentPanel">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="Left" />
                    </ObjectAnimationUsingKeyFrames>
                  </Storyboard>
                </VisualState>
              </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>

            <Grid x:Name="LayoutRoot">
              <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
              </Grid.RowDefinitions>
              <Border x:Name="BackgroundElement" 
                      Background="{TemplateBinding Background}"
                      FlowDirection="LeftToRight">
                <Border FlowDirection="{TemplateBinding FlowDirection}">
                  <Grid x:Name="ContentPanel">
                    <Grid.RowDefinitions>
                      <RowDefinition Height="Auto" MinHeight="{ThemeResource ContentDialogTitleMinHeight}" />
                      <RowDefinition Height="Auto" MinHeight="{ThemeResource ContentDialogContentMinHeight}" />
                      <RowDefinition Height="Auto" MinHeight="{ThemeResource ContentDialogButtonsMinHeight}" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition Width="*" />
                      <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <ContentControl x:Name="Title"
                                    Margin="{ThemeResource ContentDialogTitleMargin}"
                                    Content="{TemplateBinding Title}"
                                    ContentTemplate="{TemplateBinding TitleTemplate}"
                                    FontSize="{StaticResource TextStyleExtraLargeFontSize}"
                                    FontFamily="{ThemeResource PhoneFontFamilyNormal}"
                                    FontWeight="SemiBold"
                                    Grid.ColumnSpan="2" />
                    <ContentPresenter x:Name="Content"
                                      ContentTemplate="{TemplateBinding ContentTemplate}"
                                      Content="{TemplateBinding Content}"
                                      FontSize="{StaticResource TextStyleLargeFontSize}"
                                      FontFamily="{ThemeResource PhoneFontFamilyNormal}"
                                      Margin="{ThemeResource ContentDialogContentMargin}"
                                      Grid.Row="1"
                                      Grid.ColumnSpan="2" />
                    <Border x:Name="Button1Host" Padding="{ThemeResource ContentDialogButton1HostPadding}" Grid.Row="2" />
                    <Border x:Name="Button2Host" Padding="{ThemeResource ContentDialogButton2HostPadding}" Grid.Row="2" Grid.Column="1" />
                  </Grid>
                </Border>
              </Border>
            </Grid >
          </Border>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>

The interest things which cause the difference from Page:

  1. the margins of title and content were set to(suggest to keep it):

    ContentDialogTitleMargin 19,33.5,19,0

    ContentDialogContentMargin 19,16.5,19,0

2: the width in Landscape mode was set to:

...
<x:Double x:Key="ContentDialogContentLandscapeWidth">400</x:Double>
...
  1. the HorizontalAlignment in Landscape mode was set to: Value="Left"

[Solution]

In addition to the steps I provided before(just need to change the Page.Resources to ContentDialog.Resources), we need to do the following steps

To solve the issue, add the following into your App.xaml:

   <Application.Resources>
        <Style x:Key="FullScreenContentDialogStyle" TargetType="ContentDialog">
            <Setter Property="Background" Value="{ThemeResource ContentDialogBackgroundThemeBrush}" />
            <Setter Property="Template">

                <Setter.Value>
                    <ControlTemplate TargetType="ContentDialog">
                        <Border x:Name="Container">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="Orientation">
                                    <VisualState x:Name="Portrait" />
                                    <VisualState x:Name="Landscape">
                                        <Storyboard>
                                            <!--<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="ContentPanel" EnableDependentAnimation="True">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Auto" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="HorizontalAlignment" Storyboard.TargetName="ContentPanel">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Stretch" />
                                            </ObjectAnimationUsingKeyFrames>-->
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>

                            <Grid x:Name="LayoutRoot">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto" />
                                </Grid.RowDefinitions>
                                <Border x:Name="BackgroundElement"
                                        Background="{TemplateBinding Background}"
                                        FlowDirection="LeftToRight">
                                    <Border FlowDirection="{TemplateBinding FlowDirection}">
                                        <Grid x:Name="ContentPanel">
                                            <Grid.RowDefinitions>
                                                <RowDefinition Height="Auto" MinHeight="{ThemeResource ContentDialogTitleMinHeight}" />
                                                <RowDefinition Height="Auto" MinHeight="{ThemeResource ContentDialogContentMinHeight}" />
                                                <RowDefinition Height="Auto" MinHeight="{ThemeResource ContentDialogButtonsMinHeight}" />
                                            </Grid.RowDefinitions>
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="*" />
                                                <ColumnDefinition Width="*" />
                                            </Grid.ColumnDefinitions>

                                            <ContentControl x:Name="Title"
                                                            Margin="{ThemeResource ContentDialogTitleMargin}"
                                                            Content="{TemplateBinding Title}"
                                                            ContentTemplate="{TemplateBinding TitleTemplate}"
                                                            FontSize="{StaticResource TextStyleExtraLargeFontSize}"
                                                            FontFamily="{ThemeResource PhoneFontFamilyNormal}"
                                                            FontWeight="SemiBold"
                                                            Grid.ColumnSpan="2" />


                                            <ContentPresenter x:Name="Content"
                                                              ContentTemplate="{TemplateBinding ContentTemplate}"
                                                              Content="{TemplateBinding Content}"
                                                              FontSize="{StaticResource TextStyleLargeFontSize}"
                                                              FontFamily="{ThemeResource PhoneFontFamilyNormal}"
                                                              Margin="{ThemeResource ContentDialogContentMargin}"
                                                              Grid.Row="1"
                                                              Grid.ColumnSpan="2" />
                                            <Border x:Name="Button1Host" Padding="{ThemeResource ContentDialogButton1HostPadding}" Grid.Row="2" />
                                            <Border x:Name="Button2Host" Padding="{ThemeResource ContentDialogButton2HostPadding}" Grid.Row="2" Grid.Column="1" />
                                        </Grid>
                                    </Border>
                                </Border>
                            </Grid >
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>


    </Application.Resources>

And here is the CustomContentDialog.xaml:

<ContentDialog
    x:Class="CSharpWP81.CustomContentDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:CSharpWP81"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="DIALOG TITLE"
    PrimaryButtonText="sign in"  
    SecondaryButtonText="cancel"
    PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
    SecondaryButtonClick="ContentDialog_SecondaryButtonClick"
    HorizontalAlignment="Stretch"
    VerticalAlignment="Stretch"
    VerticalContentAlignment="Stretch"
    HorizontalContentAlignment="Stretch"
    Style="{StaticResource FullScreenContentDialogStyle}">

    <ContentDialog.Resources>
        <Style TargetType="ListViewItem" x:Key="StretchedListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        </Style>
    </ContentDialog.Resources>


    <StackPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
        <ListView ItemContainerStyle="{StaticResource StretchedListViewItem}" x:Name="lv">
            <TextBox Width="auto"
         Header="Please Enter Email Address"/>
            <TextBox Width="auto"
         Header="Please Enter Email address"/>
        </ListView>

    </StackPanel>

</ContentDialog>

Upvotes: 1

Jogy
Jogy

Reputation: 2475

Instead of binding the Width, try to add this below the opening ListView tag:

    <ListView.ItemContainerStyle>
      <Style TargetType="ListViewItem">
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
      </Style>
    </ListView.ItemContainerStyle>

[UPDATE]

Apparently there is a problem with ContentDialog and landscape mode. Check this thread: https://social.msdn.microsoft.com/Forums/en-US/6c8ad10c-3b27-4991-9a5a-8cb15b338709/contentdialog-behavior-in-landscape-orientation?forum=wpdevelop

If you set the background color of the List to Red, you will see that the whole List is cropped when the phone is in Landscape mode.

Upvotes: 2

Related Questions