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

时间:2016-03-30 12:40:59

标签: wpf mvvm prism

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

我想在窗口内的所有其他控件的顶部显示一个半透明图层,并显示操作进度和取消按钮,如下面的图像和代码所示

enter image description here

<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的最佳实践?

谢谢你, 纳迪亚

2 个答案:

答案 0 :(得分:2)

我会使用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> { }

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

答案 1 :(得分:0)

我建议您ExtendedWPFToolkit BusyIndicator

你的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");
    }
}

然后向ViewModel添加ProgressValue属性:

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

然后在DoWork类的BackgroundWorker lambda表达式中放置耗时的操作,以便不冻结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;
    };