2 Stimmen

wpf-Fensteraktualisierung funktioniert zuerst, dann stoppt sie

Ich habe eine Routine, die eine Liste aller Bilder in einem Verzeichnis abruft und dann einen MD5-Digest für alle Bilder durchführt. Da dies eine Weile dauert, zeige ich ein Fenster mit einem Fortschrittsbalken an. Der Fortschrittsbalken wird durch ein Lambda aktualisiert, das ich an die lang laufende Routine weitergebe.

Das erste Problem war, dass das Fortschrittsfenster nie aktualisiert wurde (was in WPF normal ist, denke ich). Da WPF keine Refresh() Befehl habe ich dies mit einem Aufruf von Dispatcher.Invoke() . Jetzt wird der Fortschrittsbalken eine Zeit lang aktualisiert, dann wird das Fenster nicht mehr aktualisiert. Die langwierige Arbeit wird schließlich beendet und die Fenster werden wieder normal angezeigt.

Ich habe bereits einen BackgroundWorker ausprobiert und wurde schnell durch ein Threading-Problem frustriert, das mit einem Ereignis zusammenhing, das durch den lang laufenden Prozess ausgelöst wurde. Wenn das also wirklich die beste Lösung ist und ich nur das Paradigma besser lernen muss, sagen Sie es bitte.

Aber ich wäre wirklich viel glücklicher mit dem Ansatz, den ich hier habe, außer dass es die Aktualisierung nach einer Weile stoppt (zum Beispiel in einem Ordner mit 1000 Dateien, könnte es für 50-100 Dateien aktualisieren, dann "hängen"). Die Benutzeroberfläche muss während dieser Aktivität nicht reagieren, außer um über den Fortschritt zu berichten.

Wie auch immer, hier ist der Code. Zuerst das Fortschrittsfenster selbst:

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>

Die lang laufende Methode (in 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);
        }
    }
}

Die so genannt wird:

 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();

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X