2

长时间的听众,第一次来电。我在 WinRT C#/XAML 中的 TextBox 遇到了一个奇怪的问题,希望有人可以帮助我。

基本上,我正在创建一个自定义控件,它基本上需要第二个 TextBox 作为第一个的副本,包括显示相同的 Text 和显示相同的 Selected Text。显然,对于 Text 要求,我只需响应第一个 TextBox 上的 TextChanged 事件并将第二个 TextBox 的 Text 设置为第一个 TextBox 的 Text,效果很好。

对于 Selected Text 要求,我从类似的解决方案开始,我的代码如下:

    void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
    {
        this.TextBox2.Select(this.TextBox1.SelectionStart, this.TextBox1.SelectionLength);
    }

最初与鼠标一起使用时,这似乎工作得很好:

使用鼠标的屏幕帽

但是我在使用Touch选择文本时遇到了问题。我在 TextBox 中双击以创建第一个“锚点”,就像在 Touch 中一样,然后拖动以开始选择;但在选择停止之前,我通常只能选择一个字符。TextBox 并没有完全失去焦点,但行为与此类似;选择锚点消失,除非我重新双击以开始新的选择,否则我无法继续选择任何内容。如果我删除了在 TextBox2 中选择文本的代码,那么 Touch 选择在 TextBox1 中的表现完美。

我一直在尝试解决此问题,但无法解决,我不确定是否可以使用 WinRT TextBoxes 获得所需的行为。有没有人有任何想法?或者也许是另一种方法来实现具有这种行为的两个文本框的解决方案?

非常感谢。

4

2 回答 2

0

我的也只是部分解决方案。

我做了一些调试并注意到该SelectionChanged事件在整个文本选择过程中被触发。换句话说,单指“滑动”会产生多个SelectionChanged事件。

正如您所发现的,TextBox.Select在文本选择手势期间调用会影响手势本身。Windows 似乎在程序化文本选择后停止了手势。

我的解决方法是尽可能延迟调用该TextBox.Select方法。这确实很好用,除了一个边缘情况。此方法失败的地方是以下场景:

用户开始选择手势,例如选择 x 个字符。用户无需将手指从屏幕上移开,就会暂停一两秒。然后用户尝试选择更多字符。

我的解决方案没有处理上一段中的最后一点。暂停后的触摸选择实际上并没有选择任何东西,因为我的代码将调用该TextBox.Select方法。

这是实际的代码。正如我上面提到的,在单个选择手势期间会触发多个选择更改事件。我的代码使用计时器和计数器仅在不再有任何挂起的触摸生成的选择更改事件时才进行编程选择。

int _selectCounter = 0;
const int SELECT_TIMER_LENGTH = 500;
async private void TextBox1_SelectionChanged(object sender, RoutedEventArgs e)
{
    // _selectCounter is the number of selection changed events that have fired.
    // If you are really paranoid, you will want to make sure that if
    // _selectCounter reaches MAX_INT, that you reset it to zero.
    int mySelectCount = ++_selectCounter;

    // start the timer and wait for it to finish
    await Task.Delay(SELECT_TIMER_LENGTH);

    // If equal (mySelectCount == _selectCounter),
    // this means that NO select change events have fired
    // during the delay call above. We only do the
    // programmatic selection when this is the case.
    // Feel free to adjust SELECT_TIMER_LENGTH to suit your needs.
    if (mySelectCount == _selectCounter)
    {
        this.TextBox2.Select(this.TextBox1.SelectionStart, this.TextBox1.SelectionLength);
    }
}
于 2013-04-11T14:10:31.190 回答
0

因此,这远不是一个答案,而是发现了一些可能会帮助您或其他人提出潜在解决方法的事情。如果这些是您已经看到和注意到的事情,我们深表歉意。

首先,问题本身不是对 TextBox2.Select() 的调用。例如,这对我来说很好

    private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
    {
        var start =  TextBox1.SelectionStart;
        var length = TextBox1.SelectionLength;
        TextBox2.Select(3, 5);
    }

不幸的是,使用startandlength与硬编码的 3 和 5 相比,即以下内容不起作用:

    private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
    {
        var start =  TextBox1.SelectionStart;
        var length = TextBox1.SelectionLength;
        TextBox2.Select(start, length);
    }

我还发现,如果我从头开始,我可以选择两个字符,但从头开始只能选择一个。这让我开始考虑调度调用来设置第二个选择:

    private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
    {
        var start =  TextBox1.SelectionStart;
        var length = TextBox1.SelectionLength;
        Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, 
            () => TextBox2.Select(start, length));
    }

现在我可以从前面选择 2,从后面选择 3,有时从后面选择 4。更进一步,可以通过非常快速的滑动选择多达六个或七个。

    private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
    {
        var start =  TextBox1.SelectionStart;
        var length = TextBox1.SelectionLength;
        Dispatcher.RunIdleAsync((v) => Highlight());
    }

    public void Highlight()
    {
        TextBox2.Select(TextBox1.SelectionStart, TextBox1.SelectionLength);
    }

似乎解决此问题的技巧是在 TextBox1 SelectionChanged 事件的任何痕迹完成之前不设置 TextBox2 。

这可能值得在Connect上注册。

于 2013-04-11T06:49:01.723 回答