0

I am trying to build a WPF application that uses SSH.NET to upload multiple files on a server in parallel and display a progress bar for each of them.

In the view I have the following data grid:

                <DataGrid
                    AlternatingRowBackground="LightGray"
                    AutoGenerateColumns="False"
                    CanUserAddRows="False"
                    CanUserDeleteRows="False"
                    IsReadOnly="True"
                    ItemsSource="{Binding Files, Mode=TwoWay}"
                    SelectedItem="{Binding SelectedFile, Mode=OneWayToSource}">
                    <DataGrid.Columns>
                        <DataGridTextColumn Binding="{Binding Path=DisplayName}" Header="File" />
                        <DataGridTextColumn Binding="{Binding Path=FileSize}" Header="Size" />
                        <DataGridTextColumn Binding="{Binding Path=IsUploaded, Mode=OneWay}" Header="Uploaded" />
                        <DataGridTextColumn Binding="{Binding Path=IsUploading, Mode=OneWay}" Header="Uploading" />
                        <DataGridTemplateColumn Header="Progress">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Grid>
                                        <ProgressBar
                                            Width="300"
                                            Height="10"
                                            Maximum="{Binding FileSize}"
                                            Value="{Binding Path=SizeUploaded, Mode=OneWay}" />
                                        <TextBlock
                                            Margin="0,5,0,0"
                                            HorizontalAlignment="Center"
                                            Text="{Binding Path=PercentageCompleted, StringFormat={}{0}%}" />
                                    </Grid>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                        <DataGridTemplateColumn Header="Start">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Button cal:Message.Attach="UploadFile" Content="Start" />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                        <DataGridTemplateColumn Header="Stop">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Button cal:Message.Attach="StopTransfer" Content="Stop" />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                        <DataGridTemplateColumn Header="Remove">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Button cal:Message.Attach="RemoveFile" Content="Remove" />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                    </DataGrid.Columns>

                </DataGrid>

The ViewModel has public properties to bind DataGrid's items and SelectedItem:

    public BindingList<UploadedFile> Files { get; set; }

    public UploadedFile SelectedFile
    {
        get { return _selectedFile; }
        set
        {
            _selectedFile = value;
            NotifyOfPropertyChange(() => SelectedFile);
        }
    }

To get a file from hard-drive I am using MvvmDialgos library and call this method to create a new UploadedFile and add it to Files list:

        public void SelectFile()
    {
        var success = OpenFileDialog(this);

        if (success)
        {
            var file = new UploadedFile
            {
                FullName = OpenFileDialogSettings.FileName
            };

            file.DisplayName = Path.GetFileName(file.FullName);

            var fileInfo = new FileInfo(file.FullName);
            file.FileSize = (int)fileInfo.Length;

            if (Files == null)
                Files = new BindingList<UploadedFile>();

            Files.Add(file);

            NotifyOfPropertyChange(() => Files);
        }

    }

To upload the file on the server, with SSH.NET I am doing to following:

    private async Task UploadFileToServer(ConnectionModel connection, string fileName, string destinationPath)
    {
        if (!string.IsNullOrWhiteSpace(destinationPath))
        {
            await Task.Run(() =>
            {
                var currentUploadedFile = Files.FirstOrDefault(x => x.FullName == fileName);

                currentUploadedFile.IsUploading = true;
                try
                {
                    _fileManager.UploadFile(connection, fileName, destinationPath);

                    currentUploadedFile.IsUploaded = true;
                }

                catch (Exception ex)
                {
                    BroadCastErrorMessage(ex.Message);
                    IsConnectionTabExpanded = true;
                }
                finally
                {
                    currentUploadedFile.IsUploading = false;
                }
            });
        }

        else
        {
            BroadCastErrorMessage("ERROR: You must enter a destination folder!");
            IsConnectionTabExpanded = true;
        }
    }

FileManager call's the actually ssh.net library with:

                        using (var fs = new FileStream(fileName, FileMode.Open))
                        {
                            fullFileName = fileName;
                            sftp.BufferSize = 4 * 1024;
                            sftp.UploadFile(fs, Path.GetFileName(fileName), true, uploadCallback: UpdateProgresBar);
                            OnFileUploadedSuccess($@"Successfully uploaded {fileName} in {path}.");
                            status = FileRenamedStatus.Uploaded;
                        }

and raises an event with the uploaded size:

    private void UpdateProgresBar(ulong uploaded)
    {
        OnFileUploading(uploaded);
    }

   protected void OnFileUploading(ulong uploaded)
    {
        FileUploading?.Invoke(this, new UploadingEventArgs(new UploadedFile
        {
            SizeUploaded = (int)uploaded,
            FullName = fullFileName
        }));
    }

In the ViewModel I am listening for the event and update the progress bar:

    private void OnUploading(object sender, UploadingEventArgs e)
    {
        foreach (var item in Files.ToList())
        {
            if (item.FullName == e.UploadedFile.FullName)
            {
                item.SizeUploaded = e.UploadedFile.SizeUploaded;

                var percentage = (double)e.UploadedFile.SizeUploaded / item.FileSize;

                item.PercentageCompleted = Math.Round(percentage * 100, 2);
            }
        }
    }

My problem is when I am starting a second file transfer the progress bar for the first one stops and the one of the second transfer is going nuts, displaying random values, increasing and decreasing. My guess is somehow adding in the progress of the first file too.

Somehow I am unable to separate the progress for each progress bar.

What am I doing wrong?

1 Answer 1

-1

I am not sure if this is the correct fix but it seems that getting a new instance of _fileManager from IoC (using Caliburn.Micro) every time I am calling UploadFileToServer() solved the progressbar issue:

var manager = IoC.Get<IFileTransferManager>(); manager.OnUploading += OnUploading;

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.