none
Windows UWP App | Progress Bar | Kein Update RRS feed

  • Frage

  • Hallo zusammen,

    ich bin neu in der Entwicklung von UWP Apps und brauche eure Hilfe.

    Wenn ich ein Upload von Dateien starte zu einem SFTP Server mit SSH.NET und eine progress bar habe die bei jeder neuen Datei um eins hochzählt aktualisiert sich leider die progress bar nicht. Erst am Ende nach der Abarbeitung sehe ich das die progress bar nun komplett gefüllt angezeigt wird. Aber eben nicht bei jedem Schritt sondern nur am Ende.

    Richtig wäre es ggf. einen BackgroundWorker zu verwenden aber da weiß ich nicht wie es geht. Vielleicht kann mir jemand ein Beispiel geben wie ich den BackgroundWorker einsetzen kann für meinen Zweck.

    Vielleicht geht es aber auch noch anders und eleganter.

    Hoffe auf eure Meinungen und Tipps.

    Grüße
    Sven

    Hier ein vereinfachtes Code-Beispiel mit nur einem Upload. Es sind jedoch 100te Uploads die ich von einer Liste in einer "for loop" abarbeiten lasse.

        ConnectionInfo conInfo = new ConnectionInfo(smaHost, 22, smaUserName, new AuthenticationMethod[]{
            new PasswordAuthenticationMethod(smaUserName,smaPW)
        });
    
        SftpClient sftpClient = new SftpClient(conInfo);
        sftpClient.Connect();
    
        string filePath = Path.Combine(ApplicationData.Current.LocalFolder.Path, "test.txt")
        sftpClient.UploadFile(SMAReader(filePath), "test.txt", true);
    
        sftpClient.Disconnect();
        sftpClient.Dispose();



    • Bearbeitet sm-a Samstag, 25. Januar 2020 14:57
    Samstag, 25. Januar 2020 14:30

Antworten

  • Hi,
    nimm die Zuweisungen aus dem thread heraus, z.B. so:

    using Renci.SshNet;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
    
    namespace App1
    {
      /// <summary>
      /// An empty page that can be used on its own or navigated to within a Frame.
      /// </summary>
      public sealed partial class MainPage : Page
      {
        public MainPage()
        {
          this.InitializeComponent();
        }
    
        private SynchronizationContext sc = SynchronizationContext.Current;
        private bool IsInProgress { get; set; } = false; // Zur Verhinderung von mehrfachen Klicks
        private List<String> smaCommands;
        private String smaHost;
        private String smaUserName;
        private String smaPW;
    
        private async void btnStart_Click(object sender, RoutedEventArgs e)
        {
          if (IsInProgress) return; // wenn "In Arbeit", dann abbrechen
          this.IsInProgress = true; // "In Arbeit" setzen
    
          // Testen ob alle Felder ausgefüllt wurden
          if (smaHostTF.Text == "" || smaUserNameTF.Text == "" || smaPWTF.Text == "")
          {
            Debug.WriteLine("NICHT ALLE FELDER SIND AUSGEFÜLLT - WIRD DAHER ABGEBROCHEN!");
            //return;
          }
    
          smaCommands = new List<String>();
    
          smaCommands.Add("sleep 15");
          smaCommands.Add("sleep 10");
          smaCommands.Add("sleep 5");
    
          // progressbar initialisierung mit werten
          pbStatus.Maximum = smaCommands.Count;
          pbStatus.Value = 0;
    
          smaHost = smaHostTF.Text.Trim();
          smaUserName = smaUserNameTF.Text.Trim();
          smaPW = smaPWTF.Text.Trim();
    
          await Task.Run(new Action(DoWork));
        }
    
    
    
        private void DoWork()
        {
          ConnectionInfo conInfo = new ConnectionInfo(smaHost, 22, smaUserName, new AuthenticationMethod[]{
                        new PasswordAuthenticationMethod(smaUserName,smaPW)
                });
    
          // ssh client verbinden
          SshClient sshClient = new SshClient(conInfo);
          sshClient.Connect();
    
          foreach (var smaCommandsToProcess in smaCommands)
          {
            Debug.WriteLine("Aktuelles Kommando:\n" + smaCommandsToProcess);
    
            var command1 = sshClient.RunCommand(smaCommandsToProcess);
            var s1 = command1.Result;
    
            Debug.WriteLine("Aktuelles Kommando OUTPUT:\n" + smaCommandsToProcess + "\n" + s1);
    
            sc.Post(new SendOrPostCallback((state) => pbStatus.Value += 1), null);
          }
    
          sshClient.Disconnect();
          sshClient.Dispose();
    
          this.IsInProgress = false;
        }
      }
    }


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    • Als Antwort markiert sm-a Mittwoch, 29. Januar 2020 14:36
    Mittwoch, 29. Januar 2020 13:54

Alle Antworten

  • Hi,
    wenn der Upload in einem anderen Thread läuft (z.B. mittels Task), dann sollte die Fortschrittsanzeige auch immer aktuell sein. Hier mal ein Beispiel für eine lang andauernde Berechnung (in der Methode DoWork wird dies durch Warten simuliert).

    XAML:

    <Page
        x:Class="App1.Page18"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
      <Page.DataContext>
        <local:Page18VM/>
      </Page.DataContext>
      <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Button Content="Start" Command="{Binding Cmd}"/>
        <TextBlock Text="{Binding Display, Mode=OneWay}"/>
        <ProgressBar Value="{Binding Progress}" Height="40"/>
      </StackPanel>
    </Page>
    

    Und dazu der ViewModel:

    using System;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Input;
    using Windows.UI.Xaml.Controls;
    
    namespace App1
    {
      public class Page18VM : INotifyPropertyChanged
      {
    
        SynchronizationContext sc = SynchronizationContext.Current;
    
        public string Display { get; set; } = "<empty>";
    
        public int Progress { get; set; }
    
        private bool IsInProgress { get; set; }
    
        public ICommand Cmd { get { return new RelayCommand(CmdExec); } }
        private async void CmdExec(object obj)
        {
          try
          {
            if (!IsInProgress) await Task.Run(new Action(DoWork));
          }
          catch (Exception ex)
          {
            Display = ex.ToString();
          }
          OnPropertyChanged(nameof(Display));
        }
    
        private async void DoWork()
        {
          IsInProgress = true;
          for (int i = 0; i <= 100; i++)
          {
            await Task.Delay(100); // simulate work
            sc.Post(new SendOrPostCallback((state) =>
            {
              Progress = i;
              OnPropertyChanged(nameof(Progress));
            }), null);
          }
          IsInProgress = false;
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName] string propertyName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    }

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Samstag, 25. Januar 2020 19:23
  • Hi Peter,

    die letzten Tage habe ich versucht es zum laufen zu bekommen jedoch scheitere ich jedesmal. Es würde mich freuen wenn Du meinen Programmcode mal ansehen könntest und mir etwas detailierter beschreiben könntest wie ich die progressbar so implementieren kann das diese auch einen Fortschritt anzeigt und nicht erst am Ende des Programmablaufs.

    Im folgenden Code-Beispiel habe ich SSH verwendet.

    Mein Code findet sich hier:
    https://github.com/sm-a/ssh-test-app

    Vielen Dank im Voraus.

    Grüße
    Sven

    Mittwoch, 29. Januar 2020 13:01
  • Hi,
    ich habe mal Deinen Code etwas umgebaut. Ich habe ihn aber nicht getestet, da ich keine passenden Zugangsdaten habe.

    using Renci.SshNet;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
    
    namespace App1
    {
      /// <summary>
      /// An empty page that can be used on its own or navigated to within a Frame.
      /// </summary>
      public sealed partial class MainPage : Page
      {
        public MainPage()
        {
          this.InitializeComponent();
        }
    
        private SynchronizationContext sc = SynchronizationContext.Current;
        private bool IsInProgress { get; set; } = false;// Zur Verhinderung von mehrfachen Klicks
        private List<String> smaCommands;
    
        private async void btnStart_Click(object sender, RoutedEventArgs e)
        {
          if (IsInProgress) return; // wenn "In Arbeit", dann abbrechen
          this.IsInProgress = true; // "In Arbeit" setzen
    
          // Testen ob alle Felder ausgefüllt wurden
          if (smaHostTF.Text == "" || smaUserNameTF.Text == "" || smaPWTF.Text == "")
          {
            Debug.WriteLine("NICHT ALLE FELDER SIND AUSGEFÜLLT - WIRD DAHER ABGEBROCHEN!");
            return;
          }
    
          smaCommands = new List<String>();
    
          smaCommands.Add("sleep 15");
          smaCommands.Add("sleep 10");
          smaCommands.Add("sleep 5");
    
          // progressbar initialisierung mit werten
          pbStatus.Maximum = smaCommands.Count;
          pbStatus.Value = 0;
    
          await Task.Run(new Action(DoWork));
        }
    
        private void DoWork()
        {
          String smaHost = smaHostTF.Text.Trim();
          String smaUserName = smaUserNameTF.Text.Trim();
          String smaPW = smaPWTF.Text.Trim();
    
          ConnectionInfo conInfo = new ConnectionInfo(smaHost, 22, smaUserName, new AuthenticationMethod[]{
                        new PasswordAuthenticationMethod(smaUserName,smaPW)
                });
    
          // ssh client verbinden
          SshClient sshClient = new SshClient(conInfo);
          sshClient.Connect();
    
          foreach (var smaCommandsToProcess in smaCommands)
          {
            Debug.WriteLine("Aktuelles Kommando:\n" + smaCommandsToProcess);
    
            var command1 = sshClient.RunCommand(smaCommandsToProcess);
            var s1 = command1.Result;
    
            Debug.WriteLine("Aktuelles Kommando OUTPUT:\n" + smaCommandsToProcess + "\n" + s1);
    
            sc.Post(new SendOrPostCallback((state) => pbStatus.Value += 1), null);
    
          }
    
          sshClient.Disconnect();
          sshClient.Dispose();
    
          this.IsInProgress = false;
        }
      }
    }
    


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Mittwoch, 29. Januar 2020 13:24
  • Hi Peter,

    vielen vielen Dank für die Hilfe.

    Wenn ich den Code ausführe dann erhalte ich folgende Exception:

    System.Exception: 'The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))'

    Diese Tritt bei folgender Codezeile (55) auf:
    String smaHost = smaHostTF.Text.Trim();

    Vielleicht hast Du hier noch eine Idee.

    Grüße
    Sven


    Mittwoch, 29. Januar 2020 13:35
  • Hi,
    nimm die Zuweisungen aus dem thread heraus, z.B. so:

    using Renci.SshNet;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
    
    namespace App1
    {
      /// <summary>
      /// An empty page that can be used on its own or navigated to within a Frame.
      /// </summary>
      public sealed partial class MainPage : Page
      {
        public MainPage()
        {
          this.InitializeComponent();
        }
    
        private SynchronizationContext sc = SynchronizationContext.Current;
        private bool IsInProgress { get; set; } = false; // Zur Verhinderung von mehrfachen Klicks
        private List<String> smaCommands;
        private String smaHost;
        private String smaUserName;
        private String smaPW;
    
        private async void btnStart_Click(object sender, RoutedEventArgs e)
        {
          if (IsInProgress) return; // wenn "In Arbeit", dann abbrechen
          this.IsInProgress = true; // "In Arbeit" setzen
    
          // Testen ob alle Felder ausgefüllt wurden
          if (smaHostTF.Text == "" || smaUserNameTF.Text == "" || smaPWTF.Text == "")
          {
            Debug.WriteLine("NICHT ALLE FELDER SIND AUSGEFÜLLT - WIRD DAHER ABGEBROCHEN!");
            //return;
          }
    
          smaCommands = new List<String>();
    
          smaCommands.Add("sleep 15");
          smaCommands.Add("sleep 10");
          smaCommands.Add("sleep 5");
    
          // progressbar initialisierung mit werten
          pbStatus.Maximum = smaCommands.Count;
          pbStatus.Value = 0;
    
          smaHost = smaHostTF.Text.Trim();
          smaUserName = smaUserNameTF.Text.Trim();
          smaPW = smaPWTF.Text.Trim();
    
          await Task.Run(new Action(DoWork));
        }
    
    
    
        private void DoWork()
        {
          ConnectionInfo conInfo = new ConnectionInfo(smaHost, 22, smaUserName, new AuthenticationMethod[]{
                        new PasswordAuthenticationMethod(smaUserName,smaPW)
                });
    
          // ssh client verbinden
          SshClient sshClient = new SshClient(conInfo);
          sshClient.Connect();
    
          foreach (var smaCommandsToProcess in smaCommands)
          {
            Debug.WriteLine("Aktuelles Kommando:\n" + smaCommandsToProcess);
    
            var command1 = sshClient.RunCommand(smaCommandsToProcess);
            var s1 = command1.Result;
    
            Debug.WriteLine("Aktuelles Kommando OUTPUT:\n" + smaCommandsToProcess + "\n" + s1);
    
            sc.Post(new SendOrPostCallback((state) => pbStatus.Value += 1), null);
          }
    
          sshClient.Disconnect();
          sshClient.Dispose();
    
          this.IsInProgress = false;
        }
      }
    }


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    • Als Antwort markiert sm-a Mittwoch, 29. Januar 2020 14:36
    Mittwoch, 29. Januar 2020 13:54
  • Hi Peter,

    wow es funktioniert. Vielen Vielen Dank.

    Möchte gerne vom Wissen wie Du werden. Welche Onlinekurse, Bücher oder sonstige Materialien hast Du gelesen um so exzellent zu werden wie Du es jetzt bist?

    Eine schöne Woche wünsche ich Dir.

    Grüße
    Sven

    Mittwoch, 29. Januar 2020 14:36
  • Hi Sven,
    vor über 50 Jahren Studium der Elektrotechnik, dann Promotion auf dem Gebiet multivirtueller Systeme, parallel Programmierung in Assembler, Fortran, Pl1, Cobol, Visual Basic und seit 20 Jahren im .NET. Da sammelt sich automatisch Erfahrung an.

    Meine Empfehlung: Grundlagenstudium, viel lesen, konkrete Lösungen programmieren. Ich lese gern und viel (Papier und auch online), arbeite dann auch Fachliteratur durch, beschäftige mich mit Prozessorganisation, Bedientechnologien uvam. Das macht alles mächtig Spaß.


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Mittwoch, 29. Januar 2020 14:58