How to open a WPF window from an async method
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
add a comment |
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
add a comment |
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
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
c# wpf asynchronous progress-bar showdialog
edited Nov 25 '18 at 7:24
Dani Lathspell Gutierrez
asked Nov 25 '18 at 7:08
Dani Lathspell GutierrezDani Lathspell Gutierrez
34
34
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
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.
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
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
add a comment |
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.
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
add a comment |
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.
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.
answered Nov 26 '18 at 0:10
Mark FeldmanMark Feldman
8,80711838
8,80711838
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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