views:

2872

answers:

4

In Silverlight, How do I make a TextBox with IsReadOnly="True" not become grayed out. The gray effect looks horrible with my app and I would like to disable it, or change its appearance/color.

+5  A: 

Nothing seems to work in the xaml (as usual), so the best solution I've come up with is make a textbox readonly myself without the IsReadOnly property.

public class ReadOnlyTextBox : TextBox
{
    protected override void OnKeyDown(KeyEventArgs e)
    {
        e.Handled = true;
        base.OnKeyDown(e);
    }
}
Struan
This helped with an issue I had trying to make a readonly combobox. In my case I also had to handle the OnKeyUp with the same code to stop a KeyUp event handler being fired.
NeilE
+1 for 'as usual'
Simon_Weaver
Another +1 for 'as usual'. One problem with this approach is you get the border and caret when you click on the textbox.
Chris S
Thanks Struan - I ended up going this route. I modified your code to set e.Handled = true only if the Ctrl key is not pressed, and if the key is not an arrow key or tab key. That way people can still tab through the control, and can still hit Ctrl+C to copy.
Richard Beier
+6  A: 

There are a couple of options in Silverlight 2, the simplest would be to use a TextBlock since that's only ever readonly.

If you need a TextBox then what you need to do is give it a different style that doesn't do the grey affect.

To do this open up blend. right click on your TextBox and select Edit Control Parts (Template) -> Edit a Copy... Call the new style whatever you want.

You then want to edit this new style and delete the border called "ReadOnlyVisualElement" and delete the storyboard that alters the opacity property of that border.

Hope this helps.

Added Style XAML

    <Style x:Key="ReadOnlyStyle" 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>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
     <GradientStop Color="#FFA3AEB9" Offset="0"/>
     <GradientStop Color="#FF8399A9" Offset="0.375"/>
     <GradientStop Color="#FF718597" Offset="0.375"/>
     <GradientStop Color="#FF617584" Offset="1"/>
    </LinearGradientBrush>
   </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>
          <ColorAnimationUsingKeyFrames Storyboard.TargetName="MouseOverBorder" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)">
           <SplineColorKeyFrame KeyTime="0" Value="#FF99C1E2"/>
          </ColorAnimationUsingKeyFrames>
         </Storyboard>
        </vsm:VisualState>
        <vsm:VisualState x:Name="Disabled">
         <Storyboard>
          <DoubleAnimationUsingKeyFrames Storyboard.TargetName="DisabledVisualElement" Storyboard.TargetProperty="Opacity">
           <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
          </DoubleAnimationUsingKeyFrames>
         </Storyboard>
        </vsm:VisualState>
        <vsm:VisualState x:Name="ReadOnly">
         <Storyboard>
         </Storyboard>
        </vsm:VisualState>
       </vsm:VisualStateGroup>
       <vsm:VisualStateGroup x:Name="FocusStates">
        <vsm:VisualState x:Name="Focused">
         <Storyboard>
          <DoubleAnimationUsingKeyFrames Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity">
           <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
          </DoubleAnimationUsingKeyFrames>
         </Storyboard>
        </vsm:VisualState>
        <vsm:VisualState x:Name="Unfocused">
         <Storyboard>
          <DoubleAnimationUsingKeyFrames Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity">
           <SplineDoubleKeyFrame KeyTime="0" Value="0"/>
          </DoubleAnimationUsingKeyFrames>
         </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>
             <System:Boolean>True</System:Boolean>
            </DiscreteObjectKeyFrame.Value>
           </DiscreteObjectKeyFrame>
          </ObjectAnimationUsingKeyFrames>
         </Storyboard>
        </vsm:VisualState>
       </vsm:VisualStateGroup>
      </vsm:VisualStateManager.VisualStateGroups>
      <Border x:Name="Border" Opacity="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1">
       <Grid>
        <Border x:Name="MouseOverBorder" BorderBrush="Transparent" BorderThickness="1">
         <ScrollViewer x:Name="ContentElement" BorderThickness="0" IsTabStop="False" Padding="{TemplateBinding Padding}"/>
        </Border>
       </Grid>
      </Border>
      <Border x:Name="DisabledVisualElement" IsHitTestVisible="False" Opacity="0" Background="#A5F7F7F7" BorderBrush="#A5F7F7F7" BorderThickness="{TemplateBinding BorderThickness}"/>
      <Border x:Name="FocusVisualElement" Margin="1" IsHitTestVisible="False" Opacity="0" BorderBrush="#FF6DBDD1" BorderThickness="{TemplateBinding BorderThickness}"/>
      <Border x:Name="ValidationErrorElement" Visibility="Collapsed" BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1">
       <ToolTipService.ToolTip>
        <ToolTip x:Name="validationTooltip" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{StaticResource ValidationToolTipTemplate}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}">
         <ToolTip.Triggers>
          <EventTrigger RoutedEvent="Canvas.Loaded">
           <BeginStoryboard>
            <Storyboard>
             <ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsHitTestVisible">
              <DiscreteObjectKeyFrame KeyTime="0">
               <DiscreteObjectKeyFrame.Value>
                <System:Boolean>true</System:Boolean>
               </DiscreteObjectKeyFrame.Value>
              </DiscreteObjectKeyFrame>
             </ObjectAnimationUsingKeyFrames>
            </Storyboard>
           </BeginStoryboard>
          </EventTrigger>
         </ToolTip.Triggers>
        </ToolTip>
       </ToolTipService.ToolTip>
       <Grid Height="12" HorizontalAlignment="Right" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12" Background="Transparent">
        <Path Fill="#FFDC000C" Margin="1,3,0,0" Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z"/>
        <Path Fill="#ffffff" Margin="1,3,0,0" Data="M 0,0 L2,0 L 8,6 L8,8"/>
       </Grid>
      </Border>
     </Grid>
    </ControlTemplate>
   </Setter.Value>
  </Setter>
 </Style>

I would get the preview of Blend, coding the above by hand would be a large amount of unnecessary work.

Graeme Bradbury
I am not using a TextBlock because I still want to be able to copy Text from the textbox and paste it somewhere else. I don't have Blend (I am using Visual Web Developer 2008 Express) so I can't try your second suggestion.
Struan
+1 for YOU GOTTA BE KIDDING ME!
Simon_Weaver
A: 

Here's an enhanced version of @Struan's answer.

I assume you want to allow Select all and Copy if you're wanting a read only textbox. You need to handle keypresses such as Ctrl+A and Ctrl+C.

Disclaimer: this is not a fully complete set of keys - you may need to add more, but this will allow for copy at least.

public class ReadOnlyTextBox : TextBox
{
    protected override void OnKeyDown(KeyEventArgs e)
    {
        if (e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up || e.Key == Key.Down)
        {
            base.OnKeyDown(e);
            return;
        }

        if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control ||
            (Keyboard.Modifiers & ModifierKeys.Apple) == ModifierKeys.Apple)
        {
            if (e.Key == Key.A || e.Key == Key.C)
            {
                // allow select all and copy!
                base.OnKeyDown(e);
                return;
            }
        }

        e.Handled = true;
        base.OnKeyDown(e);
    }
}

And here's a simple Style I'm using that indicates to the user that the item is selectable, but is smaller than a typical textbox.

<Style TargetType="my:ReadOnlyTextBox">
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="Padding" Value="3,0,3,0"/>
    <Setter Property="Background" Value="Transparent"/>
</Style>
Simon_Weaver
+1  A: 

If you just want an equivalent of a block of text in HTML, that can be selected (which for some reason even Silverlight 4 is missing) you can shorten Graeme's answer slightly:

<Style x:Key="ReadOnlyStyle" TargetType="TextBox">
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="Background" Value="#FFFFFFFF"/>
    <Setter Property="Padding" Value="2"/>
    <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"/>
                            <vsm:VisualState x:Name="Disabled" />
                            <vsm:VisualState x:Name="ReadOnly"/>
                        </vsm:VisualStateGroup>
                        <vsm:VisualStateGroup x:Name="FocusStates">
                            <vsm:VisualState x:Name="Focused">
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity">
                                        <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
                                    </DoubleAnimationUsingKeyFrames>
                                </Storyboard>
                            </vsm:VisualState>
                            <vsm:VisualState x:Name="Unfocused">
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity">
                                        <SplineDoubleKeyFrame KeyTime="0" Value="0"/>
                                    </DoubleAnimationUsingKeyFrames>
                                </Storyboard>
                            </vsm:VisualState>
                        </vsm:VisualStateGroup>
                    </vsm:VisualStateManager.VisualStateGroups>
                    <Border x:Name="Border" Opacity="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1">
                        <Grid>
                            <Border x:Name="MouseOverBorder" BorderBrush="Transparent" BorderThickness="1">
                                <ScrollViewer x:Name="ContentElement" BorderThickness="0" IsTabStop="False" Padding="{TemplateBinding Padding}"/>
                            </Border>
                        </Grid>
                    </Border>
                    <Border x:Name="DisabledVisualElement" IsHitTestVisible="False" Opacity="0" Background="#A5F7F7F7" BorderBrush="#A5F7F7F7" BorderThickness="{TemplateBinding BorderThickness}"/>
                    <Border x:Name="FocusVisualElement" Margin="1" IsHitTestVisible="False" Opacity="0" BorderBrush="#FF6DBDD1" BorderThickness="{TemplateBinding BorderThickness}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

You may even be able to remove the disabled states.

Chris S