System.Threading.Timer: Почему он ненавидит меня?

Я только начал возиться с C#/.NET/mono и прочим, и я пытаюсь сделать простой проигрыватель песен. Для этого я использую winmm.dll (не нашел простого кроссплатформенного решения). Проблема заключается в следующем: мне нужно обновить трекбар вместе с воспроизведением песни. У меня есть две функции, Player.GetLength а также Player.GetCurrentPosition, которые возвращают время в миллисекундах. Если я назову их "нормально", все в порядке. Но мне нужно вызвать их по таймеру, например так:

new System.Threading.Timer((state) =>
{
    length = Player.GetLength();
    pos = Player.GetCurrentPosition();
    trackBar1.Value = (pos / length) * 100;
}, null, 0, 100);     

Это GetLength, а также GetCurrentPosition похож:

public static int GetLength()
{
    StringBuilder s = new StringBuilder(128);
    mciSendString("status Song length", s, s.Capacity, IntPtr.Zero);
    return int.Parse(s.ToString());
}

Проблема: когда вызывается одна из этих двух функций, программа просто останавливается без каких-либо предупреждений или исключений. Примечание: я использую.NET

Поэтому мне было интересно, если вы можете объяснить мне, где я ошибся:)

1 ответ

Решение

Стоит отметить, что System.Threading.Timer запускает обратный вызов в своем собственном потоке. Поскольку вы взаимодействуете с пользовательским интерфейсом, вам нужно либо использовать System.Windows.Forms.Timer (в качестве компонента формы), либо вызывать обратно в пользовательский интерфейс следующим образом:

new System.Threading.Timer((state) =>
{
    length = Player.GetLength();
    pos = Player.GetCurrentPosition();
    trackBar1.Invoke(new Action(()=>trackBar1.Value = (pos / length) * 100));
}, null, 0, 100);   

Кроме того, я не уверен, поддерживает ли класс Player несколько потоков, но если нет, то существует вероятность того, что весь обратный вызов должен быть вызван в пользовательском интерфейсе.

Другие вопросы по тегам