Updating Gui (Wpf) Using a Different Thread

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



Leave a reply



Submit