我推薦一個更可重複使用的的方法,它可以讓你尋找,跳過和重播。由於很多代碼在這個問題中缺失,我已經對它的外觀做了一些假設。
將您的字幕保存在一個簡單的類中,該類至少包含應顯示的時間戳和要顯示的文本。如果您在任何時候都不想顯示任何文本,只需爲文本添加一個條目String.Empty
即可。
public class SubtitleEntry
{
public TimeSpan TimeStamp { get; set; }
public string Text { get; set; }
}
要跟蹤其位置(時間戳和字幕索引)你的,檢查下一個條目的時間戳比最後爲人所知的時間戳還早。如果「當前」字幕條目已更改,則引發事件以更新文本。
public class SubtitleManager
{
public event EventHandler<string> UpdateSubtitles;
private List<SubtitleEntry> _entries;
private int _currentIndex = -1;
private TimeSpan _currentTimeStamp = TimeSpan.MinValue;
public SubtitleManager()
{
_entries = new List<SubtitleEntry>();
}
public void SetEntries(IEnumerable<SubtitleEntry> entries)
{
// Set entries and reset previous "last" entry
_entries = new List<SubtitleEntry>(entries);
_currentTimeStamp = TimeSpan.MinValue;
_currentIndex = -1;
}
public void UpdateTime(TimeSpan timestamp)
{
// If there are no entries, there is nothing to do
if (_entries == null || _entries.Count == 0)
return;
// Remember position of last displayed subtitle entry
int previousIndex = _currentIndex;
// User must have skipped backwards, re-find "current" entry
if (timestamp < _currentTimeStamp)
_currentIndex = FindPreviousEntry(timestamp);
// Remember current timestamp
_currentTimeStamp = timestamp;
// First entry not hit yet
if (_currentIndex < 0 && timestamp < _entries[0].TimeStamp)
return;
// Try to find a later entry than the current to be displayed
while (_currentIndex + 1 < _entries.Count && _entries[_currentIndex + 1].TimeStamp < timestamp)
{
_currentIndex++;
}
// Has the current entry changed? Notify!
if(_currentIndex >= 0 && _currentIndex < _entries.Count && _currentIndex != previousIndex)
OnUpdateSubtitles(_entries[_currentIndex].Text);
}
private int FindPreviousEntry(TimeSpan timestamp)
{
// Look for the last entry that is "earlier" than the specified timestamp
for (int i = _entries.Count - 1; i >= 0; i--)
{
if (_entries[i].TimeStamp < timestamp)
return i;
}
return -1;
}
protected virtual void OnUpdateSubtitles(string e)
{
UpdateSubtitles?.Invoke(this, e);
}
}
在你的窗口,這將是這個樣子:
private DispatcherTimer _timer;
private SubtitleManager _manager;
public MainWindow()
{
InitializeComponent();
_manager = new SubtitleManager();
_manager.SetEntries(new List<SubtitleEntry>()
{
new SubtitleEntry{Text = "1s", TimeStamp = TimeSpan.FromSeconds(1)},
new SubtitleEntry{Text = "2s", TimeStamp = TimeSpan.FromSeconds(2)},
new SubtitleEntry{Text = "4s", TimeStamp = TimeSpan.FromSeconds(4)},
new SubtitleEntry{Text = "10s", TimeStamp = TimeSpan.FromSeconds(10)},
new SubtitleEntry{Text = "12s", TimeStamp = TimeSpan.FromSeconds(12)},
});
_manager.UpdateSubtitles += ManagerOnUpdateSubtitles;
}
private void ManagerOnUpdateSubtitles(object sender, string text)
{
txtSubtitle.Text = text;
}
private void BtnLoadVideo_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
if (dialog.ShowDialog(this) != true) return;
element.Source = new Uri(dialog.FileName, UriKind.Absolute);
_timer = new DispatcherTimer();
_timer.Tick += Timer_Tick;
_timer.Interval = new TimeSpan(0,0,0,0,50); //50 ms is fast enough
_timer.Start();
}
private void Timer_Tick(object sender, EventArgs eventArgs)
{
_manager.UpdateTime(element.Position);
}
這聽起來非常低效。至少,當你解析它們時,你可以「正常化」時間 - 基本上四捨五入到最近的500ms。那麼你的問題變得更簡單。 – Gui