So, I have this big application that does some long work on the UI Thread. I know it's bad design, but this can't be changed. Thake it as a constraint.
To show the progress of the work, I want to show a WPF dialog with a progressbar. The dialog is using DataBindings to DependencyProperties for its labels and the progressbar.
When I first called Show() on the dialog instance, the dialog wouldn't be displayed, because the Dispatcher is busy working on the long running task. So I called Dispatcher.Yield() after Show(). I also call Yield() after each update of the DependencyProperty of the progressbar. The dialog windows is showing up, but it's still very empty. The DataBindings are not updated on Dispatcher.Yield().
Is there any chance I can get them to update while the Dispatcher is busy?
Example App
Create a new .NET Framework WPF App, name it 'BusyProgress' and change these files.
MainWindow.xaml
<Window x:Class="BusyProgress.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BusyProgress"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="window"
Title="MainWindow"
Width="400"
Height="100"
mc:Ignorable="d">
<DockPanel DataContext="{Binding ElementName=window}">
<ProgressBar Height="20"
DockPanel.Dock="Bottom"
Maximum="10"
Value="{Binding Progress}" />
<TextBlock Text="{Binding LabelText}" />
</DockPanel>
</Window>
MainWindow.xaml.cs
using System.Windows;
namespace BusyProgress
{
public partial class MainWindow : Window
{
public string LabelText
{
get => (string)GetValue(LabelTextProperty);
set => SetValue(LabelTextProperty, value);
}
public static readonly DependencyProperty LabelTextProperty =
DependencyProperty.Register("LabelText", typeof(string), typeof(MainWindow), new PropertyMetadata("Initial Value"));
public int Progress
{
get => (int)GetValue(ProgressProperty);
set => SetValue(ProgressProperty, value);
}
public static readonly DependencyProperty ProgressProperty =
DependencyProperty.Register("Progress", typeof(int), typeof(MainWindow), new PropertyMetadata(0));
public MainWindow()
{
InitializeComponent();
}
}
}
App.xaml
<Application x:Class="BusyProgress.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="Application_Startup" />
App.xaml.cs
using System.Windows;
using System.Windows.Threading;
using System.Threading;
using System;
namespace BusyProgress
{
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
MainWindow window = new MainWindow();
window.LabelText = "Init";
window.Show();
Dispatcher.Yield();
// Do some long running stuff
int count = 0;
while (count++ < 10)
{
Console.WriteLine(count);
window.Progress = count;
window.LabelText = $"Working hard... ({count}/10)";
Dispatcher.Yield();
// Simulate Work
Thread.Sleep(500);
}
MessageBox.Show("Done");
}
}
}