0

I am creating an application to read table from database and dump them into file.The user ask to dump one file and right after as a second task then a third and so one. I am looking to display on the GUI when the task finnish or if they fail.I am having hard time to communicate between my task and the GUI. Here is the code of my gui :

namespace ClientCsvDumper
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
async void go_Click(object sender, RoutedEventArgs e)
        {
            String database_name;
            String schema_name;
            String output_file_name;

            database_name = this.database_name.SelectedItem.ToString();

            output_file_name = this.output_file_name.Text;

            SqlConnection conn = new SqlConnection("Data Source="+this.server_name.Text+";Initial Catalog="+"MASTER"+";Integrated Security=True");
            if (this.query_button.IsChecked.Value) {
                String query_text;
                query_text = this.query_textbox.Text;
                thread_number++;
                await Task.Run(() => {
                    UpdateWindows("task " + thread_number.ToString() + " started");
                    AsyncDumpQueryToFile(conn, database_name, query_text, output_file_name);
                });


            }
            else {
                schema_name = this.schema_name.SelectedItem.ToString();
                String table_name;
                table_name = this.table_name.SelectedItem.ToString();
                thread_number++;
                await Task.Run(() => {UpdateWindows("task " + thread_number.ToString() + " started");
                    AsyncDumpTableToFile(conn, database_name, schema_name, table_name, output_file_name);
                });

             }

        }

async Task AsyncDumpTableToFile( SqlConnection connection, string database_name, string schema_name, string tableName, string destinationFile) {
           // gui.UpdateWindows("Work Started");
            TableDumper ts = new TableDumper();
            ts.DumpTableToFile(connection, database_name, schema_name, tableName, destinationFile);

          //  gui.UpdateWindows("Done");
        }
        async Task AsyncDumpQueryToFile( SqlConnection connection, string database_name, string query, string destinationFile)
        {
            //gui.UpdateWindows("Work Started");
            TableDumper ts = new TableDumper();
            ts.DumpQueryToFile( connection,  database_name,  query,  destinationFile);

           // gui.UpdateWindows("Done");
        }

        void UpdateWindows(String text) {

            Dispatcher.Invoke(() => { status.Text += text; });
        }

First i tried (using code from the web ) to pass the gui 0bject to the fonction AsyncDumpTableToFile (so i can modify thing on the gui but it was crashing saying the main Thread used and own it.

How could i print on the main GUI informatoin about the runnin task ( Started,running,failed ( exception message), SUccess ) ?

Also any good reading for me to understand a bit more this kind of stuff ?

All the best

Vincent

Il Vic
  • 5,576
  • 4
  • 26
  • 37
  • 2
    Look into the BackgroundWorker class. It has everything needed to monitor progression and completion of your work: https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx – Kevin Gosse Jun 01 '17 at 06:35
  • 1
    @Kevin: I disagree with the suggestion to use `BackgroundWorker`. It is a decent enough solution, and I grant there is a lot of information out there about how to use it, due to the length of time it's been around. But modern C# code will use `Task.Run()` as in the code above. Advice at this point should help move the OP forward, not backward. – Peter Duniho Jun 01 '17 at 07:07
  • 2
    To the OP: you are using WPF, which means that, in the general case, if you would use view model objects with `INotifyPropertyChanged` and data binding to the UI, cross-thread updates will be handled automatically. For scenarios where that doesn't work, you can use `Progress` to report progress, and of course return objects from the task method via `await`. Unfortunately, your question does not include a good [mcve] that reliably reproduces your problem, so it's not possible to give you any specific advice nor a good answer (you may get plenty of bad answers though). – Peter Duniho Jun 01 '17 at 07:09
  • Possible duplicate of [Right way to continuously update the UI](https://stackoverflow.com/questions/44285619/right-way-to-continuously-update-the-ui) – Rekshino Jun 01 '17 at 07:25
  • As @PeterDuniho said you should use MVVM for WPF applications. In a view model you can define property like Status that will be updated during an operation execution. Create binding from a GUI control to this property and you will be happy. I recommend move your logic from code behind to command in view model. Also there are some nice features in C# like `var` and `string` instead of `String` :). – Maxim Jun 01 '17 at 07:39
  • 1
    Maybe you can use the solution from [here](https://stackoverflow.com/a/42366480/238902) which uses IProgress to report status – default Jun 01 '17 at 07:41
  • I push my code to BitBucker if that can be any use https://bitbucket.org/vdiallonort/csvdumper – Vincent Diallo-Nort Jun 01 '17 at 07:52
  • 2
    _"...if that can be any use"_ -- no, that's of no use. One of your responsibilities as a person seeking help on Stack Overflow is to prepare a proper, good [mcve] that reliably reproduces your problem, and to include that in its entirety in your question. Read that linked page, as well as [ask], and the articles linked at the bottom of _that_ page, to understand better what that means and why it's so important. – Peter Duniho Jun 01 '17 at 08:18
  • Hi,Sorry if that did make you angry,for now i have no idea which direction i am looking at and the only element i though was relevant is that the Main thread block me to pass the GUI object as a parameter.I am for now only looking for direction therefore the reason i ask for reading so i get to know what i am looking at.I only post my code to indicate what kind of problem i have.I am not looking for anyone to solve my problems just point me some direction. – Vincent Diallo-Nort Jun 02 '17 at 00:01

1 Answers1

1

I agree with Peter that your ideal solution will use MVVM. However, you can also access UI elements directly with the modern IProgress<T>-based approach, something like:

async void go_Click(object sender, RoutedEventArgs e)
{
  IProgress<string> progress = new Progress<string>(text => status.Text += text);
  ...
  await Task.Run(() =>
  {
    progress.Report("task " + thread_number.ToString() + " started");
    AsyncDump*ToFile(..., progress);
  });
  ...
}

async Task AsyncDump*ToFile(..., IProgress<string> progress)
{
  progress.Report("Work Started");
  ...
  progress.Report("Done");
}

The important part of this pattern is that the Progress<T> object must be created while on the UI thread. It will then take care of the thread marshalling for you.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810