【问题标题】:C# Timer throwing an error during loop?C# Timer 在循环期间抛出错误?
【发布时间】:2014-12-11 05:57:14
【问题描述】:

这里的代码显示了我用来向用户打印文本输出的“打字机效果”。基本上它打印出带有打字机效果的文本。但它会抛出一个错误:

“索引和长度必须引用字符串中的某个位置”

这是我的代码:

private void TypeWriterTimer_Tick(object sender, EventArgs e)
        {
            const int MaxRetries = 5;

            for (int i = 0; i < MaxRetries; i++)
            {
                try
                {
                    Action final = () => dialogBox.Text = typeWriterReply.Substring(0, TypeWriter_index_Num) + "_";//Substring is a part of Type_Text String that we declared at the start
                    dialogBox.Dispatcher.Invoke(final, null);

                    TypeWriter_index_Num++;//Doing a post fix
                    if (TypeWriter_index_Num == typeWriterReply.Length +1)//An if statment with a condition of course
                    {
                        TypeWriter_index_Num = 0;
                        TypeWriterTimer.Stop();
                    }
                    dialogBox.Focus();
                    dialogBox.CaretIndex = dialogBox.Text.Length;
                    dialogBox.ScrollToEnd();

                    break;
                }
                catch (Exception tw)
                {
                    MessageBoxResult result = MessageBox.Show("Type Writer ERROR");
                    Console.WriteLine(tw.ToString());
                }
            }
        }

TypeWriterReply 是正在打印的文本,所有变量都是全局声明的。

为什么会抛出这个错误?

【问题讨论】:

  • 表达式“TypeWriter_index_Num == typeWriterReply.Length +1”当然是一个错误,如果不是你要问的那个。字符串中唯一有效的索引是 小于 typeWriterReply.Length 的值。你阻止一个角色太晚了。
  • 请不要这样编码:catch (Exception tw)。像这样捕获所有异常是一种不好的做法。

标签: c# wpf loops timer error-handling


【解决方案1】:

使用 C# 的 async / await awesomeness 实现更短、更简单、更漂亮的方式:

<Window x:Class="WpfApplication5.TypeWriter"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TypeWriter" Height="300" Width="300">
    <TextBox x:Name="TextBox"/>
</Window>

代码背后:

public partial class TypeWriter : Window
{
    public TypeWriter()
    {
        InitializeComponent();

        TypeText();
    }

    public async void TypeText()
    {
        await Task.Delay(1000);

        var text = "Hello, World! I'm simulating typing into this TextBox.";

        foreach (var character in text)
        {
            this.TextBox.Text += character;

            await Task.Delay(100);
        }
    }
}

【讨论】:

  • 这太棒了!谢谢 但是如果我第二次运行该方法,它会附加之前的文本。如何首先清理文本框并运行此代码?另外,有没有办法在打印过程结束时添加一个_来产生这种效果:“Hello world_”:)
  • @ProgrammingFreak 只需在 foreach 循环之前添加 this.TextBox.Text = string.Empty;... 看起来很明显,不是吗?
  • 谢谢!试过了,但有时它有点打乱我的话,第二个循环导致它打印出“Holel wrlod!”这样的词。和类似的东西。一个很好的计时器解决方案
【解决方案2】:

这是一个快速而肮脏的打字机效果,目前我正在循环浏览文本,但您可以改为停止计时器。

XAML:

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Grid>
        <TextBlock x:Name="TextBlock1" />
    </Grid>
</Window>

代码:

using System;
using System.Timers;
using System.Windows;

namespace WpfApplication4
{
    public partial class MainWindow
    {
        private int _length;
        private string _text;

        public MainWindow() {
            InitializeComponent();
            Loaded += MainWindow_Loaded;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e) {
            _text = "Hello, world !";
            var timer = new Timer(100);
            timer.Elapsed += timer_Elapsed;
            timer.Start();
        }

        private void timer_Elapsed(object sender, ElapsedEventArgs e) {
            _length++;
            if (_length > _text.Length) _length = 0;
            var substring = _text.Substring(0, _length);
            Dispatcher.BeginInvoke((Action) (() => { TextBlock1.Text = substring; }));
        }
    }
}

编辑:这里是一个在结尾处停止的版本

private void timer_Elapsed(object sender, ElapsedEventArgs e) {
    _length++;
    if (_length > _text.Length) {
        Timer timer = (Timer)sender;
        timer.Stop();
        return;
    }
    var substring = _text.Substring(0, _length);
    Dispatcher.BeginInvoke((Action) (() => { TextBlock1.Text = substring; }));
}

【讨论】:

    猜你喜欢
    • 2013-12-18
    • 2014-06-06
    • 1970-01-01
    • 2011-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-10
    相关资源
    最近更新 更多