使用 Prism 6 (WPF) 显示耗时操作的操作进度层

Display operation progress layer for a time consuming operation using Prism 6 (WPF)

我正在开发我的第一个使用 Prism 6 的 WPF 应用程序。 单击按钮时,大约需要 1-2 分钟的操作应该开始。

我想在 window 内的所有其他控件之上显示一个半透明层,并显示操作进度和一个取消按钮,如下图和代码所示

<Window x:Class="TestingApplication.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://www.codeplex.com/prism">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Border Grid.Column="0">
            <ContentControl x:Name="NavigationItemsControl" 
                          prism:RegionManager.RegionName="MainNavigationRegion" 
                          Grid.Column="0"/>
        </Border>

        <ContentControl prism:RegionManager.RegionName="MainContentRegion" 
                        Grid.Row="1"/>

        <Grid Grid.RowSpan="2" Background="#5555">
            <Border BorderBrush="Gray" BorderThickness="1"
                    Width="400" Height="200" Background="White">
                <StackPanel Margin="10">
                    <TextBlock Text="Loading... Please wait" 
                               Margin="0,10" FontSize="18"/>
                    <ProgressBar HorizontalAlignment="Stretch" Height="40"/>
                    <Button Content="Cancel" HorizontalAlignment="Center"
                            Margin="0,10"/>
                </StackPanel>
            </Border>
        </Grid>
    </Grid>
</Window>

你能给我任何建议吗?这将是实施此功能并利用 Prism 和 MVVM 的最佳实践?

谢谢, 纳迪亚

我会使用 eventAggrgator 。

<ProgressBar HorizontalAlignment="Stretch" Height="40" Value{Binding ProgressBarValue}/>

public class ViewModel:BindableBase
{
    private readonly IEventAggregator _eventAggregator;

    public ViewModel(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;
        _eventAggregator.GetEvent<ProgressbarEvent>().Subscribe(PopulateProgress);
    }

    private void PopulateProgress(double value)
    {
        ProgressbarValue = value;
    }

    private double _progressbarValue;

    public double ProgressbarValue
    {
        get { return _progressbarValue; }
        set { SetProperty(ref(_progressbarValue),value); }
    }

//this is how you would send event
        public void SendProgress()
        {
            for (double i = 0; i < 100; i++)
            {
                _eventAggregator.GetEvent<ProgressbarEvent>().Publish(i);
            }
        }

    }
    public class ProgressbarEvent : PubSubEvent<Double> { }

确保您在执行长时间操作时处于单独的线程中。

我建议你 BusyIndicator 来自 ExtendedWPFToolkit

你的 XAML 应该是这样的:

<extToolkit:BusyIndicator IsBusy="{Binding IsBusy}" BusyContent="Processing..." >
   <extToolkit:BusyIndicator.ProgressBarStyle>
      <Style TargetType="ProgressBar">
        <Setter Property="IsIndeterminate" Value="False"/>
        <Setter Property="Height" Value="15"/>
        <Setter Property="Margin" Value="8,0,8,8"/>
        <Setter Property="Value" Value="{Binding ProgressValue}"/>
      </Style>
   </extToolkit:BusyIndicator.ProgressBarStyle>

   <ListBox ItemsSource="{Binding Persons}"/>

</extToolkit:BusyIndicator>

然后在您的 ViewModel 中实现布尔值 IsBusy 属性:

private bool isBusy;
public bool IsBusy
{
    get { return isBusy; }
    set
    {
        this.isBusy = value;
        this.OnPropertyChanged("IsBusy");
    }
}

然后添加一个 ProgressValue 属性 到你的 ViewModel:

private int progressValue ;
public int ProgressValue
{
    get { return progressValue ; }
    set
    {
        this.progressValue = value;
        this.OnPropertyChanged("ProgressValue ");
    }
}

然后将耗时操作放在BackgroundWorker class的DoWork lambda-expression中,以免冻结UI:

    BackgroundWorker worker = new BackgroundWorker();
    worker.WorkerReportsProgress = true;        
    worker.DoWork += (o, ea) =>
    {
           IsBusy = true;
           //Do your heavy work here
           worker.ReportProgress(10);

           //Do your heavy work here
           worker.ReportProgress(20);

           //And so on
    };


    worker.ProgressChanged += (o,ea) =>
    {
        ProgressValue = e.ProgressPercentage;
    };

    worker.RunWorkerCompleted += (o, ea) =>
    {
      IsBusy = false;
    };