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");
}
}
}