WPF:如何在DataGrid中输入多行文本

10

大家好,我想在DataGridTextColumn中输入多行文本,我可以使用"enter"来输入多行字符。但是我想像Visual Studio资源管理器一样使用"shift+enter",以下是我使用"enter"键的代码。

<DataGridTextColumn Header="Value" Binding="{Binding Value}" Width="*">
  <DataGridTextColumn.ElementStyle>
      <Style TargetType="TextBlock">
         <Setter Property="TextWrapping" Value="Wrap" />
      </Style>
  </DataGridTextColumn.ElementStyle>
  <DataGridTextColumn.EditingElementStyle>
      <Style TargetType="TextBox">
        <Setter Property="TextWrapping" Value="Wrap" />
        <Setter Property="AcceptsReturn" Value="true" />
      </Style>
  </DataGridTextColumn.EditingElementStyle>

2个回答

13

一种实现方式是通过在样式中使用EventSetter处理TextBox上的KeyDown事件。我使用了你的示例,从样式中删除了AcceptsReturn设置,并在EditingElementStyle中添加了一个KeyDown处理程序,用于在光标所在位置添加换行符并将CaretIndex移到右侧。

以下是XAML代码:

<DataGridTextColumn Header="Value" Binding="{Binding Value}" Width="*">
    <DataGridTextColumn.ElementStyle>
        <Style TargetType="TextBlock">
            <Setter Property="TextWrapping" Value="Wrap" />
        </Style>
    </DataGridTextColumn.ElementStyle>
    <DataGridTextColumn.EditingElementStyle>
        <Style TargetType="TextBox">
            <Setter Property="TextWrapping" Value="Wrap" />
            <EventSetter Event="KeyDown" Handler="OnTextBoxKeyDown"/>
        </Style>
    </DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>

我在新的应用项目模板中编写了Window类的示例,这里是整个Window及其事件处理代码的C#代码。请注意,我将Handled设置为true,以防止事件在任何地方冒泡,因为我不希望在这种情况下将返回键处理为对编辑行的提交。我认为这实际上是这种方法的缺点之一。停止事件的冒泡/隧道是一个容易变成逻辑炸弹的事情,特别是当您的应用程序与用户输入有复杂的交互时。但如果您只有一个特殊情况,那么也不是太糟糕。所以像任何东西一样,随着使用这个部分的UI增长,请谨慎使用。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new List<Thing>
        {
            new Thing { Value = "Some text" },
            new Thing { Value = "More text" + Environment.NewLine + " second line" },
            new Thing { Value = "Another value" }
        };
    }

    private void OnTextBoxKeyDown(object sender, KeyEventArgs e)
    {
        if (Key.Return == e.Key && 
            0 < (ModifierKeys.Shift & e.KeyboardDevice.Modifiers))
        {
            var tb = (TextBox)sender;
            var caret = tb.CaretIndex;
            tb.Text = tb.Text.Insert(caret, Environment.NewLine);
            tb.CaretIndex = caret + 1;
            e.Handled = true;
        }
    }
}

public class Thing
{
    public string Value { get; set; }
}

另一个需要考虑的问题是,如果按下了插入键并且您处于覆盖输入模式,则可能希望行为不同。也许在这种情况下,下一个字符应该被新行替换。但是在Visual Studio 2010中的资源编辑器似乎不会对插入键作出反应(它也不会将文本显示为多行)。但我认为,根据此示例,您可以扩展它以使其与插入键配合得很好。希望这有所帮助-祝您好运!


嗨,timmyl,非常感谢你的回答。我已经采用了你的方法,尝试从文本框继承,并解决了我的问题,非常非常感谢。 - yafeya
继承很好,因为它让你干净地封装这个功能,但代价是从类型图中分支出来。另一种封装此事件处理的替代方法是使用附加属性添加行为,并利用属性更改处理程序来执行事件订阅/取消订阅操作,而无需在类型树中放置新节点(当然只要你需要就可以使其复杂)。酷的是,这个逻辑将可重用于不仅仅是 TextBox(如其他派生控件)。祝一切顺利。 - timmyl
是的,这种方式可以为我提供一些简单的扩展文本框逻辑的方法,非常好。 - yafeya

8

将TextWrapping设置为Wrap,AcceptsReturn设置为True...

<DataGridTextColumn.EditingElementStyle>
  <Style TargetType="TextBox">
    <Setter Property="TextWrapping" Value="Wrap" />
    <Setter Property="AcceptsReturn" Value="true" />
  </Style>
</DataGridTextColumn.EditingElementStyle>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接