У меня есть рутина, которая захватывает список всех изображений в каталоге, а затем запускает дайджест MD5 на всех из них. Поскольку это занимает некоторое время, я должен открыть окно с индикатором выполнения. Индикатор выполнения обновляется лямбдой, которую я перехожу к длительной рутине.Сначала обновляется окно wpf, затем останавливается
Первой проблемой было то, что окно прогресса никогда не обновлялось (что, как я полагаю, является нормальным в WPF). Поскольку WPF не хватает команды Refresh()
, я исправил это с помощью вызова Dispatcher.Invoke()
. Теперь индикатор выполнения обновляется некоторое время, затем окно перестает обновляться. В конечном итоге работа над долгой работой заканчивается, и окна возвращаются к нормальной жизни.
Я уже пробовал BackgroundWorker и быстро разочаровался в проблеме потоковой передачи, связанной с событием, вызванным длительным процессом. Так что если это действительно лучшее решение, и мне просто нужно лучше изучить парадигму, скажите об этом.
Но я был бы намного более счастлив с подходом, который я получил здесь, за исключением того, что он немного перестает обновляться (например, в папке с 1000 файлами она может обновляться для 50-100 файлов, затем "повесить"). Пользовательский интерфейс не должен быть отзывчивым во время этой деятельности, за исключением отчета о прогрессе.
В любом случае, вот код. Сначала само окно прогресса:
public partial class ProgressWindow : Window
{
public ProgressWindow(string title, string supertext, string subtext)
{
InitializeComponent();
this.Title = title;
this.SuperText.Text = supertext;
this.SubText.Text = subtext;
}
internal void UpdateProgress(int count, int total)
{
this.ProgressBar.Maximum = Convert.ToDouble(total);
this.ProgressBar.Value = Convert.ToDouble(count);
this.SubText.Text = String.Format("{0} of {1} finished", count, total);
this.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
}
private static Action EmptyDelegate = delegate() { };
}
<Window x:Class="Pixort.ProgressWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Pixort Progress" Height="128" Width="256" WindowStartupLocation="CenterOwner" WindowStyle="SingleBorderWindow" ResizeMode="NoResize">
<DockPanel>
<TextBlock DockPanel.Dock="Top" x:Name="SuperText" TextAlignment="Left" Padding="6"></TextBlock>
<TextBlock DockPanel.Dock="Bottom" x:Name="SubText" TextAlignment="Right" Padding="6"></TextBlock>
<ProgressBar x:Name="ProgressBar" Height="24" Margin="6"/>
</DockPanel>
</Window>
Длинный метод работает (в Gallery.cs):
public void ImportFolder(string folderPath, Action<int, int> progressUpdate)
{
string[] files = this.FileIO.GetFiles(folderPath);
for (int i = 0; i < files.Length; i++)
{
// do stuff with the file
if (null != progressUpdate)
{
progressUpdate.Invoke(i + 1, files.Length);
}
}
}
Что называется таким образом:
ProgressWindow progress = new ProgressWindow("Import Folder Progress", String.Format("Importing {0}", folder), String.Empty);
progress.Show();
this.Gallery.ImportFolder(folder, ((c, t) => progress.UpdateProgress(c, t)));
progress.Close();
Вы знаете, где я могу найти рабочий пример этого? Я попробовал много разных вещей, чтобы заставить это работать без добавления слоев косвенности к коду. Каждый раз, когда панель вообще не обновлялась. – mlibby
Привет, я разместил код. Проверь это. – RockWorld