locked
WP8: How to create a fully customizable and horizontally scrollable XAML TextBox RRS feed

  • General discussion

  • Hi,

    I was researching a long time about how to make the text in a TextBox scrollable like the TextBoxes the System uses because the property "HorizontalScrollBarVisibility="Visible"" does not work. Now, I can present a solution, have fun with it^^

    <TextBox VerticalScrollBarVisibility="Disabled" Style="{StaticResource BoxStyle}" UseOptimizedManipulationRouting="False" Language="en-US" x:Name="Box" Background="#FFBDDBFF" TextWrapping="NoWrap" Text=""  TextAlignment="Left">
       <TextBox.InputScope>
           <InputScope>
               <InputScopeName  NameValue="Search" />
           </InputScope>
       </TextBox.InputScope>
    </TextBox>

    TextWrapping and VerticalScrollBarVisibility must be disabled.

    And now the TextBox style:

    <phone:PhoneApplicationPage.Resources>
            
            <Style x:Key="BoxStyle" TargetType="TextBox">
                <Setter Property="BorderThickness" Value="1"/>
                <Setter Property="Background" Value="#FFFFFFFF"/>
                <Setter Property="Foreground" Value="#FF000000"/>
                <Setter Property="Padding" Value="2"/>
                <Setter Property="BorderBrush">
                    <Setter.Value>
                        <SolidColorBrush Color="Transparent" Opacity="1"/>
                    </Setter.Value>
                </Setter>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="TextBox">
                            <Grid x:Name="RootElement">
                                <vsm:VisualStateManager.VisualStateGroups>
                                    <vsm:VisualStateGroup x:Name="CommonStates">
                                        <vsm:VisualState x:Name="Normal"/>
                                        <vsm:VisualState x:Name="MouseOver">
                                            <Storyboard>
                                                <ColorAnimation Storyboard.TargetName="MouseOverBorder" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="#FF99C1E2" Duration="0"/>
                                            </Storyboard>
                                        </vsm:VisualState>
                                        <vsm:VisualState x:Name="Disabled">
                                            <Storyboard>
                                                <DoubleAnimation Storyboard.TargetName="DisabledVisualElement" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
                                            </Storyboard>
                                        </vsm:VisualState>
                                        <vsm:VisualState x:Name="ReadOnly">
                                            <Storyboard>
                                                <DoubleAnimation Storyboard.TargetName="ReadOnlyVisualElement" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
                                            </Storyboard>
                                        </vsm:VisualState>
                                    </vsm:VisualStateGroup>
                                    <vsm:VisualStateGroup x:Name="FocusStates">
                                        <vsm:VisualState x:Name="Focused">
                                            <Storyboard>
                                                <DoubleAnimation Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.5"/>
                                                <DoubleAnimation Storyboard.TargetName="UnFocusVisualElement" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.5"/>
                                            </Storyboard>
                                        </vsm:VisualState>
                                        <vsm:VisualState x:Name="Unfocused">
                                            <Storyboard>
                                                <DoubleAnimation Storyboard.TargetName="FocusVisualElement"  Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.5"/>
                                                
                                                <DoubleAnimation Storyboard.TargetName="UnFocusVisualElement" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.5"/>
                                            </Storyboard>
                                        </vsm:VisualState>
                                    </vsm:VisualStateGroup>
                                    <vsm:VisualStateGroup x:Name="ValidationStates">
                                        <vsm:VisualState x:Name="Valid"/>
                                        <vsm:VisualState x:Name="InvalidUnfocused">
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
                                                    <DiscreteObjectKeyFrame KeyTime="0">
                                                        <DiscreteObjectKeyFrame.Value>
                                                            <Visibility>Visible</Visibility>
                                                        </DiscreteObjectKeyFrame.Value>
                                                    </DiscreteObjectKeyFrame>
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </vsm:VisualState>
                                        <vsm:VisualState x:Name="InvalidFocused">
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
                                                    <DiscreteObjectKeyFrame KeyTime="0">
                                                        <DiscreteObjectKeyFrame.Value>
                                                            <Visibility>Visible</Visibility>
                                                        </DiscreteObjectKeyFrame.Value>
                                                    </DiscreteObjectKeyFrame>
                                                </ObjectAnimationUsingKeyFrames>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsOpen">
                                                    <DiscreteObjectKeyFrame KeyTime="0">
                                                        <DiscreteObjectKeyFrame.Value>
                                                            <sys:Boolean>True</sys:Boolean>
                                                        </DiscreteObjectKeyFrame.Value>
                                                    </DiscreteObjectKeyFrame>
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </vsm:VisualState>
                                    </vsm:VisualStateGroup>
                                </vsm:VisualStateManager.VisualStateGroups>
                                <Border x:Name="Border" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1" Opacity="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
                                    <Grid>
                                        <Border x:Name="ReadOnlyVisualElement" Opacity="0" Background="#5EC9C9C9"/>
                                        <Border x:Name="MouseOverBorder" BorderThickness="1" BorderBrush="Transparent">
                                            <ScrollViewer x:Name="ContentElement" HorizontalScrollBarVisibility="Visible" Padding="5,0,50,2" BorderThickness="0" IsTabStop="False"/>
                                        </Border>
                                    </Grid>
                                </Border>
                                <Border x:Name="DisabledVisualElement" Background="#A5F7F7F7" BorderBrush="#A5F7F7F7" BorderThickness="{TemplateBinding BorderThickness}" Opacity="0" IsHitTestVisible="False"/>
                                <Border x:Name="FocusVisualElement"  BorderThickness="4" Margin="-3" Opacity="0" IsHitTestVisible="False">
    
                                    <Border.BorderBrush>
                                        <SolidColorBrush Color="{StaticResource PhoneAccentColor}" Opacity="1"/>
                                    </Border.BorderBrush>
                                </Border>
                                <Border x:Name="UnFocusVisualElement"  BorderThickness="4" Margin="-3" Opacity="1" IsHitTestVisible="False">
    
                                    <Border.BorderBrush>
                                        <SolidColorBrush Color="{StaticResource PhoneAccentColor}" Opacity="0.35"/>
                                    </Border.BorderBrush>
                                </Border>
                                <Border x:Name="ValidationErrorElement" BorderThickness="1" CornerRadius="1" BorderBrush="#FFDB000C" Visibility="Collapsed">
                                    <ToolTipService.ToolTip>
                                        <ToolTip x:Name="validationTooltip" Placement="Right" 
                             PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}"
                             DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
                                            <ToolTip.Triggers>
                                                <EventTrigger RoutedEvent="Canvas.Loaded">
                                                    <EventTrigger.Actions>
                                                        <BeginStoryboard>
                                                            <Storyboard>
                                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsHitTestVisible">
                                                                    <DiscreteObjectKeyFrame KeyTime="0">
                                                                        <DiscreteObjectKeyFrame.Value>
                                                                            <sys:Boolean>true</sys:Boolean>
                                                                        </DiscreteObjectKeyFrame.Value>
                                                                    </DiscreteObjectKeyFrame>
                                                                </ObjectAnimationUsingKeyFrames>
                                                            </Storyboard>
                                                        </BeginStoryboard>
                                                    </EventTrigger.Actions>
                                                </EventTrigger>
                                            </ToolTip.Triggers>
                                        </ToolTip>
                                    </ToolTipService.ToolTip>
                                    <Grid Width="12" Height="12" HorizontalAlignment="Right" Margin="1,-4,-4,0" VerticalAlignment="Top" Background="Transparent">
                                        <Path Margin="1,3,0,0" Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C"/>
                                        <Path Margin="1,3,0,0" Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff"/>
                                    </Grid>
                                </Border>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
    
    </phone:PhoneApplicationPage.Resources>

    The "ContentElement" ScrollViewer is the place where the text input is displayed. With the Padding property, we can precisely position the entered text and create some space to the right border e.g. to place an x-button in it which could delete all the text in the TextBox. As you can see, we can add animations to the visual states too. 

    Do not forget to add these namespaces to the xaml page:

    xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"

    Now the text within the Textbox is horizontally scrollable.

    Wednesday, February 26, 2014 5:12 PM

All replies

  • Thank you!

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Thursday, February 27, 2014 1:02 PM
    Moderator