How to open a WPF window from an async method












0















I've been trying to find a solution for this, but at this point nothing that I've found has made the click. I'm starting with WPF, so I may just missed some obvious answer, but I would highly appreciate an answer for dumbs. This is the situation:



My app is structured using MVVM. Its main functionality is called from a button. Once called, it will loop through all the files within an specified directory and perform some renaming. While doing this loop, I wanted to show a progress bar indicated how many files have been renamed out of the total.
The progress value is a property binded to the Progressbar control



I've only been able to update the progress bar asynchronously; otherwise it will remain empty until the process finishes. Right now its working with a BackgroundWorker.



_bgWorker.DoWork += (s, e) =>
{
RenamingMethod();
};
...
RenamingMethodCommand = new RelayCommand(_ =>_bgWorker.RunWorkerAsync());


For performing the renaming, a hash is expected in the name of the file. This hash will be translated to a user-entered value if found, otherwise a window should be displayed asking the user to enter it.



This window is not being able to be displayed in a MTAThread (I'm using ShowDialog, I haven't found any other way to make it appear), and so I can't call it from the async methods in my main window. The only way I found to make it work was calling everything inside RenamingMethod like this:



public void RenamingMethod()
{
Application.Current.Dispatcher.Invoke((Action)delegate
{
//code for renaming
}
}


At this point, the progress bar is only updated the moment I close the pop up window. Then it remains on the same value until a new window is opened and closed.



I would like to open the pop up window from the asynchronous method that updates the progress bar, so the evolution of this is smooth, and its stopped when a new window is openned. Or being able to update the progress bar synchronously would probably work as well.



Here's the code in more detail:



public void RenameMethod()
{
Application.Current.Dispatcher.Invoke((Action)delegate
{
IEnumerable<string> files = Directory.EnumerateFiles(
OriginMediaFolder,
"*.*",
SearchOption.AllDirectories).
Where(name => name.EndsWith(".jpg") || name.EndsWith(".mp4"));

int numberOfFiles = files.Count();
float fileNumber = 0;
foreach (string file in files)
{
MoveAndRenameFile(file);
ProgressValue = (int)(100 * (fileNumber++ / numberOfFiles));
}
});
}

public void MoveAndRenameFile(string file)
{
//Name structure: path/1234567891234567-hash.ext
string fileName = Regex.Match(file, @"[^/\]+.",RegexOptions.RightToLeft).
Value.TrimEnd('.');
string date = fileName.Substring(0, 16);
string hash = fileName.Substring(17);
if (!HashToName(hash, out string gameName))
{
var gameNamingWindow = GetNewNameFromUser(hash);
}
string extension = Regex.Match(file, @"..+Z", RegexOptions.RightToLeft).Value;

if (!Directory.Exists(DestinationMediaFolder + "/" + gameName))
Directory.CreateDirectory(DestinationMediaFolder + "/" + gameName);

File.Move(file, DestinationMediaFolder + "/" + gameName + "/" + date + extension);
}

public string GetNewNameFromUser(string hash)
{
var gameNamingWindow = new NewGameWindow.MainWindow(OriginMediaFolder, hash);
if (gameNamingWindow.ShowDialog().Value)
{
string gameName = gameNamingWindow.Result;
NameHashes.Add(new NameHash
{
GameName = gameName,
Hash = hash
});
return gameName;
}
return hash;
}









share|improve this question





























    0















    I've been trying to find a solution for this, but at this point nothing that I've found has made the click. I'm starting with WPF, so I may just missed some obvious answer, but I would highly appreciate an answer for dumbs. This is the situation:



    My app is structured using MVVM. Its main functionality is called from a button. Once called, it will loop through all the files within an specified directory and perform some renaming. While doing this loop, I wanted to show a progress bar indicated how many files have been renamed out of the total.
    The progress value is a property binded to the Progressbar control



    I've only been able to update the progress bar asynchronously; otherwise it will remain empty until the process finishes. Right now its working with a BackgroundWorker.



    _bgWorker.DoWork += (s, e) =>
    {
    RenamingMethod();
    };
    ...
    RenamingMethodCommand = new RelayCommand(_ =>_bgWorker.RunWorkerAsync());


    For performing the renaming, a hash is expected in the name of the file. This hash will be translated to a user-entered value if found, otherwise a window should be displayed asking the user to enter it.



    This window is not being able to be displayed in a MTAThread (I'm using ShowDialog, I haven't found any other way to make it appear), and so I can't call it from the async methods in my main window. The only way I found to make it work was calling everything inside RenamingMethod like this:



    public void RenamingMethod()
    {
    Application.Current.Dispatcher.Invoke((Action)delegate
    {
    //code for renaming
    }
    }


    At this point, the progress bar is only updated the moment I close the pop up window. Then it remains on the same value until a new window is opened and closed.



    I would like to open the pop up window from the asynchronous method that updates the progress bar, so the evolution of this is smooth, and its stopped when a new window is openned. Or being able to update the progress bar synchronously would probably work as well.



    Here's the code in more detail:



    public void RenameMethod()
    {
    Application.Current.Dispatcher.Invoke((Action)delegate
    {
    IEnumerable<string> files = Directory.EnumerateFiles(
    OriginMediaFolder,
    "*.*",
    SearchOption.AllDirectories).
    Where(name => name.EndsWith(".jpg") || name.EndsWith(".mp4"));

    int numberOfFiles = files.Count();
    float fileNumber = 0;
    foreach (string file in files)
    {
    MoveAndRenameFile(file);
    ProgressValue = (int)(100 * (fileNumber++ / numberOfFiles));
    }
    });
    }

    public void MoveAndRenameFile(string file)
    {
    //Name structure: path/1234567891234567-hash.ext
    string fileName = Regex.Match(file, @"[^/\]+.",RegexOptions.RightToLeft).
    Value.TrimEnd('.');
    string date = fileName.Substring(0, 16);
    string hash = fileName.Substring(17);
    if (!HashToName(hash, out string gameName))
    {
    var gameNamingWindow = GetNewNameFromUser(hash);
    }
    string extension = Regex.Match(file, @"..+Z", RegexOptions.RightToLeft).Value;

    if (!Directory.Exists(DestinationMediaFolder + "/" + gameName))
    Directory.CreateDirectory(DestinationMediaFolder + "/" + gameName);

    File.Move(file, DestinationMediaFolder + "/" + gameName + "/" + date + extension);
    }

    public string GetNewNameFromUser(string hash)
    {
    var gameNamingWindow = new NewGameWindow.MainWindow(OriginMediaFolder, hash);
    if (gameNamingWindow.ShowDialog().Value)
    {
    string gameName = gameNamingWindow.Result;
    NameHashes.Add(new NameHash
    {
    GameName = gameName,
    Hash = hash
    });
    return gameName;
    }
    return hash;
    }









    share|improve this question



























      0












      0








      0








      I've been trying to find a solution for this, but at this point nothing that I've found has made the click. I'm starting with WPF, so I may just missed some obvious answer, but I would highly appreciate an answer for dumbs. This is the situation:



      My app is structured using MVVM. Its main functionality is called from a button. Once called, it will loop through all the files within an specified directory and perform some renaming. While doing this loop, I wanted to show a progress bar indicated how many files have been renamed out of the total.
      The progress value is a property binded to the Progressbar control



      I've only been able to update the progress bar asynchronously; otherwise it will remain empty until the process finishes. Right now its working with a BackgroundWorker.



      _bgWorker.DoWork += (s, e) =>
      {
      RenamingMethod();
      };
      ...
      RenamingMethodCommand = new RelayCommand(_ =>_bgWorker.RunWorkerAsync());


      For performing the renaming, a hash is expected in the name of the file. This hash will be translated to a user-entered value if found, otherwise a window should be displayed asking the user to enter it.



      This window is not being able to be displayed in a MTAThread (I'm using ShowDialog, I haven't found any other way to make it appear), and so I can't call it from the async methods in my main window. The only way I found to make it work was calling everything inside RenamingMethod like this:



      public void RenamingMethod()
      {
      Application.Current.Dispatcher.Invoke((Action)delegate
      {
      //code for renaming
      }
      }


      At this point, the progress bar is only updated the moment I close the pop up window. Then it remains on the same value until a new window is opened and closed.



      I would like to open the pop up window from the asynchronous method that updates the progress bar, so the evolution of this is smooth, and its stopped when a new window is openned. Or being able to update the progress bar synchronously would probably work as well.



      Here's the code in more detail:



      public void RenameMethod()
      {
      Application.Current.Dispatcher.Invoke((Action)delegate
      {
      IEnumerable<string> files = Directory.EnumerateFiles(
      OriginMediaFolder,
      "*.*",
      SearchOption.AllDirectories).
      Where(name => name.EndsWith(".jpg") || name.EndsWith(".mp4"));

      int numberOfFiles = files.Count();
      float fileNumber = 0;
      foreach (string file in files)
      {
      MoveAndRenameFile(file);
      ProgressValue = (int)(100 * (fileNumber++ / numberOfFiles));
      }
      });
      }

      public void MoveAndRenameFile(string file)
      {
      //Name structure: path/1234567891234567-hash.ext
      string fileName = Regex.Match(file, @"[^/\]+.",RegexOptions.RightToLeft).
      Value.TrimEnd('.');
      string date = fileName.Substring(0, 16);
      string hash = fileName.Substring(17);
      if (!HashToName(hash, out string gameName))
      {
      var gameNamingWindow = GetNewNameFromUser(hash);
      }
      string extension = Regex.Match(file, @"..+Z", RegexOptions.RightToLeft).Value;

      if (!Directory.Exists(DestinationMediaFolder + "/" + gameName))
      Directory.CreateDirectory(DestinationMediaFolder + "/" + gameName);

      File.Move(file, DestinationMediaFolder + "/" + gameName + "/" + date + extension);
      }

      public string GetNewNameFromUser(string hash)
      {
      var gameNamingWindow = new NewGameWindow.MainWindow(OriginMediaFolder, hash);
      if (gameNamingWindow.ShowDialog().Value)
      {
      string gameName = gameNamingWindow.Result;
      NameHashes.Add(new NameHash
      {
      GameName = gameName,
      Hash = hash
      });
      return gameName;
      }
      return hash;
      }









      share|improve this question
















      I've been trying to find a solution for this, but at this point nothing that I've found has made the click. I'm starting with WPF, so I may just missed some obvious answer, but I would highly appreciate an answer for dumbs. This is the situation:



      My app is structured using MVVM. Its main functionality is called from a button. Once called, it will loop through all the files within an specified directory and perform some renaming. While doing this loop, I wanted to show a progress bar indicated how many files have been renamed out of the total.
      The progress value is a property binded to the Progressbar control



      I've only been able to update the progress bar asynchronously; otherwise it will remain empty until the process finishes. Right now its working with a BackgroundWorker.



      _bgWorker.DoWork += (s, e) =>
      {
      RenamingMethod();
      };
      ...
      RenamingMethodCommand = new RelayCommand(_ =>_bgWorker.RunWorkerAsync());


      For performing the renaming, a hash is expected in the name of the file. This hash will be translated to a user-entered value if found, otherwise a window should be displayed asking the user to enter it.



      This window is not being able to be displayed in a MTAThread (I'm using ShowDialog, I haven't found any other way to make it appear), and so I can't call it from the async methods in my main window. The only way I found to make it work was calling everything inside RenamingMethod like this:



      public void RenamingMethod()
      {
      Application.Current.Dispatcher.Invoke((Action)delegate
      {
      //code for renaming
      }
      }


      At this point, the progress bar is only updated the moment I close the pop up window. Then it remains on the same value until a new window is opened and closed.



      I would like to open the pop up window from the asynchronous method that updates the progress bar, so the evolution of this is smooth, and its stopped when a new window is openned. Or being able to update the progress bar synchronously would probably work as well.



      Here's the code in more detail:



      public void RenameMethod()
      {
      Application.Current.Dispatcher.Invoke((Action)delegate
      {
      IEnumerable<string> files = Directory.EnumerateFiles(
      OriginMediaFolder,
      "*.*",
      SearchOption.AllDirectories).
      Where(name => name.EndsWith(".jpg") || name.EndsWith(".mp4"));

      int numberOfFiles = files.Count();
      float fileNumber = 0;
      foreach (string file in files)
      {
      MoveAndRenameFile(file);
      ProgressValue = (int)(100 * (fileNumber++ / numberOfFiles));
      }
      });
      }

      public void MoveAndRenameFile(string file)
      {
      //Name structure: path/1234567891234567-hash.ext
      string fileName = Regex.Match(file, @"[^/\]+.",RegexOptions.RightToLeft).
      Value.TrimEnd('.');
      string date = fileName.Substring(0, 16);
      string hash = fileName.Substring(17);
      if (!HashToName(hash, out string gameName))
      {
      var gameNamingWindow = GetNewNameFromUser(hash);
      }
      string extension = Regex.Match(file, @"..+Z", RegexOptions.RightToLeft).Value;

      if (!Directory.Exists(DestinationMediaFolder + "/" + gameName))
      Directory.CreateDirectory(DestinationMediaFolder + "/" + gameName);

      File.Move(file, DestinationMediaFolder + "/" + gameName + "/" + date + extension);
      }

      public string GetNewNameFromUser(string hash)
      {
      var gameNamingWindow = new NewGameWindow.MainWindow(OriginMediaFolder, hash);
      if (gameNamingWindow.ShowDialog().Value)
      {
      string gameName = gameNamingWindow.Result;
      NameHashes.Add(new NameHash
      {
      GameName = gameName,
      Hash = hash
      });
      return gameName;
      }
      return hash;
      }






      c# wpf asynchronous progress-bar showdialog






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 25 '18 at 7:24







      Dani Lathspell Gutierrez

















      asked Nov 25 '18 at 7:08









      Dani Lathspell GutierrezDani Lathspell Gutierrez

      34




      34
























          1 Answer
          1






          active

          oldest

          votes


















          0














          The Invoke call switches over to the GUI thread, so you're basically tying up that thread doing all your work and effectively negating the whole point of using a worker thread to begin with. Change RenameMethod() so that that only thing inside the Invoke block is the one thing that actually needs to be there i.e. the line that updates the progress bar.



          Better yet, start using proper data binding for your GUI controls so that you don't have to mess around with task switching at all.






          share|improve this answer
























          • Hey Mark, thanks for the answer. It was actuallly de line opening the window the one inside the Invoke, the update was in another Thread because if not, it wouldn't get updated until the end. About the better data binding, anything to expand on that?

            – Dani Lathspell Gutierrez
            Nov 26 '18 at 6:41













          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53465399%2fhow-to-open-a-wpf-window-from-an-async-method%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          0














          The Invoke call switches over to the GUI thread, so you're basically tying up that thread doing all your work and effectively negating the whole point of using a worker thread to begin with. Change RenameMethod() so that that only thing inside the Invoke block is the one thing that actually needs to be there i.e. the line that updates the progress bar.



          Better yet, start using proper data binding for your GUI controls so that you don't have to mess around with task switching at all.






          share|improve this answer
























          • Hey Mark, thanks for the answer. It was actuallly de line opening the window the one inside the Invoke, the update was in another Thread because if not, it wouldn't get updated until the end. About the better data binding, anything to expand on that?

            – Dani Lathspell Gutierrez
            Nov 26 '18 at 6:41


















          0














          The Invoke call switches over to the GUI thread, so you're basically tying up that thread doing all your work and effectively negating the whole point of using a worker thread to begin with. Change RenameMethod() so that that only thing inside the Invoke block is the one thing that actually needs to be there i.e. the line that updates the progress bar.



          Better yet, start using proper data binding for your GUI controls so that you don't have to mess around with task switching at all.






          share|improve this answer
























          • Hey Mark, thanks for the answer. It was actuallly de line opening the window the one inside the Invoke, the update was in another Thread because if not, it wouldn't get updated until the end. About the better data binding, anything to expand on that?

            – Dani Lathspell Gutierrez
            Nov 26 '18 at 6:41
















          0












          0








          0







          The Invoke call switches over to the GUI thread, so you're basically tying up that thread doing all your work and effectively negating the whole point of using a worker thread to begin with. Change RenameMethod() so that that only thing inside the Invoke block is the one thing that actually needs to be there i.e. the line that updates the progress bar.



          Better yet, start using proper data binding for your GUI controls so that you don't have to mess around with task switching at all.






          share|improve this answer













          The Invoke call switches over to the GUI thread, so you're basically tying up that thread doing all your work and effectively negating the whole point of using a worker thread to begin with. Change RenameMethod() so that that only thing inside the Invoke block is the one thing that actually needs to be there i.e. the line that updates the progress bar.



          Better yet, start using proper data binding for your GUI controls so that you don't have to mess around with task switching at all.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 26 '18 at 0:10









          Mark FeldmanMark Feldman

          8,51311738




          8,51311738













          • Hey Mark, thanks for the answer. It was actuallly de line opening the window the one inside the Invoke, the update was in another Thread because if not, it wouldn't get updated until the end. About the better data binding, anything to expand on that?

            – Dani Lathspell Gutierrez
            Nov 26 '18 at 6:41





















          • Hey Mark, thanks for the answer. It was actuallly de line opening the window the one inside the Invoke, the update was in another Thread because if not, it wouldn't get updated until the end. About the better data binding, anything to expand on that?

            – Dani Lathspell Gutierrez
            Nov 26 '18 at 6:41



















          Hey Mark, thanks for the answer. It was actuallly de line opening the window the one inside the Invoke, the update was in another Thread because if not, it wouldn't get updated until the end. About the better data binding, anything to expand on that?

          – Dani Lathspell Gutierrez
          Nov 26 '18 at 6:41







          Hey Mark, thanks for the answer. It was actuallly de line opening the window the one inside the Invoke, the update was in another Thread because if not, it wouldn't get updated until the end. About the better data binding, anything to expand on that?

          – Dani Lathspell Gutierrez
          Nov 26 '18 at 6:41




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53465399%2fhow-to-open-a-wpf-window-from-an-async-method%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

          Calculate evaluation metrics using cross_val_predict sklearn

          Insert data from modal to MySQL (multiple modal on website)