WPF异步MVVM等待窗体

需求描述

  • 在 ViewModel 中处理 Model 中的数据需要一定时间的等待;
  • ViewModel 或 Model 在获取数据或访问同步服务时有一定延迟需要等待;
  • ViewModel 操作 View 加载数据需要一段时间;

解决办法

  • 显示一个等待 UI,当数据处理完毕或服务接口返回后等待UI消失

转动齿轮控件

等待控件

 1   <Grid>
 2     <local:SprocketControl Grid.Row="0"
 3                            Grid.Column="0"
 4                            Width="100"
 5                            Height="100"
 6                            Margin="0,0,0,0"
 7                            HorizontalAlignment="Center"
 8                            VerticalAlignment="Center"
 9                            Background="Transparent"
10                            Interval="60"
11                            IsIndeterminate="True"
12                            StartAngle="-90"
13                            TickColor="{DynamicResource MaskForegroundColor}"
14                            TickCount="16"
15                            TickWidth="5" />
16   </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 状态转变为控件状态

 1   public class StatusToAnimationVisibilityConverter : IValueConverter
 2   {
 3     #region IValueConverter Members
 4 
 5     public object Convert(
 6       object value, Type targetType, object parameter, CultureInfo culture)
 7     {
 8       try
 9       {
10         string status = value.ToString();
11 
12         switch (status)
13         {
14           case "Initializing":
15           case "Loading":
16           case "Saving":
17             return Visibility.Visible;
18           case "Loaded":
19           case "Saved":
20           default:
21             return Visibility.Collapsed;
22         }
23       }
24       catch (Exception)
25       {
26         return Visibility.Collapsed;
27       }
28     }
29 
30     public object ConvertBack(
31       object value, Type targetType, object parameter, CultureInfo culture)
32     {
33       return DependencyProperty.UnsetValue;
34     }
35 
36     #endregion
37   }

使 UserControl 支持异步显示

 1   <coverters:StatusToAnimationVisibilityConverter x:Key="StatusToAnimationVisibilityConverter" />
 2 
 3   <Style x:Key="AsyncWorkUserControlStyle" TargetType="{x:Type UserControl}">
 4     <Setter Property="Template">
 5       <Setter.Value>
 6         <ControlTemplate TargetType="{x:Type UserControl}">
 7           <Grid>
 8             <ContentPresenter Panel.ZIndex="0" />
 9             <Grid x:Name="animationGrid"
10                   Width="Auto"
11                   Height="Auto"
12                   HorizontalAlignment="Stretch"
13                   VerticalAlignment="Stretch"
14                   Panel.ZIndex="2000"
15                   Visibility="{Binding Path=Status,
16                                Converter={StaticResource StatusToAnimationVisibilityConverter}}">
17               <Grid Width="Auto"
18                     Height="Auto"
19                     HorizontalAlignment="Stretch"
20                     VerticalAlignment="Stretch"
21                     Panel.ZIndex="0"
22                     Background="{DynamicResource MaskGridBackgroundBrush}"
23                     Opacity="0.2" />
24               <ctrl:WaitingControl x:Name="animation" Panel.ZIndex="1" />
25             </Grid>
26           </Grid>
27         </ControlTemplate>
28       </Setter.Value>
29     </Setter>
30   </Style>

应用 Style 至 UserControl

 1 <UserControl x:Class="DeviceConfiguration.Views.CameraManagementView"
 2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6              d:DesignHeight="318"
 7              d:DesignWidth="632"
 8              Style="{DynamicResource AsyncWorkUserControlStyle}"
 9              mc:Ignorable="d">
10 </UserControl>

定义基础 ViewModel

 1   /// <summary>
 2   /// 响应式的ViewModel模型
 3   /// </summary>
 4   public abstract class ViewModelResponsive : ViewModelBase, IViewModelResponsive
 5   {
 6     #region Fields
 7 
 8     private ViewModelStatus _status = ViewModelStatus.None;
 9 
10     #endregion
11     
12     #region ViewModel Status
13 
14     /// <summary>
15     /// 刷新UI数据
16     /// </summary>
17     public virtual void Refresh()
18     {
19 
20     }
21 
22     /// <summary>
23     /// ViewModel状态
24     /// </summary>
25     public ViewModelStatus Status
26     {
27       get
28       {
29         return _status;
30       }
31       protected set
32       {
33         if (_status != value)
34         {
35           _status = value;
36           RaisePropertyChanged(@"Status");
37         }
38       }
39     }
40 
41     #endregion
42   }

ViewModel 应用

 1   public class CameraManagementViewModel : ViewModelResponsive
 2   {
 3     protected override void BindCommands()
 4     {
 5       RefreshCommand = new RelayCommand(() =>
 6       {
 7         Refresh();
 8       });
 9     }
10     
11     public override void Refresh()
12     {
13       base.Refresh();
14 
15       Status = ViewModelStatus.Initializing;
16       CameraCollection.Clear();
17       Model.GetCameras(GetCamerasCallback);
18     }
19     
20     private void GetCamerasCallback(object sender, AsyncWorkerCallbackEventArgs<IList<Camera>> args)
21     {
22       CameraCollection.Clear();
23       Status = ViewModelStatus.Loaded;
24 
25       if (result)
26       {
27         foreach (var item in (args.Data as IList<Camera>))
28         {
29           CameraCollection.Add(item);
30         }
31       }
32     }
33   }

实现效果

posted @ 2013-04-18 08:45  sangmado  阅读(10284)  评论(31编辑  收藏  举报