|
需求描述 •在ViewModel中处理Model中的数据需要一定时间的等待 •ViewModel或Model在获取数据或访问同步服务时有一定延迟需要等待 •ViewModel操作View加载数据需要一段时间 解决办法 •显示一个等待UI,当数据处理完毕或服务接口返回后等待UI消失 转动齿轮控件 •参考开源实现SprocketControl :http://wpfspark.codeplex.com/ 等待控件
<Grid> <local:SprocketControl Grid.Row="0" Grid.Column="0" Width="100" Height="100" Margin="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Background="Transparent" Interval="60" IsIndeterminate="True" StartAngle="-90" TickColor="{DynamicResource MaskForegroundColor}" TickCount="16" TickWidth="5" /> </Grid>
等待效果

定义MVVM中的ViewModel的状态
/// <summary> /// 在MVVM模式中ViewModel的状态 /// </summary> [Flags] public enum ViewModelStatus { /// <summary> /// ViewModel无状态 /// </summary> None = 0x0, /// <summary> /// ViewModel正在初始化 /// </summary> Initializing = 0x1, /// <summary> /// ViewModel初始化完毕 /// </summary> Initialized = 0x2, /// <summary> /// ViewModel正在加载 /// </summary> Loading = 0x4, /// <summary> /// ViewModel加载完毕 /// </summary> Loaded = 0x8, /// <summary> /// ViewModel正在保存 /// </summary> Saving = 0x16, /// <summary> /// ViewModel保存完毕 /// </summary> Saved = 0x32 }
ViewModel状态转变为控件状态
public class StatusToAnimationVisibilityConverter : IValueConverter { #region IValueConverter Members
public object Convert( object value, Type targetType, object parameter, CultureInfo culture) { try { string status = value.ToString();
switch (status) { case "Initializing": case "Loading": case "Saving": return Visibility.Visible; case "Loaded": case "Saved": default: return Visibility.Collapsed; } } catch (Exception) { return Visibility.Collapsed; } }
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture) { return DependencyProperty.UnsetValue; }
#endregion }
使UserControl支持异步显示
<coverters:StatusToAnimationVisibilityConverter x:Key="StatusToAnimationVisibilityConverter" />
<Style x:Key="AsyncWorkUserControlStyle" TargetType="{x:Type UserControl}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type UserControl}"> <Grid> <ContentPresenter Panel.ZIndex="0" /> <Grid x:Name="animationGrid" Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Panel.ZIndex="2000" Visibility="{Binding Path=Status, Converter={StaticResource StatusToAnimationVisibilityConverter}}"> <Grid Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Panel.ZIndex="0" Background="{DynamicResource MaskGridBackgroundBrush}" Opacity="0.2" /> <ctrl:WaitingControl x:Name="animation" Panel.ZIndex="1" /> </Grid> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
应用Style至UserControl
<UserControl x:Class="DeviceConfiguration.Views.CameraManagementView" 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" d:DesignHeight="318" d:DesignWidth="632" Style="{DynamicResource AsyncWorkUserControlStyle}" mc:Ignorable="d"> </UserControl>
定义基础ViewModel
/// <summary> /// 响应式的ViewModel模型 /// </summary> public abstract class ViewModelResponsive : ViewModelBase, IViewModelResponsive { #region Fields
private ViewModelStatus _status = ViewModelStatus.None;
#endregion
#region ViewModel Status
/// <summary> /// 刷新UI数据 /// </summary> public virtual void Refresh() {
}
/// <summary> /// ViewModel状态 /// </summary> public ViewModelStatus Status { get { return _status; } protected set { if (_status != value) { _status = value; RaisePropertyChanged(@"Status"); } } }
#endregion }
ViewModel应用
public class CameraManagementViewModel : ViewModelResponsive { protected override void BindCommands() { RefreshCommand = new RelayCommand(() => { Refresh(); }); }
public override void Refresh() { base.Refresh();
Status = ViewModelStatus.Initializing; CameraCollection.Clear(); Model.GetCameras(GetCamerasCallback); }
private void GetCamerasCallback(object sender, AsyncWorkerCallbackEventArgs<IList<Camera>> args) { CameraCollection.Clear(); Status = ViewModelStatus.Loaded;
if (result) { foreach (var item in (args.Data as IList<Camera>)) { CameraCollection.Add(item); } } } }

|