Dispatcher.Yied() 上是否没有刷新 WPF DataBindings?
Are WPF DataBindings not refreshed on Dispatcher.Yied()?
所以,我有一个在 UI 线程上做一些长时间工作的大型应用程序。我知道这是糟糕的设计,但这无法更改。以此为约束。
为了显示工作进度,我想显示一个带有进度条的 WPF 对话框。该对话框为其标签和进度条使用 DataBindings 到 DependencyProperties。
当我第一次在对话框实例上调用 Show()
时,对话框不会显示,因为 Dispatcher 正忙于处理较长的 运行 任务。所以我在Show()
之后调用了Dispatcher.Yield()
。我还在每次更新进度条的 DependencyProperty 后调用 Yield()
。对话框 windows 出现了,但它仍然很空。 DataBindings 未在 Dispatcher.Yield()
.
上更新
在 Dispatcher 忙碌的时候我是否有机会让他们更新?
示例应用程序
创建一个新的 .NET Framework WPF 应用程序,将其命名为 'BusyProgress' 并更改这些文件。
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");
}
}
}
构建示例有助于认识到 this answer 实际上就足够了。
我的应用程序还有另一个我以前没有意识到的限制。 Dispatcher 已禁用 -.-...感谢 sintar 的帮助!
所以,我有一个在 UI 线程上做一些长时间工作的大型应用程序。我知道这是糟糕的设计,但这无法更改。以此为约束。
为了显示工作进度,我想显示一个带有进度条的 WPF 对话框。该对话框为其标签和进度条使用 DataBindings 到 DependencyProperties。
当我第一次在对话框实例上调用 Show()
时,对话框不会显示,因为 Dispatcher 正忙于处理较长的 运行 任务。所以我在Show()
之后调用了Dispatcher.Yield()
。我还在每次更新进度条的 DependencyProperty 后调用 Yield()
。对话框 windows 出现了,但它仍然很空。 DataBindings 未在 Dispatcher.Yield()
.
在 Dispatcher 忙碌的时候我是否有机会让他们更新?
示例应用程序
创建一个新的 .NET Framework WPF 应用程序,将其命名为 'BusyProgress' 并更改这些文件。
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");
}
}
}
构建示例有助于认识到 this answer 实际上就足够了。
我的应用程序还有另一个我以前没有意识到的限制。 Dispatcher 已禁用 -.-...感谢 sintar 的帮助!