我想将WPF ProgressBar的value属性绑定到在长时间运行的进程中更新的依赖项属性。如果从主线程调用长时间运行的进程,则会阻止UI(以及ProgressBar)进行更新,直到进程完成为止 - 阻止通过显示进程的所需进度。长时间运行的进程也无法通过旋转单独的线程来运行,因为无法将依赖项属性从不同的线程更新为其所有者(即创建它的线程)。
在下面的代码中,单击按钮时,长时间运行的进程会运行,进度条会在完成时从0%跳到100%。相反,我希望能够单击按钮并让进度条显示长时间运行进度的进度(即,当进程结束但显示顺利进展时,不仅仅是从0%更新到100%)。
MainWindow.xaml
<Window x:Class="ProgressBarTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<StackPanel>
<Button Width="200" Height="50" x:Name="btnRun" Click="btnRun_Click">Run Process</Button>
<ProgressBar Width="200" Height="20" x:Name="pbProgress" Minimum="0" Maximum="100" Value="{Binding Path=MyFoo.ProgressValue}"/>
</StackPanel>
</Window>
MainWindow.xaml.cs
using System.Windows;
using System.Threading;
namespace ProgressBarTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public Foo MyFoo { get; set; }
public MainWindow()
{
MyFoo = new Foo();
InitializeComponent();
}
private void btnRun_Click(object sender, RoutedEventArgs e)
{
btnRun.IsEnabled = false;
MyFoo.LongRunningProcess(); // Since this runs on same thread as UI, progress bar does not update until the long running process completes.
btnRun.IsEnabled = true;
}
}
public class Foo : DependencyObject
{
public static readonly DependencyProperty ProgressValueProperty = DependencyProperty.Register("ProgressValue", typeof(double), typeof(Foo));
public double ProgressValue
{
get { return (double)GetValue(ProgressValueProperty); }
set
{
SetValue(ProgressValueProperty, value);
}
}
public Foo()
{
ProgressValue = 0;
}
public void LongRunningProcess()
{
do
{
ProgressValue += 1;
Thread.Sleep(30);
}
while (ProgressValue < 100);
}
}
}
P.S。我知道有一种方法可以通过将ProgressBar实例作为参数传递给长时间运行的进程来实现这一点,以便它可以直接通过Dispatcher.Invoke更新它,但这不是我想要的。我希望通过绑定到依赖项属性来更新进度条。
由于
肖恩
答案 0 :(得分:2)
我会尝试比欣快更好。
您需要使用在不同线程上运行该进程的BackgroundWorker运行LongRunningProcess
,然后使用ProgressChanged事件更新属性
// This event handler updates the progress bar.
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
MyFoo.ProgressValue = e.ProgressPercentage;
}
答案 1 :(得分:2)
需要从主线程更新UI。因此,您需要使用Dispather来更新属性。
在LongRunningProcess()中使用它来将调用放在Dispatcher队列上:
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Render, new Action<double>(UpdateData), value);
并实现更新方法如下:
private void UpdateData(double value){
MyFoo.ProgressValue = value;
}
希望这有帮助。
答案 2 :(得分:1)
我不知道如果你找到了解决问题的方法,但这就是我过去解决类似问题的方法。这使您可以绑定到DP并只更新正常属性
public static readonly DependencyProperty progressProperty = DependencyProperty.Register("progress", typeof(int), typeof(this));
public int progress
{
get
{
return (int)this.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Background,
(DispatcherOperationCallback)delegate { return GetValue(progressProperty ); },
progressProperty );
}
protected set
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate { SetValue(progressProperty , value); }, value);
}
}