C#MVVM中的简单进度条

  • 本文关键字:简单 C#MVVM c# wpf mvvm
  • 更新时间 :
  • 英文 :


我在公司使用LabVIEW,希望更改为C#MVVM。在我的自学之旅中,当我偶然发现一些在LabVIEW中很容易完成但在C#中根本无法完成的事情时,我觉得自己完全是个白痴。

在了解了MVVM的基本知识后,我现在正试图获得一个简单的进度条,显示1000毫秒间隔内的更新,直到完全更新。但当执行以下代码时,窗口显示一个空的进度条,4秒后跳到最终值100。

我认为我的一些基本编程原理是错误的,所以如果你能帮我,我将不胜感激。提前感谢!!

以下是代码:

主窗口.xaml

<Window x:Class="MicrosoftMVVMToolkit_Sandbox.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MicrosoftMVVMToolkit_Sandbox"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ProgressBar Width="500" Height="10" Value="{Binding Progress}" Minimum="0" Maximum="100"></ProgressBar>
</Grid>

主窗口.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Toolkit.Mvvm;
namespace MicrosoftMVVMToolkit_Sandbox
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ViewModel vm = new ViewModel();

public MainWindow()
{
InitializeComponent();
this.DataContext = vm;
this.Show();
vm.Work();
}
}
}

ViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Toolkit.Mvvm;
using Microsoft.Toolkit.Mvvm.ComponentModel;
namespace MicrosoftMVVMToolkit_Sandbox
{
class ViewModel : ObservableObject
{
private int progress;
public int Progress
{
get => progress;
set => SetProperty(ref progress, value);
}
public void Work()
{
Progress = 0;
System.Threading.Thread.Sleep(1000); 
Progress = 25;
System.Threading.Thread.Sleep(1000);
Progress = 50;
System.Threading.Thread.Sleep(1000); 
Progress = 75;
System.Threading.Thread.Sleep(1000);
Progress = 100;
}
}
}

==============================

解决方案1-等待任务。延迟选项:

以下是wait Task.Delay选项的示例代码,以防其他人有同样的问题:

public async void Work()
{          
Progress = 0;
await Task.Delay(1000);
Progress = 25;
await Task.Delay(1000);
Progress = 50;
await Task.Delay(1000);
Progress = 75;
await Task.Delay(1000);
Progress = 100;
}

这里的主要问题是进度条只有在UI线程没有被阻塞时才能更新。也就是说,它正在处理windows消息。然而,Thread.Sleep会阻塞UI线程,阻止它执行任何其他工作,包括绘制进度条。

有几种可能的解决方案

  • 使用异步方法并使用await Task.Delay(1000)而不是Thread.Sleep。这将允许UI线程在等待时执行其他工作。但是,如果您需要做任何处理密集型的工作,它将不起作用
  • 在后台线程上运行您的工作,例如使用Task.Run。但这会导致下一个问题:不允许从后台线程更新任何UI控件。为此,有两种解决方案:
    • 使用Dispatcher.BeginInvoke从UI线程更新Progress属性。(或在UI线程上运行代码的任何等效方法(
    • 从后台线程更新进度字段,但使用单独的计时器引发progress属性的OnPropertyChanged事件。计时器应该是在UI线程上运行的计时器,如DispatchTimer。这样做的优点是允许频繁更新进度,而不会向UI线程发送垃圾邮件

在构造函数中:

public MainWindow()
{
InitializeComponent();
this.DataContext = vm;
this.Show();
vm.Work();
}

vm.Work()阻止代码执行4秒(每次调用System.Threading.Thread.Sleep(1000)(这使得UI对那段时间不负责任。

您需要使用一些非阻塞工具(如DispatcherTimer(更改进度条Progress

示例:

// remove vm.Work() from constructor
// add private field in MainWindow
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
// add in constructor
dispatcherTimer.Tick += dispatcherTimer_Tick;
dispatcherTimer.Interval = new TimeSpan(0,0,1);
dispatcherTimer.Start();
// add private method in MainWindow
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
vm.Progress += 1;
}

我没有测试这个代码。

最新更新