UWP 使用绑定和异步函数更改加载状态

UWP Change loading state using binding and async functions

我来自 Angular 2 和 C# 后端背景,所以对于 Angular 方面的事情,我习惯于使用异步函数和代码,以及 C# 背景我了解基础库。

我正在尝试创建一个简单的页面,其中包含一个按钮和一个正在加载的 gif。您单击出现加载 gif 的按钮,10 秒后它消失。

我可以让加载开始没问题,但是异步代码的性质会跳过执行并立即使 gif 消失。

如何启动微调器/使 gif 可见,以非 ui 阻塞方式等待 10 秒,然后以线程安全的方式结束动画/gif 可见性?

查看模型代码:

public class LoadingViewModel: INotifyPropertyChanged
    {
        private Visibility _loadingState;

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        public LoadingViewModel()
        {
            this._loadingState = Visibility.Collapsed;
        }

        public Visibility LoadingState
        {
            get {
                return this._loadingState;
            }
            set {
                this._loadingState = value;
                this.OnPropertyChanged();
            }
        }

        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            // Raise the PropertyChanged event, passing the name of the property whose value has changed.
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

MainView.xaml.cs:

public LoadingViewModel LoadingViewModel { get; set; }

        public MainPage()
        {
            this.InitializeComponent();
            this.LoadingViewModel = new LoadingViewModel();
        }


        private async Task BeginLoading()
        {
            LoadingViewModel.LoadingState = Visibility.Visible;
            await Task.Factory.StartNew(() =>
            {
                Task.Delay(TimeSpan.FromSeconds(10));

            }).ContinueWith(EndLoadingState);


        }

        //Updated and works but is there a better way?
        private async Task BeginLoading()
        {
            LoadingViewModel.LoadingState = Visibility.Visible;
            await Task.Factory.StartNew(async () =>
            {
                await Task.Delay(TimeSpan.FromSeconds(10));
                await EndLoadingState(); //<-- New EndLoadingState doesn't accept parms
            });


        }

        private async void EndLoadingState(object state)
        {
            await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
                LoadingViewModel.LoadingState = Visibility.Collapsed;
            });
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            await BeginLoading();
        }

最后是带有我的按钮和图像的基本堆栈面板:

<StackPanel Margin="10,144,0,144">
            <Button Content="Begin Loading for 10 seconds" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0" Height="157" Width="366" FontSize="22" Background="{x:Null}" BorderThickness="5" BorderBrush="#FF58FF00" Click="Button_Click"/>
            <Image HorizontalAlignment="Center" Height="250" VerticalAlignment="Center" Width="250" Margin="0,25,0,0" Stretch="UniformToFill" Source="Assets/LoadingBubbles.gif" Visibility="{x:Bind Path=LoadingViewModel.LoadingState, Mode=TwoWay}"/>
        </StackPanel>

首先,尝试在 LoadingViewModel 中使用 bool 属性 而不是 Visibility,因为后者是 UI 属性。您通常不希望在 ViewModel 中使用它。如果您的 Windows10 目标版本是 14393 或更高版本,您可以直接绑定它而无需 BoolToVisibilityConverter。而且绑定也不需要 TwoWay

 Visibility="{x:Bind Path=LoadingViewModel.IsLoading, Mode=OneWay}"

其次,XAML 绑定实际上负责将更新后的值分派到 UI 线程。所以你也可以摆脱 Dispatcher.RunAsync 并有一个正常的 void 方法

private void EndLoadingState(object state)
{
    LoadingViewModel.IsLoading = false;
}

最后,你的BeginLoading方法(最好重命名为BeginLoadingAsync)可以简化为

private async Task BeginLoadingAsync()
{
    LoadingViewModel.IsLoading = true;

    await Task.Delay(TimeSpan.FromSeconds(10));

    EndLoadingState();
}

希望对您有所帮助!