WPF - 部分不可编辑的文本框

时间:2014-01-06 20:50:13

标签: c# wpf xaml

有没有办法在WPF的TextBox中添加固定的文本(TextBlock或Label)?这样;用户可以在控件中围绕它编写文本,但是不能删除或编辑它吗?

我正在寻找this question的倒数,即:

<TextBox>
    "Chunk #1: This part of text is editable"

    "Chunk #2: This piece is not editable"

    "Chunk #3: This text is editable"
</TextBox>

(注意:这些是用于详细说明的虚构卡盘,它是一个文本块的所有延续;它可能是带有换行符的多行。)

Chunk #2应相应移动的位置,用户可以修改Chunk #1#3

3 个答案:

答案 0 :(得分:4)

您可以在StackPanel中使用三个TextBox控件:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="1">
        <TextBox BorderThickness="1,1,0,1"/>
        <TextBox BorderThickness="0,1,0,1" 
                 Text="Chunk 2" IsReadOnly="True"
                 IsTabStop="False" />
        <TextBox BorderThickness="0,1,1,1"/>
    </StackPanel>
</Grid>

结果如下:

Resulting view

编辑:您应该能够使用Tab键从第一个TextBox跳转到最后一个TextBox。

答案 1 :(得分:1)

我可能认为屏蔽文本框是可能的解决方案。在wpftoolkit中查看有关如何使用它的codeplex上的this article

答案 2 :(得分:1)

如果您希望UI的行为类似于单个TextBox,则可能需要自定义TextBox控件。

在尝试各种活动后,我提出了以下解决方案:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WpfApplication1
{
    public class MyTextBox : TextBox
    {
        public MyTextBox()
        {
            TextChanged += new TextChangedEventHandler(MyTextBox_TextChanged);
            PreviewKeyDown += new KeyEventHandler(MyTextBox_PreviewKeyDown);
            PreviewTextInput += new TextCompositionEventHandler(MyTextBox_PreviewTextInput);
            DataObject.AddPastingHandler(this, new DataObjectPastingEventHandler(OnPaste));
        }

        private void OnPaste(object sender, DataObjectPastingEventArgs e)
        {
            if (!IsValidPositionForEdit())
            {
                e.CancelCommand(); // do not allow pasting 
            }
        }

        void MyTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            if (!IsValidPositionForEdit())
            {
                e.Handled = true;
            }
        }

        void MyTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (!IsValidPositionForEdit())
            {
                e.Handled = true;
            }
        }

        private bool IsValidPositionForEdit()
        {
            return SelectionStart <= this.before || SelectionStart >= this.before + ReadOnlyTextChunk.Length;
        }

        public static readonly DependencyProperty ReadOnlyTextChunkProperty = DependencyProperty.Register(
            "ReadOnlyTextChunk", typeof(string), typeof(MyTextBox), new PropertyMetadata(""));
        public string ReadOnlyTextChunk
        {
            get { return (string)GetValue(ReadOnlyTextChunkProperty); }
            set { SetValue(ReadOnlyTextChunkProperty, value); }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            Text = ReadOnlyTextChunk;
            this.before = 0;
            this.after = ReadOnlyTextChunk.Length;
        }

        void MyTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            foreach (TextChange ch in e.Changes)
            {
                if (ch.Offset <= this.before) // before text was modified
                {
                    this.before += ch.AddedLength - ch.RemovedLength;
                }
                else if (ch.Offset >= this.before + ReadOnlyTextChunk.Length) // after text was modified
                {
                    this.after += ch.AddedLength - ch.RemovedLength;
                }
            }
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.Key == Key.Tab) // jump to after part
            {
                if (SelectionStart <= this.before)
                {
                    SelectionStart = this.before + ReadOnlyTextChunk.Length;
                    e.Handled = true;
                }
                else
                {
                    base.OnKeyDown(e);
                }
            }
        }

        private int before; // length of before part
        private int after; // length of after part
    }
}

按如下方式使用:

<local:MyTextBox ReadOnlyTextChunk="Chunk2" TextWrapping="Wrap" Width="200" Height="50"/>

结果如下所示:

enter image description here