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

前端 未结 3 1571
北荒
北荒 2021-01-17 10:17

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

相关标签:
3条回答
  • 2021-01-17 10:53

    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;
        }
    }
    
    0 讨论(0)
  • 2021-01-17 10:57

    use both of these in your XAML

    IsReadOnly="True"
    IsReadOnlyCaretVisible="True" 
    

    IsReadOnlyCaretVisible only works when the first property is being used.

    0 讨论(0)
  • 2021-01-17 11:06

    You could try extracting the templates from .NET 4.0, and use them in your .NET 3.5 application.

    Hopefully you can use it without too many adjustments.

    0 讨论(0)
提交回复
热议问题