如何在视图模型重新加载绑定数据时显示“正在加载...”覆盖

hya*_*kov 6 wpf xaml adorner

我想做一些听起来非常简单的事情,但我发现很难做到。

假设我有一些内容与缓慢加载操作有关。例如,从本地 SQL 检索到的可观察列表需要几秒钟。在发生这种情况时,我想Groupbox用“正在加载...”文本或任何其他“请稍候”类型的内容覆盖内容演示者(例如 a )。

我很快得出结论,在操作前后简单地切换绑定到 UI 的布尔标志是行不通的。在整个操作完成之前,UI 不会刷新。可能是因为操作是CPU密集型的,我不知道。

我现在正在研究Adorners,但是我在“繁忙指标”覆盖的上下文中搜索它时提供的信息很少。互联网上只有一些解决方案,大约 5 年前,我无法让其中任何一个工作。

问题:

听起来很简单 - 如何在视图模型正在更新绑定数据的同时在屏幕上临时显示某些内容?

mm8*_*mm8 6

我很快得出结论,在操作前后简单地切换绑定到 UI 的布尔标志是行不通的。在整个操作完成之前,UI 不会刷新。可能是因为操作是CPU密集型的,我不知道。

是的,它应该可以工作,前提是您实际上是在后台线程上执行长时间运行的操作。

请参考以下简单示例。

看法:

<Window x:Class="WpfApplication2.Window1"
        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:WpfApplication2"
        mc:Ignorable="d"
        xmlns:s="clr-namespace:System;assembly=mscorlib"
        Title="Window1" Height="300" Width="300">
    <Window.DataContext>
        <local:Window1ViewModel />
    </Window.DataContext>
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    </Window.Resources>
    <Grid>
        <TextBlock>Content...</TextBlock>
        <Grid Background="Yellow" Visibility="{Binding IsLoading, Converter={StaticResource BooleanToVisibilityConverter}}">
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Loading...</TextBlock>
        </Grid>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

查看型号:

public class Window1ViewModel : INotifyPropertyChanged
{
    public Window1ViewModel()
    {
        IsLoading = true;
        //call the long running method on a background thread...
        Task.Run(() => LongRunningMethod())
            .ContinueWith(task =>
            {
                //and set the IsLoading property back to false back on the UI thread once the task has finished
                IsLoading = false;
            }, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
    }

    public void LongRunningMethod()
    {
        System.Threading.Thread.Sleep(5000);
    }

    private bool _isLoading;
    public bool IsLoading
    {
        get { return _isLoading; }
        set { _isLoading = value; NotifyPropertyChanged(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
Run Code Online (Sandbox Code Playgroud)