How to update UI in WPF application from thread?
Use a blocking invoke to update UI on the main thread. This way, the thread will wait for the update to finish, and then continue. You were invoking in a non-blocking async way, which probably flooded the main thread and that's why it froze.
System.Windows.Application.Current.Dispatcher.Invoke(delegate{
// update UI
});
Update C# WPF GUI when different thread and library variable change
I found an answer how to do it. I couldn't work out why my Observers does not catch update but I manage to do it using delegators.
On the main calculation thread, I create a method that dispatch update to GUI thread:
public void SuperStepProgressMethod(Dictionary<string, string> stepDictionary)
{
DispatcherHelper.CheckBeginInvokeOnUI(
() =>
{
// Set step item list
StepItems = StepProgressHandler.UpdateStepList(stepDictionary);
});
}
After that when I am calling Project method I delegate MainViewModel method as an action to it.
public static void Run(
Action<Dictionary<string, string>> superStepProgressMethod)
{
ProgressStageDictionary["Data Initiation"] = Initiation();
superStepProgressMethod.Invoke(ProgressStageDictionary);#
}
Using this solution behind the scene threads are updating/running at following order:
GUI Thread -> Calculation Thread -> Separate Project Thread -> GUI Thread
C# .NET 5.0 Wpf UI modified by another thread
You need to use BeginInvoke method. Something in the line of:
.....
while (!streamReader.EndOfStream)
{
var stream = await streamReader.ReadLineAsync();
if (stream.ToString() == "update")
{
var dispatcher = Application.Current.MainWindow.Dispatcher;
dispatcher.BeginInvoke(new Action(() =>
{
//update the WPF UI
}), (DispatcherPriority)10);
}
}
break; ///if UI Updated exit the while true loop
.....
Also, as a side note, don't every swallow exceptions. Log or/and handle the exception on catch block
Bindings and updating from another thread
It's perfectly legal to set a source property on a background thread. The framework handles the marshaling for you under the hood.
If you however try to add or remove items from a source collection, it's a different story:
How to update only a property in an observable collection from thread other than dispatcher thread in WPF MVVM?
Target properties, or more exactly properties of DependencyObjects
, can only be accessed on the thread on which the object was originally created though. But you don't need to use a dispatcher to set view model properties from a background thread.
C# - WPF - Updating the UI from another class on another Thread
Assuming that ProcessClass is your own code that you can update, change the signiture of DoDomething()
to
public async Task DoSomething(IProgress<string> progress)
{
progress.Report("Begin DoSomething()");
var counter = 0;
for(var i = 1; i < 100; i++)
{
counter += i;
await Task.Delay(100).ConfigureAwait(false);
progress.Report($"DoSomething() - i = {i}");
}
progress.Report($"DoSomething() Completed, answer is {counter}");
}
Now your button click handler can be written
private async void btnStart_Click(object sender, RoutedEventArgs e)
{
// usually you would update some other control such as a TextBlock
// for the feedback, rather than the button content
var progress = new Progress<string>(s => btnStart.Content = s);
ProcessClass processClass = new ProcessClass();
await processClass.DoSomething(progress).ConfigureAwait(false);
}
Cannot update UI from another thread in WPF
You should freeze the BitmapImage
by calling its Freeze()
method in order to be able to use it on another thread than the one on which it was created:
new Thread(() =>
{
BitmapImage bitmapImage = ThreadProcedure();
bitmapImage.Freeze(); //<--
this.Dispatcher.Invoke(new Action(() => {
pbStatus.Visibility = Visibility.Hidden;
EditedImage.Source = bitmapImage;
}));
}).Start();
Multiple threads tasks updating 1 progressbar - UI C# WPF
You could use either the Parallel
class or the PLINQ library to process the items in parallel, using multiple ThreadPool
threads. For reporting the progress to the UI you could use the IProgress<T>
abstraction, where T
can be any type of your choice. For example it could be a ValueTuple<string, bool>
, in order to communicate both the processed item, and the success/failure of the operation. This way you could create an application-agnostic, library-like method. You could copy-paste this method verbatim in a completely different application (a Console app for example), and it would work exactly the same without any modification. Below is an example of such a method, that uses the PLINQ library for handling the parallelism:
public static string[] ProcessAllItems(string[] items, string baseUrl,
IProgress<(string, bool)> progress)
{
return items
.AsParallel()
.AsOrdered()
.WithDegreeOfParallelism(4)
.Select(item =>
{
HttpRequest req = new HttpRequest();
req.Proxy = null;
req.ConnectTimeout = 5000;
req.IgnoreProtocolErrors = true;
var response = req.Get(baseUrl + url);
if (response.StatusCode == Leaf.xNet.HttpStatusCode.OK)
{
progress.Report((item, true)); // Success
return item;
}
progress.Report((item, false)); // Failure
return null;
})
.Where(result => result != null)
.ToArray();
}
Then all that you'll have to do is to create a Progress<(string, bool)>
object on the UI thread, and pass a delegate that handles the reported messages from the background thread. This delegate should update both the myResults
and progressbar
UI elements. Calling the ProcessAllItems
should be wrapped in an await Task.Run
, in order to keep the UI responsive.
private async void startButton_Click(object sender, RoutedEventArgs e)
{
string baseUrl = myURL.Text;
string[] items = myLoadedList.Items.Select(x => x.ToString()).ToArray();
var completedCount = 0;
var progress = new Progress<(string, bool)>(message =>
{
if (message.Item2)
{
myResults.Items.Add(message.Item1);
}
completedCount++;
progressbar.Value = completedCount * 100 / items.Length;
});
progressbar.Value = 0;
myResults.Items.Clear();
myResults.Items.Add("----Starting----");
string[] results = await Task.Run(() =>
{
return ProcessAllItems(items, baseUrl, progress);
});
progressbar.Value = 100;
myResults.Items.Add("----Finish----");
}
Notice the async
keyword in the startButton_Click
handler, that enables the use of the await
operator.
The main point of this suggestion is to avoid using the awkward Dispatcher.Invoke
method, that encourages intermingling the processing logic with the presentation logic, as well as the technologically obsolete BackgroundWorker
class.
WPF Update UI From Background Thread
You are overriden the main window. You should not do that. Just create a new instance of it and call Show()
.
public ICommand ShowSettingsCommand => new DelegateCommand
{
CommandAction = () =>
{
var settingsWindow = = new Views.SettingsWindow( _logger, _hidservice, _certificateService );
settingsWindow.Show();
}
};
Related Topics
Any Faster Way of Copying Arrays in C#
.Net Events for Process Executable Start
Starting Tasks in Foreach Loop Uses Value of Last Item
How to Get the Currently-Logged Username from a Windows Service in .Net
How to Get Printer Info in .Net
Example Ajax Call Back to an ASP.NET Core Razor Page
How to Use a String to Create a Ef Order by Expression
Deserializing Dates with Dd/Mm/Yyyy Format Using JSON.Net
When Do Static Variables Get Initialized in C#
How to Display a Popup from a Webbrowser in Another Window I Created
Cause of Error Cs0161: Not All Code Paths Return a Value
Adding Items to a List<> of Objects Results in Duplicate Objects When Using a New in a Loop
ASP.NET Core 1.0 on Iis Error 502.5
Operator Overloading with C# Extension Methods
C# "Parameter Is Not Valid." Creating New Bitmap
C# Webbrowser Control - Form Submit Not Working Using Invokemember("Click")