UWP使用绑定和异步功能更改加载状态

时间:2017-08-02 20:14:43

标签: asynchronous uwp uwp-xaml ui-thread

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

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

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

如何启动微调器/使gif可见,以非ui-blocking方式等待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>

1 个答案:

答案 0 :(得分:3)

首先,尝试在bool而不是LoadingViewModel中使用Visibility属性,因为后者是UI属性。您通常不希望在 ViewModel 中使用它。如果您的目标Windows 10版本是 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();
}

希望这有帮助!