【问题标题】:WPF ProgressBar Visibility with MVVM does not WorkMVVM 的 WPF ProgressBar 可见性不起作用
【发布时间】:2015-09-30 13:58:47
【问题描述】:

我有一个显示两个日期之间的记录列表的 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
    }

提前谢谢你。

【问题讨论】:

  • 这很可能是因为您在主线程上执行了长时间的操作。 DoItWithStoredProcedure 是做什么的?执行是否需要大量时间?如果是这样,您将希望将该操作移至后台线程。
  • 该任务大约需要 1 秒,大约 19000 条记录。它在一段时间内从按日期索引的 sql server 2012 表中执行选择查询
  • 它是否触及转换器的 Convert 方法?
  • 照 mittmemo 说的做。在检索记录时,UI 被冻结。您还可以签出异步命令here。您希望等待 DoItWithStoredProcedure() 以便在 SP 运行时 UI 可以更新。
  • @HabibGherairi 我编辑了我的答案。阅读和理解它应该比其他答案更直观和简单。我建议在未来的项目/任务中避免遵循 Anjum 的答案中显示的相同模式。

标签: wpf mvvm


【解决方案1】:

公认的答案是他们在过去(.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

证明:

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

【讨论】:

  • 抱歉投反对票,但您的代码的问题是 TaskInProgress 将始终为 false,因为 DoItWithStoredProcedure() 将异步执行,因此在您的任务语句控制继续到 TaskInProgress = false; .我们可以转移 TaskInProgress = false;也可以使用 DoItWithStoredProcedure(),但作为一种设计选择,我选择了事件处理模式,因为它更直观。
  • @AnjumSKhan 修改我编辑的答案,如果您决定不更改投票,请发表评论。没有发表评论的投票者也是如此。
  • @NetScape 抱歉迟到了。我试过你的代码,它措辞完美,更优雅。谢谢。
  • @NETscape SO 的所有用户都会不断更改他们的错误答案,这样就不会有任何错误答案,也不会有任何反对意见。一旦问题所有者检查并在您的 cmets 之后,请参阅我没有更改我的答案。我在发布之前检查我的答案。你的第一个答案是完全错误的。现在谁疯了?
  • @AnjumSKhan 好吧,如果他们更改的答案比接受的答案和原始答案更好,谁在乎?我们在这里提供好的答案,而不是向其他人展示如何不这样做。如果您要投诉,请删除您的答案。有趣的是,在接受的答案发生变化之前,您没有回复我的评论。
【解决方案2】:

您需要进行异步处理,因为一旦完成功能处理,所有 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();这可以做到,但不是好的做法。我们当前的模式使用通知之类的事件,并通知我们长时间运行的任务完成。

【讨论】:

  • 检查你的转换器,你为什么使用 collapse ?我看不到它被设置在某个地方。简单的 bool bValue = (bool)value; if (bValue) 返回 Visibility.Visible;否则返回 Visibility.Hidden;应该足够了。然后在您的进度条绑定中,不需要 UpdateSourceTrigger,因为 Mode 是 OneWay。
  • 还要检查 RaisePropertyChanged("TaskInProgress"); 的实现;替换 DoItWithStoredProcedure();在你的代码中使用 for(long i=1;i
  • 对于折叠属性,我按如下方式编辑我的代码 并且仍然无法正常工作。对于 RaisePropertyChanged,它包含在 MVVMLight 中
【解决方案3】:

@Habib Gherairi, 为避免阻塞 UI,您可能需要在绑定中添加“IsAsync=True”:

<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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    相关资源
    最近更新 更多