在我的应用程序中,我执行了一个长时间的操作,我想显示操作的进度。在长时间操作中,我使用 3rd-party dll。不幸的是,该 dll 不支持来自非主线程的调用。所以我不能使用另一个线程来启动我的进程。
我找到了一种使用 Dispather 在主线程中更新进度条的方法。起初我写了一个简单的 WPF 应用程序,并在代码隐藏中编写了简单的方法。
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
for (int i = 0; i <= 100; i++)
{
Dispatcher.Invoke(DispatcherPriority.Loaded,
(Action)(() =>
{
pb.Value = i;
}));
Thread.Sleep(10);
}
}
这段代码工作正常。我在窗口中看到了进度。但是我使用MVVM的问题,所以我不能使用这种方法。
为了解决我的问题,我创建了 AttachedProperty
internal class ProgressBarAttachedBehavior
{
public static readonly DependencyProperty ValueAsyncProperty =
DependencyProperty.RegisterAttached("ValueAsync",
typeof (double),
typeof (ProgressBarAttachedBehavior),
new UIPropertyMetadata(default(double), ValueAsyncChanged));
private static void ValueAsyncChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var pb =
d as ProgressBar;
if (pb == null)
{
return;
}
var dispatcher =
d.Dispatcher;
//if (dispatcher == null || dispatcher.CheckAccess())
//{
// pb.Value = (double) e.NewValue;
//}
//else
{
DispatcherFrame frame =
new DispatcherFrame(true);
var dispatcherOperation = dispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(() =>
{
pb.Value = (double)e.NewValue;
frame.Continue = false;
})
);
Dispatcher.PushFrame(frame);
}
}
public static void SetValueAsync(ProgressBar progressBar, double value)
{
progressBar.SetValue(ValueAsyncProperty, value);
}
public static double GetValueAsync(ProgressBar progressBar)
{
return (double)progressBar.GetValue(ValueAsyncProperty);
}
在 XAML 我写
<ProgressBar tesWpfAppMvvm:ProgressBarAttachedBehavior.ValueAsync="{Binding Progress}"/>
还有我的 ViewModel 代码
class Workspace1ViewModel : WorkspaceViewModel
{
private ICommand _startCommand;
private double _progress;
public ICommand StartCommand
{
get
{
if (_startCommand == null)
{
_startCommand =
new RelayCommand(Start);
}
return _startCommand;
}
}
private void Start()
{
for (int i = 0; i <= 100; i++)
{
Progress = i;
Thread.Sleep(20);
}
}
public double Progress
{
get
{
return _progress;
}
set
{
_progress = value;
RaisePropertyChanged(() => Progress);
}
}
}
代码工作正常。长进程在主线程中运行,我在窗口中看到进度。
但是问题是,当我将我的 Active ViewModel 更改为另一个模型时,我得到了错误:
Cannot perform this operation while dispatcher processing is suspended.
我试图在任何地方找到解决方案,但找不到。解决方案在任何地方都在单独的线程中运行日志进程。
请告诉我我的错误在哪里以及如何解决我的问题。
您可以在此处下载演示项目以重现该问题