更改文本框中的粘贴内容

22

我该如何动态地更改将要粘贴到文本框中的内容。

以下是我的事件订阅方式:

DataObject.AddPastingHandler (uiTextBox, TextBoxPaste);

以下是我定义事件处理程序的方式:

private void TextBoxPaste (object sender, DataObjectPastingEventArgs args)
{
    string clipboard = args.DataObject.GetData (typeof (string)) as string;

    Regex nonNumeric = new System.Text.RegularExpressions.Regex (@"\D");
    string result = nonNumeric.Replace (clipboard, String.Empty);

    // I can't just do "args.DataObject.SetData (result)" here.
}
4个回答

42

由于DataObject已被冻结,您不能调用args.DataObject.SetData("some data")。您可以做的是替换整个DataObject:

private void TextBoxPaste(object sender, DataObjectPastingEventArgs e) {
        string text = (String)e.DataObject.GetData(typeof(String));
        DataObject d = new DataObject();
        d.SetData(DataFormats.Text, text.Replace(Environment.NewLine, " "));
        e.DataObject = d;
 }

4
这绝对是一个更优雅的解决方案。 - Andrew dh

22
我能想到两种方法,但都不是很理想 :) 而且两种方法都包括取消粘贴命令。 第一种方式将是取消粘贴命令,然后计算如果粘贴 result 会得到什么文本。
private void TextBoxPaste(object sender, DataObjectPastingEventArgs args)
{
    string clipboard = args.DataObject.GetData(typeof(string)) as string;

    Regex nonNumeric = new System.Text.RegularExpressions.Regex(@"\D");
    string result = nonNumeric.Replace(clipboard, String.Empty);

    int start = uiTextBox.SelectionStart;
    int length = uiTextBox.SelectionLength;
    int caret = uiTextBox.CaretIndex;

    string text = uiTextBox.Text.Substring(0, start);
    text += uiTextBox.Text.Substring(start + length);

    string newText = text.Substring(0, uiTextBox.CaretIndex) + result;
    newText += text.Substring(caret);
    uiTextBox.Text = newText;
    uiTextBox.CaretIndex = caret + result.Length;

    args.CancelCommand();
}

另外一种方法是取消粘贴命令,更改剪贴板中的文本,然后重新执行粘贴。这也需要你区分真正的粘贴命令和手动调用的粘贴命令。可以像这样实现:

bool m_modifiedPaste = false;
private void TextBoxPaste(object sender, DataObjectPastingEventArgs args)
{
    if (m_modifiedPaste == false)
    {
        m_modifiedPaste = true;
        string clipboard = args.DataObject.GetData(typeof(string)) as string;

        Regex nonNumeric = new System.Text.RegularExpressions.Regex(@"\D");
        string result = nonNumeric.Replace(clipboard, String.Empty);

        args.CancelCommand();

        Clipboard.SetData(DataFormats.Text, result);
        ApplicationCommands.Paste.Execute(result, uiTextBox);
    }
    else
    {
        m_modifiedPaste = false;
    }
}

是的,我也在考虑你的第一种方法。然而第二种方法要糟糕得多,因为你正在修改剪贴板内容。无论哪种方式,这正是我所寻找的,谢谢! - Dave
感谢您的回答。我只想发布第一种方法的缩短版本(从9行到3行):int caret = uiTextBox.CaretIndex; uiTextBox.Text = uiTextBox.Text.Insert(uiTextBox.SelectionStart, result); uiTextBox.CaretIndex = caret + result.Length; - newman
发送者是发生粘贴事件的文本框,因此您无需明确引用特定的文本框,只需将发送者强制转换为“TextBox”(或其他内容)即可。 - Will
3
@Farawin的回答建议完全替换DataObject,比接受的答案更加优雅。 - Darren Gosbell

0

我经常使用VB.net,我测试过这个C#代码块,因为我太菜了,所以我用了一个转换器 :)

    string oClipboard;

    private void TextBox1_GotFocus(object sender, System.EventArgs e)
    {
        oClipboard = Clipboard.GetText();
        Clipboard.SetText("foo");
    }

    private void TextBox1_LostFocus(object sender, System.EventArgs e)
    {
        Clipboard.SetText(oClipboard);
    }

当控件获得焦点时,我将剪贴板设置为新文本。它会存储旧值。稍后,当控件失去焦点时,剪贴板会被设置回旧值。

0

这只是对@Fredrik代码的一些修改,因为我一直在尝试他的两种方法。

第一个只是一个缩短版本。

private void TextBox_Pasting(object sender, DataObjectPastingEventArgs e)
{
    string clipboard = e.DataObject.GetData(typeof(string)) as string;
    Regex nonNumeric = new System.Text.RegularExpressions.Regex (@"\D");
    string result = nonNumeric.Replace(clipboard, string.Empty);

    int caret = CaretIndex;
    Text = Text.Substring(0, SelectionStart) + result +
        Text.Substring(SelectionStart + SelectionLength);
    CaretIndex = caret + result.Length;

    e.CancelCommand();
}

另一个则是在保留剪贴板内容的情况下进行更新

private string oldClipboardContent { get; set; } = "";
private bool pasteModified { get; set; } = false;

private void TextBox_Pasting(object sender, DataObjectPastingEventArgs e)
{
    if (pasteModified)
    {
        pasteModified = false;
    }
    else
    {
        pasteModified = true;

        string text = (string)e.DataObject.GetData(typeof(string));
        oldClipboardContent = text;

        Regex nonNumeric = new System.Text.RegularExpressions.Regex (@"\D");
        text = nonNumeric.Replace(text, string.Empty);
        e.CancelCommand();

        Clipboard.SetData(DataFormats.Text, text);
        ApplicationCommands.Paste.Execute(text, this);

        Clipboard.SetData(DataFormats.Text, OldClipboardContent);
        oldClipboardContent = "";
    }
}

我在我的自定义TextBox控件中使用它们,这就是为什么我可以在不先写名称的情况下访问TextBox属性。


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