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, o
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);
}
}
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.
I wanted to reduce the style to bare bone, and tested this with silverlight 4.0:
<Style x:Key="ReadOnlyStyle" TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<TextBlock Text="{TemplateBinding Text}" TextAlignment="{TemplateBinding TextAlignment}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
It is almost a cheat, like saying:Hey silverligh, this textbox is a textblock!
You should eventually add something in the TextBlock tag, to better reflect other TextBox properties.
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>
Until the definition/behavior/appearance of a button changes, another more elegant solution is to simply change your TextBox to a Button. Change the 'Text' property to a 'Content' property to set the text displayed, remove the 'IsReadOnly' setting and you will have the effect you desire, I believe (a flat text-box-like control that supports text and all the border, background, foreground properties of a TextBox without the opacity change [graying-out] and the hassle of defining a new style).
When a user attempts to interact with this control, it's features change on the click event, but without an event handler associated with the button, there will be no impact to your interface. In fact, I think the default button behavior makes the effect appear kind of "cool".
I found @Simon_Weaver's solution the easiest to implement. The only change I made was to check for Key.Tab along with left/right/up/down so that I could tab out of the field. I created the class ReadOnlyTextBox and copied the code above. Then I added the check for Key.Tab and compiled. Next I changed my Xaml tag from
<TextBox ... IsEnabled="False" />
to
<MyNameSpace:ReadOnlyTextBox ... Background="LightGray" />
(removing the IsEnabled reference and adding the background color). It looks and works exactly as I expected.
Thanks Simon.