Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Readonly textbox for WPF with visible cursor (.NET 3.5)

I need my textbox to be read-only. However, when I set the IsReadOnly to true, then the user can no longer interact with the textbox using the keyboard since the cursor no longer appears.

In .NET 4 there is a IsReadOnlyCaretVisible property, however, I am forced to use .NET 3.5.

Is there a good solution?

Thanks!

like image 413
VitalyB Avatar asked Sep 28 '11 08:09

VitalyB


People also ask

How do I make a TextBox ReadOnly in WPF?

To prevent users from modifying the contents of a TextBox control, set the IsReadOnly attribute to true.

How do I make a TextBox read only?

Set the TextBox control's ReadOnly property to true . With the property set to true , users can still scroll and highlight text in a text box without allowing changes.

Is read only in WPF?

For example, the Windows Presentation Foundation (WPF) framework implements the IsMouseOver property as read-only because its value should only be determined by mouse input. If IsMouseOver allowed other inputs, its value might become inconsistent with mouse input.


2 Answers

use both of these in your XAML

IsReadOnly="True"
IsReadOnlyCaretVisible="True" 

IsReadOnlyCaretVisible only works when the first property is being used.

like image 77
Stephen DuMont Avatar answered Oct 21 '22 22:10

Stephen DuMont


I've ended it doing it myself using an attached property, it does the following:

  • Disables all input and modification to the textbox using keyboard
  • Sets the context menu to have Copy only
  • Disables cut/paste commands
  • Disables modification using mouse selection & dragging
  • Changes the bacgrkound color of the textbox to notify it being read-only.

Usage:

<TextBox AttachedProperties:ReadOnlyModeWithCursor.IsModeEnabled="True">
     This textbox has some long text and it can't be edited.
</TextBox>

The class:

public static class ReadOnlyModeWithCursor
{
    public static readonly DependencyProperty IsModeEnabledProperty = DependencyProperty.RegisterAttached("IsModeEnabled",
                                                                                                          typeof(bool),
                                                                                                          typeof(ReadOnlyModeWithCursor),
                                                                                                          new FrameworkPropertyMetadata(OnModeEnabledChanged));

    private static ContextMenu _contextMenuWithCopyOnly = new ContextMenu();

    static ReadOnlyModeWithCursor()
    {
        _contextMenuWithCopyOnly.Items.Add(new MenuItem { Command = ApplicationCommands.Copy });
    }

    public static bool GetIsModeEnabled(TextBox textBox)
    {
        if (textBox == null)
        {
            throw new ArgumentNullException("textBox");
        }

        return (bool)textBox.GetValue(IsModeEnabledProperty);
    }

    public static void SetIsModeEnabled(TextBox textBox, bool value)
    {
        if (textBox == null)
        {
            throw new ArgumentNullException("textBox");
        }

        textBox.SetValue(IsModeEnabledProperty, value);
    }

    private static void NoCutting(object sender, ExecutedRoutedEventArgs e)
    {
        if (e.Command == ApplicationCommands.Cut)
        {
            e.Handled = true;
        }
    }

    private static void NoDragCopy(object sender, DataObjectCopyingEventArgs e)
    {
        if (e.IsDragDrop)
        {
            e.CancelCommand();
        }
    }

    private static void OnModeEnabledChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        var textBox = (TextBox)dependencyObject;
        var isEnabled = (bool)e.NewValue;

        if (isEnabled)
        {
            textBox.PreviewTextInput += textBox_PreviewTextInput;
            textBox.PreviewKeyDown += textBox_PreviewKeyDown;
            DataObject.AddPastingHandler(textBox, Pasting);
            DataObject.AddCopyingHandler(textBox, NoDragCopy);
            CommandManager.AddPreviewExecutedHandler(textBox, NoCutting);

            // Default context menu has cut & paste, we want only copy.
            textBox.ContextMenu = _contextMenuWithCopyOnly;

            // Remove if you want to set the style of readonly textboxes via styles
            textBox.Background = new SolidColorBrush(Color.FromRgb(240, 240, 240));
        }
        else
        {
            textBox.PreviewTextInput -= textBox_PreviewTextInput;
            textBox.PreviewKeyDown -= textBox_PreviewKeyDown;
            DataObject.RemovePastingHandler(textBox, Pasting);
            DataObject.RemoveCopyingHandler(textBox, NoDragCopy);
            CommandManager.RemovePreviewExecutedHandler(textBox, NoCutting);

            textBox.ClearValue(TextBox.ContextMenuProperty);
            textBox.ClearValue(TextBox.BackgroundProperty);
        }
    }

    private static void Pasting(object sender, DataObjectPastingEventArgs e)
    {
        e.CancelCommand();
    }

    private static void textBox_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        //pressing space doesn't raise PreviewTextInput, reasons here http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/446ec083-04c8-43f2-89dc-1e2521a31f6b?prof=required
        if (e.Key == Key.Space || e.Key == Key.Back || e.Key == Key.Delete)
        {
            e.Handled = true;
        }
    }

    private static void textBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        e.Handled = true;
    }
}
like image 3
VitalyB Avatar answered Oct 21 '22 22:10

VitalyB