none
Threading Probleme - FlowDokument abspeichern RRS feed

  • Allgemeine Diskussion

  • Hallo,

    ich habe ein Problem mit dem Threadding. Ich habe eine Liste von Objekten, denen je mehrere FlowDokument (genauer ein ablgeleitetes AdvancedFlowDokument) anhängt. Diese Elemente möchte ich in einen Thread auf die Festplatte verbannen. Das System hat bisher problemlos Funktioniert, aber jetzt wo ich es in einen Thread packen möchte, bekomme ich Probleme, das das Objekt nicht Besitzer ist. Da die Speichernoperation langsam ist, möchte ich diese aber auch nicht per Dispatcher durch führen. Weiß wer Rat? Kern des Problems ist mit Sicherheit, das es sich um ein FlowDokument handelt, was für mich nach wie vor ein Buch mit sieben Siegeln ist. 

    Zuerst das Durchlaufen der Liste und das ansprechen der Speicherung.

    Der Aufruf

    await Task.Run(() =>
               {
                   SaveList("Notecards", App.Variable.Database.ListNotecard);
               });


     /// <summary>
            /// Speichert die Liste.
            /// </summary>
            private void SaveList<T>(string path, ItemsChangeObservableCollection<T> list) where T : DispatcherSaveableBaseItem
            {
                this.DataExchange.ActualItemNumber = 0;
                string pathString = System.IO.Path.Combine(Properties.Settings.Default.StorageLocation, path);
                System.IO.Directory.CreateDirectory(pathString);
    
                var changes = from card in list
                              where card.Changed == true
                              select card;
    
                var changeList = changes.ToArray();
    
                this.DataExchange.MaximalItems = changeList.Count();
    
                for (int i = 0; i < changeList.Count(); i++)
                {
                    DispatcherSaveableBaseItem card = changeList[i];
                    changeList[i].Save(pathString);
                    this.DataExchange.ActualItemNumber = i;
                }
            }

    Es folgt das Speichern der einzelnen Elemente.

    /// <summary>
            /// Speichert die Notecard an einer bestimmten stelle.
            /// </summary>
            /// <param name="path"></param>
            public override void Save(string path)
            {
                if (this.Changed)
                {
                    string tmpPath = path + "\\" + this.ID.ToString() + ".json";
                    string s = this.JsonPlus();
    
                    using (System.IO.StreamWriter file = new System.IO.StreamWriter(tmpPath))
                    {
                         file.Write(s);
                    }
                    FlowDokumentConverter.DocumentToFile(Question, path + @"\" + QuestionPath);
                    FlowDokumentConverter.DocumentToFile(Answer, path + @"\" + AnswerPath);
                }
             
            }

    Zu guter letzt noch die Hilfsfunktion die Speichert.

    public static void DocumentToFile(FlowDocument document, string filePath)
            {
                
                TextRange range;
                FileStream fStream;
                range = new TextRange(document.ContentStart, document.ContentEnd);
                fStream = new FileStream(filePath, FileMode.Create);
                Dispatcher.CurrentDispatcher.Invoke(() => range.Save(fStream, DataFormats.XamlPackage));
                fStream.Close();
                //return System.IO.Path.GetFileName(filePath);
            }

    Hier habe ich probiert, das sichern über eine einzelne Dispatcherzeile durch zu führen. Ohne Erfolg.

    Sonntag, 16. August 2015 20:09

Alle Antworten

  • Hi,
    untersuche zuerst einmal, wo der Zeitverlust entsteht. Ich vermute, dass es das Schreiben ins Dateisystem ist. Im Haupt-Thread schreibst Du dann anstelle ins Dateisystem in einen MemoryStream. Diesen MemoryStream schreibst Du dann dem asynchronen Hintergund-Thread zum Schreiben ins Dateisystem.

    Beim Code, der im Vordergrund ausgeführt wird, solltest Du nach Möglichkeit auf Persistierungen ("var changeList = changes.ToArray();") verzichten und in einer foreach-Schleife den LinQ-Ausdruck direkt verarbeiten. Das spart Ressourcen und damit auch Zeit.


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks

    Montag, 17. August 2015 05:24
  • Hallo UrielMhezzek,

    bist Du weitergekommen?

    Gruß

    Aleksander


    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht,  kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Donnerstag, 27. August 2015 10:46
  • Leider nein. Vielleicht kann wer weiter helfen.

    Folgender Code führt das Speichern aus

     Task.Run(() =>
                {
                    this.DataExchange.IsBusy = true;
                    this.DataExchange.MaximalLists = 2;
    
                    this.DataExchange.ActualListNumber = 1;
                    this.DataExchange.WorkItem = "Lektionen";
                    //await Task.Run(() =>
                    //{
                        SaveList("Lectures", App.Variable.Database.ListLectures);
                    //});
                    App.Variable.Database.ListLectures.IsSaved();
    
                    this.DataExchange.ActualListNumber = 2;
                    this.DataExchange.WorkItem = "Lernkarten";
                
                    SaveList("Notecards", App.Variable.Database.ListNotecard);
    
                    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        App.Variable.Database.ListNotecard.IsSaved();
                    }));
    
    
                    SomethingChanged = false;
                    SetSaveItemsCount();
                
                    this.DataExchange.IsBusy = false;
                });


    Die Liste führt dann folgenden Code aus.

     private void SaveList<T>(string path, ItemsChangeObservableCollection<T> list) where T : DispatcherSaveableBaseItem
            {
                this.DataExchange.ActualItemNumber = 0;
                string pathString = System.IO.Path.Combine(Properties.Settings.Default.StorageLocation, path);
                System.IO.Directory.CreateDirectory(pathString);
    
                var changes = from card in list
                              where card.Changed == true
                              select card;
    
                var changeList = changes.ToArray();
    
                this.DataExchange.MaximalItems = changeList.Count();
    
                for (int i = 0; i < changeList.Count(); i++)
                {
                    DispatcherSaveableBaseItem card = changeList[i];
                    changeList[i].Save(pathString);
                    this.DataExchange.ActualItemNumber = i;
                }
            }


    Welches dann wiederum den jedes einzelne Element mit ... sichert

    /// <summary>
            /// Speichert die Notecard an einer bestimmten stelle.
            /// </summary>
            /// <param name="path"></param>
            public override void Save(string path)
            {
                if (this.Changed)
                {
                    string tmpPath = path + "\\" + this.ID.ToString() + ".json";
                    string s = this.JsonPlus();
    
                    using (System.IO.StreamWriter file = new System.IO.StreamWriter(tmpPath))
                    {
                         file.Write(s);
                    }
                    Question.SaveDispatcher(path + @"\" + QuestionPath);
                    Answer.SaveDispatcher(path + @"\" + AnswerPath);
                }
             
            }

    Aber nun komme ich zu meinen Problem. Question und Answer sind jeweils meine FlowDokumente. Aber ich bekomme diese schlicht nicht gesichert. Dieser Code sollte zwar Funktionieren, aber Problem ist, das das speichern verzögert statt findet und der Code weiter ausgeführt wird.

      public async void SaveDispatcher(string filePath)
            {
                await Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        TextRange range;
                        FileStream fStream;
                        range = new TextRange(this.ContentStart, this.ContentEnd);
                        fStream = new FileStream(filePath, FileMode.Create);
                        range.Save(fStream, DataFormats.XamlPackage);
                        fStream.Close();
                        range = null;
                        fStream = null;
                    }));
            }
    Ich hoffe jemand kann helfen.


    • Bearbeitet UrielMhezzek Donnerstag, 3. September 2015 20:10
    Donnerstag, 3. September 2015 20:07