gpt4 book ai didi

c# - 在 MVVM 的主线程中更新进度条

转载 作者:太空宇宙 更新时间:2023-11-03 11:03:00 29 4
gpt4 key购买 nike

在我的应用程序中,我执行了一个很长的操作,我想显示操作的进度。在长期操作中,我使用 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.

我尝试到处寻找解决方案,但找不到。该解决方案在任何地方都在单独的线程中运行日志进程。

请告诉我我的错误在哪里以及如何解决我的问题。

您可以下载演示项目来重现问题 here

最佳答案

为什么不直接使用 View 模型中的 Application.Current.Dispatcher.Invoke()

请看一下这个示例:

MainViewModel.cs

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Threading;

namespace WpfApplication4
{
public class MainViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged
= delegate { };

private int mCounter;

public int Counter
{
get { return mCounter; }
set
{
mCounter = value;
PropertyChanged(this, new PropertyChangedEventArgs("Counter"));
}
}

/// <summary>
/// Supposed to be run from the background thread
/// </summary>
public void Start()
{
for(int i = 0; i <= 100; i++)
{
if(Application.Current == null)
{
//do not try to update UI if the main window was closed
break;
}

Application.Current.Dispatcher.Invoke(
DispatcherPriority.Background,
(Action)(() =>
{
// Long running operation in main thread
// with low priority to prevent UI freeze
Thread.Sleep(100);
Counter = i;
}));
}
}
}
}

MainWindow.xaml.cs

using System.Threading.Tasks;
using System.Windows;

namespace WpfApplication4
{
public partial class MainWindow : Window
{
private MainViewModel mainViewModel;
public MainWindow()
{
InitializeComponent();
Loaded += (sender, args) => StartOperation();
}

private void Button_Click(object sender, RoutedEventArgs e)
{
StartOperation();
}

/// <summary>
/// Start the long running operation in the background.
/// </summary>
private void StartOperation()
{
DataContext = mainViewModel = new MainViewModel();
Task.Factory.StartNew(() => mainViewModel.Start());
}
}
}

MainWindow.xaml

<Window x:Class="WpfApplication4.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">
<Grid>
<ProgressBar Height="20" Width="200" Value="{Binding Counter}" />
<Button Content="Change View model" Height="23" Margin="0,100,0,0"
HorizontalAlignment="Center"
Click="Button_Click" />
</Grid>
</Window>

关于c# - 在 MVVM 的主线程中更新进度条,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16999824/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com