使用MVVM的WPF ProgressBar可见性不起作用

时间:2015-09-30 13:58:47

标签: wpf mvvm

我有一个WPF窗口,显示两个日期之间的记录列表。我用它:MVVM Light,实体框架和存储过程。

当我运行命令显示列表时,我想显示一个进度条以指示任务正在运行。查询完成后,我想隐藏进度条。 问题是进度条的可见性不能很好地工作。以下是我的代码:

//XAML 
.
.
.
.
<StatusBar Grid.Row="2">

        <StatusBarItem Width="300">
            <TextBlock Text="{Binding SBMessage, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
        </StatusBarItem>

        <StatusBarItem Width="Auto">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="Requête en cours..." Visibility="{Binding TaskInProgress, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource booltovisibility}}" />
            <ProgressBar 
                Visibility="{Binding TaskInProgress, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource booltovisibility}}" 
                Width="100" 
                Height="20" 
                IsIndeterminate="True"
                VerticalAlignment="Center"
                Grid.Column="1"
                />
            </Grid>

        </StatusBarItem>

    </StatusBar>


 //ViewModel

 bool _taskinprogress = false;
  public bool TaskInProgress
    {
        get { return _taskinprogress; }
        set
        {
            _taskinprogress = value;
            RaisePropertyChanged("TaskInProgress");
        }
    }

  public RelayCommand DisplaySimulationsListCommand
    {
        get
        {
            if (_splist == null)
                _splist = new RelayCommand(DisplaySimulationsListCommandExecute);
            return _splist;
        }
    }




    private void DisplaySimulationsListCommandExecute()
    {
        SBMessage = "Exécution...";
        TaskInProgress = true;
        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();
        DoItWithStoredProcedure();
        stopWatch.Stop();
        TimeSpan ts = stopWatch.Elapsed;
        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
        ts.Hours, ts.Minutes, ts.Seconds,
        ts.Milliseconds / 10);
        SBMessage = ListSimulations.Count().ToString() +  " Enregistrement(s) en : " + elapsedTime;
        CurrentDisplayedTab = 1;
        TaskInProgress = false;

        //SBMessage = "Prêt";
    }






    private void DoItWithStoredProcedure()
    {

        try
        {

            using (UnitOfWork cx = new UnitOfWork())
            {
                var ls = cx.GetSimulationsPeriode(VMPeriode.Debut, VMPeriode.Fin).AsReadOnly();
                ListSimulations = new ObservableCollection<Simulation>(ls);
                CVS = (ListCollectionView)CollectionViewSource.GetDefaultView(ListSimulations);
                RaisePropertyChanged("CVS");
            }
        }

        catch (Exception ex)
        {
            Messenger.Default.Send<ExceptionMessageRefresh>(new ExceptionMessageRefresh(ex), "DoItWithStoredProcedure");
        }
    }

//Converter
  public class BoolToVisiblityConverter : IValueConverter
    {
        #region Constructors
        /// <summary>
        /// The default constructor
        /// </summary>
        public BoolToVisiblityConverter() { }
        #endregion


        public bool Collapse { get; set; }

        #region IValueConverter Members
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool bValue = (bool)value;
            if (bValue)
                return Visibility.Visible;
            else
            {
                if (Collapse)
                    return Visibility.Collapsed;
                else
                    return Visibility.Hidden;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Visibility visibility = (Visibility)value;

            if (visibility == Visibility.Visible)
                return true;
            else
                return false;
        }
        #endregion
    }

提前谢谢。

3 个答案:

答案 0 :(得分:3)

接受的答案是他们过去是如何做到的(在.NET Framework 4之前),当时孩子们必须走上坡/上学。这是一个更易读的解决方案,不需要大量的代码(感谢.NET Framework 4 / 4.5)。

private void DoItWithStoredProcedure()
{
    //Do your normal SP stuff here
    //Instead, I mocked a synchronous method 
    Thread.Sleep(1000);
    Console.WriteLine("Completed");
}

private void DisplaySimulationsListCommandExecute()
{
    //Do stuff 
    Console.WriteLine("Started");
    TaskInProgress = true;
    Task.Run(() => DoItWithStoredProcedure())
        .ContinueWith( task => { TaskInProgress = false; });
    Console.WriteLine("Finished");
    //Do the rest of your stuff
}

输出:

Started   //Showed the ProgressBar animation 
Finished  //Task.Run was hit
Completed //ProgressBar became collapsed after ContinueWith is hit

证明:

Working example

正如您所看到的,您可以亲眼看到,这种被广泛接受的使用Task.RunContinueWith的方法是一个单行解决方案,可以很容易地阅读和理解。

答案 1 :(得分:0)

您需要进行异步处理,因为完成功能完成处理后,所有UI级别更改都将可用。在正常情况下,处理时间可以忽略不计,因此这种情况并不明显。

建议的更改:

// suggested changes start //
            delegate void LongTaskDelegate();
            private void DoItWithStoredProcedureAsync()
            {
                LongTaskDelegate del = new LongTaskDelegate(DoItWithStoredProcedure);
                AsyncCallback callback = new AsyncCallback(LongTaskFinishedCallback);
                IAsyncResult result = del.BeginInvoke(callback, null);
            }
            private void LongTaskFinishedCallback(IAsyncResult result)
            {
                TaskInProgress = false;
                ... some extra work
            }
// suggested changes end //    
            private void DisplaySimulationsListCommandExecute()
            {
                ...

                TaskInProgress = true;                    

                // call our new method declared above
                DoItWithStoredProcedureAsync();                     
            }

如果我们使用async / await模式,那么没有像通知那样的事件,我们必须用TaskInProgress = false污染我们的DoItWithStoredProcedure();这可以做但不是好的做法。我们当前的模式使用诸如通知之类的事件,并通知我们长期运行的任务完成。

答案 2 :(得分:0)

@Habib Gherairi, 为避免阻止用户界面,您可能需要添加&#39; IsAsync = True&#39;你的装订:

<ProgressBar Visibility="{Binding TaskInProgress, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource booltovisibility}, IsAsync=True}" IsIndeterminate="True" /

https://msdn.microsoft.com/en-us/library/system.windows.data.binding.isasync(v=vs.110).aspx

  

当绑定源属性的get访问器可能需要很长时间时,请使用IsAsync属性。一个示例是具有从Web下载的get访问器的图像属性。将IsAsync设置为true可避免在下载时阻止UI。

相关问题