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();
}
希望对您有所帮助!
我来自 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();
}
希望对您有所帮助!