【6月日新计划18】WPF入门-DialogContent

274 阅读5分钟

【6月日新计划18】WPF入门-DialogContent

當我們加載數據的時間,稍微有點長的時候,我們需要有一個加載動畫來緩解此時的尷尬

也就是主頁MainWindow裡面的DialogHost添加一個DiaglogContent

1. 虚方法和抽象方法

  • 虚方法就是以virtual关键字修饰并在一个或多个派生类中实现的方法,子类重写的虚方法则以override关键字标记。虚方法调用,是在运行时确定根据其调用对象的类型来确定调用适当的覆写方法。.NET默认是非虚方法,如果一个方法被virtual标记,则不可再被static、abstrcat和override修饰。

  • 抽象方法就是以abstract关键字修饰的方法,抽象方法可以看作是没有实现体的虚方法,并且必须在派生类中被覆写,如果一个类包括抽象方法,则该类就是一个抽象类。因此,抽象方法其实隐含为虚方法,只是在声明和调用语法上有所不同。abstract和virtual一起使用是错误的。

1.1 虚方法

概念:使用关键词Virtual创建的方法称为虚方法

   用法:将关键词Virtual添加到方法的返回类型的前面

   模样:public virtual void Method(int i) { }

   特点:1.方法定义后面必须有“{}”,可以有实现体,也就是说“{}”里可以有实现体也可以没有。

          2.可以定义在除密封类的所有类中。

          3.虚方法在派生类中可以被重写也可以不被重写

 

1.2 抽象方法

   概念: 使用关键词abstract创建的方法称为抽象方法.

   用法: 将关键字 abstract 添加到方法的返回类型的前面.

   模样: public abstract void Method(int i);

   特点: 1.(必须)没有实现体,方法定义后面是分号”;”

         2.抽象方法必须定义在抽象类中

         3.抽象方法在派生类中必须被重写

         4.存在抽象方法的类必须定义成抽象类

2. 延時

常用方法,但是WPF頁面會假死。基本不要用

System.Threading.Thread.Sleep()

優雅的延時

Task.Delay(你需要等待的时间);

異步等待

await Task.Delay(你需要等待的时间);

3. RestSharp呼叫api

3.1 使用擴展組件RestSharp

官方提供的基本操作

//1.直接帶請求路徑,寫死
var client = new RestClient("http://example.com");
// client.Authenticator = new HttpBasicAuthenticator(username, password);

//2.也可以把請求路徑傳參,將url註冊到app.xaml.cs
var client = new RestClient();
string url = "https://api.openweathermap.org/";
client.BaseUrl = new Uri(url);

//3.拼接url,傳參
var request = new RestRequest("resource/{id}", Method.POST);
request.AddParameter("name", "value"); 
request.AddUrlSegment("id", "123"); 


//4. add HTTP Headers
request.AddHeader("header", "value");

//5. add files to upload (works with compatible verbs)
request.AddFile("file", path);

//6. execute the request
IRestResponse response = client.Execute(request);
var content = response.Content; 

//7.泛型
IRestResponse<Person> response2 = client.Execute<Person>(request);
var name = response2.Data.Name;


// 8.easy async support
await client.ExecuteAsync(request);

// async with deserialization
var response = await client.ExecuteAsync(request);
System.Diagnostics.Trace.WriteLine("------Client執行結果 :" + response.Content);
if (response.StatusCode == System.Net.HttpStatusCode.OK) 
     return JsonConvert.DeserializeObject<Weather=這是要轉換的類型>(response.Content);

// abort the request on demand
asyncHandle.Abort();

對第二個的補充,註冊host

图片.png

3.2 封裝RestSharp

先註冊url(app.xaml.cs)

    public partial class App
    {

        //打印log
        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        
        protected override Window CreateShell()
        {
            //ui线程未捕获的异常
            DispatcherUnhandledException += OnDispatcherUnhandledException;
            //Task线程未捕获的异常
            TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
            //多线程异常
            AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;

            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {


            //將host進行註冊
            containerRegistry.GetContainer().Register<HttpRestClient>(made: Parameters.Of.Type<string>(serviceKey: "url"));
            containerRegistry.GetContainer().RegisterInstance(@"https://api.openweathermap.org/", serviceKey: "url");

            //將呼叫方法的service進行註冊
            containerRegistry.Register<IWeatherService, WeatherService>();


            //將view和viewModel捆綁,已經註冊。
            containerRegistry.RegisterForNavigation<ToDoView,ToDoViewModel>();
            containerRegistry.RegisterForNavigation<OlkView,OLKViewModel>();
            containerRegistry.RegisterForNavigation<IndexView,IndexViewModel>();
            containerRegistry.RegisterForNavigation<CustomView, CustomViewModel>();
            containerRegistry.RegisterForNavigation<WeatherView, WeatherViewModel>();

        }

        private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            logger.Info($"{e.Exception.StackTrace},{e.Exception.Message}");
        }

        private void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
        {
            logger.Info($"{e.Exception.StackTrace},{e.Exception.Message}");
        }

        private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Exception ex = e.ExceptionObject as Exception;
            logger.Info($"{ex.StackTrace},{ex.Message}");
        }

    }

HttpRestClient

using BlankApp1.Common.Models;
using BlankApp1.Common.Models.Weather;
using Newtonsoft.Json;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BlankApp1.Service
{
    public class HttpRestClient
    {

        private readonly string url;

        protected readonly RestClient client;

        public HttpRestClient(string url)
        {

            this.url = url;
            client = new RestClient(url);
        }

        public async Task<T> ExecuteAsync<T>(BaseRequest baseRequest)
        {
            var request = new RestRequest(baseRequest.Method);
            request.AddHeader("Content-Type", baseRequest.ContentType);

            if (baseRequest.Parameter != null)
            {
                request.AddParameter("param", JsonConvert.SerializeObject(baseRequest.Parameter), ParameterType.RequestBody);
            }

            client.BaseUrl = new Uri(url + baseRequest.Route);
            var response = await client.ExecuteAsync(request);

            System.Diagnostics.Trace.WriteLine("---------Client執行結果 :" + response.Content);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                System.Diagnostics.Trace.WriteLine("---------將結果封裝---------------");
                return JsonConvert.DeserializeObject<T> (response.Content);
            }
            else
                return default(T);
        }


        public async Task<Weather> ExecuteAsync01(BaseRequest baseRequest)
        {
            var request = new RestRequest(baseRequest.Method);
            request.AddHeader("Content-Type", baseRequest.ContentType);

            if (baseRequest.Parameter != null)
            {
                request.AddParameter("param", JsonConvert.SerializeObject(baseRequest.Parameter), ParameterType.RequestBody);
            }

            client.BaseUrl = new Uri(url + baseRequest.Route);
            var response = await client.ExecuteAsync(request);
            System.Diagnostics.Trace.WriteLine("---------Client執行結果 :" + response.Content);

            if (response.StatusCode == System.Net.HttpStatusCode.OK) 
                return JsonConvert.DeserializeObject<Weather>(response.Content);
            else 
                return new Weather(){ };

        }

    }
}

封裝基礎方法

namespace BlankApp1.Service
{
    public interface IBaseService<TEntity> where TEntity : class
    {
        Task<TEntity> AddAsync(TEntity entity);

        Task<Weather> GetWeatherAsync(WeatherParameter parameter);

        Task<TEntity> GetCurrentWeatherAsync(WeatherParameter parameter);
    }
}
using BlankApp1.Common.Models.Weather;
using BlankApp1.Service.Shared;
using RestSharp;
using System;
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BlankApp1.Service
{
    public class BaseService<TEntity> : IBaseService<TEntity> where TEntity : class
    {
        private readonly HttpRestClient client;
        private readonly string serviceName;

        public BaseService(HttpRestClient client, string serviceName)
        {
            this.client = client;
            this.serviceName = serviceName;
        }

        public async Task<TEntity> AddAsync(TEntity entity)
        {
            BaseRequest request = new BaseRequest();
            request.Method = RestSharp.Method.POST;
            request.Route = $"api/{serviceName}/Add";
            request.Parameter = entity;
            return await client.ExecuteAsync<TEntity>(request);
        }


        public async Task<Weather> GetWeatherAsync(WeatherParameter parameter)
        {
            System.Diagnostics.Trace.WriteLine("-----提示信息: 開始執行查詢方法!" );
            BaseRequest request = new BaseRequest();
            request.Method = RestSharp.Method.GET;
            
            request.Route = $"data/2.5/forecast?q={parameter.Query}" +
                $"&appid={parameter.AppId}";
            System.Diagnostics.Trace.WriteLine("---------输出信息Router :" + request.Route);
            return await client.ExecuteAsync01(request);
        }

        public async Task<TEntity> GetCurrentWeatherAsync(WeatherParameter parameter)
        {
            BaseRequest request = new BaseRequest();
            request.Method = RestSharp.Method.GET;
            request.Route = $"data/2.5/weather?q={parameter.Query}" +
                $"&appid={parameter.AppId}";
            System.Diagnostics.Trace.WriteLine("---------输出信息:" + request.Route);
            return await client.ExecuteAsync<TEntity>(request);
        }
    }
}

View對應的方法

namespace BlankApp1.Service
{
    public interface IWeatherService : IBaseService<Weather>
    {

        string GetCurrentWeather3(WeatherParameter parameter);
    }
}
using BlankApp1.Common.Models.Weather;
using BlankApp1.Service.Shared;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;

namespace BlankApp1.Service
{
    public class WeatherService : BaseService<Weather>, IWeatherService
    {
        private readonly HttpRestClient client;
        public WeatherService(HttpRestClient client) : base(client, "Weather")
        {
            this.client = client;
        }

        public Task<CurrentWeather> AddAsync(CurrentWeather entity)
        {
            throw new NotImplementedException();
        }

        async Task<Weather> IBaseService<Weather>.GetWeatherAsync(WeatherParameter parameter)
        {
            System.Diagnostics.Trace.WriteLine("---------提示信息: 開始執行查詢方法!");
            BaseRequest request = new BaseRequest();
            request.Method = RestSharp.Method.GET;

            request.Route = $"data/2.5/forecast?q={parameter.Query}" +
                $"&appid={parameter.AppId}";
            System.Diagnostics.Trace.WriteLine("---------输出信息Router :" + request.Route);
            return await client.ExecuteAsync01(request);

        }

        public string GetCurrentWeather3(WeatherParameter parameter)
        {

            var client = new RestClient();
            string url = "https://api.openweathermap.org/data/2.5/forecast?q=DongGuan&appid=xxxxxxx";
            client.BaseUrl = new Uri(url);

            var request = new RestRequest();
            request.Method = RestSharp.Method.GET;
            Task<IRestResponse> response = client.ExecuteAsync(request);
            return response.Result.Content;
        }

        async Task<Weather> IBaseService<Weather>.GetCurrentWeatherAsync(WeatherParameter parameter)
        {
            System.Diagnostics.Trace.WriteLine("---------输出信息:開始執行");
            BaseRequest request = new BaseRequest();
            request.Method = RestSharp.Method.GET;
            request.Route = $"data/2.5/weather?q={parameter.Query}" +
                $"&appid={parameter.AppId}";
            System.Diagnostics.Trace.WriteLine("---------Route Msg:" + request.Route);
            return await client.ExecuteAsync<Weather>(request);
        }
    }
}

ViewModel直接調用就好

using BlankApp1.Common.Models.Config;
using BlankApp1.Common.Models.Weather;
using BlankApp1.Service;
using BlankApp1.Service.Shared;
using Newtonsoft.Json;
using NLog;
using Prism.Ioc;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.SqlTypes;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace BlankApp1.ViewModels.Config
{
    public class WeatherViewModel : BindableBase
    {
        private readonly IWeatherService _weatherService;

        private ObservableCollection<MainDto> mainList;

        public ObservableCollection<MainDto> MainList
        {
            get { return mainList; }
            set { mainList = value; }
        }

        private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        public WeatherViewModel(IWeatherService weatherService, IContainerProvider provider) : base(provider)
        {
            this._weatherService = weatherService;
            MainList = new ObservableCollection<MainDto>();
            queryWeathers();
        }

        public async void QueryWeathers()
        {
            //直接呼叫方法
            var currentWeather = await _weatherService.GetWeatherAsync(new WeatherParameter() { Query = "DongGuan" });

            //獲取屬性
            var result = currentWeather.GetType().GetProperty("List").GetValue(currentWeather, null);
            ObservableCollection<ListDto> allWeather = (ObservableCollection<ListDto>)result;
            foreach (var item in allWeather)
            {
                await Task.Delay(20);
                System.Diagnostics.Trace.WriteLine("------睡了一覺:0.02s");

                var weatherParameter = item.GetType().GetProperty("Main").GetValue(item, null);
                System.Diagnostics.Trace.WriteLine("---------查看結果:" + weatherParameter.GetType().GetProperty("Temp").GetValue(weatherParameter, null));

                MainList.Add((MainDto)weatherParameter);
            }
        }
    }
}

4. 加載動畫

先寫一個類,是否展開窗口

namespace BlankApp1.Common.Animations
{
    public class UpdateModel
    {
        public bool IsOpen { get; set; }
    }

    public class UpdateLoadingEvent : PubSubEvent<UpdateModel>
    {

    }
}

彈窗的基類

using BlankApp1.Common;
using BlankApp1.Common.Animations;
using Prism.Events;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BlankApp1.Extensions
{
    public static class DialogExtension
    {
        /// <summary>
        /// 询问窗口
        /// </summary>
        /// <param name="dialogHost">指定的DialogHost会话主机</param>
        /// <param name="title">标题</param>
        /// <param name="content">询问内容</param>
        /// <param name="dialogHostName">会话主机名称(唯一)</param>
        /// <returns></returns>
        public static async Task<IDialogResult> Question(this IDialogHostService dialogHost,
            string title, string content, string dialogHostName = "Root"
            )
        {
            DialogParameters param = new DialogParameters();
            param.Add("Title", title);
            param.Add("Content", content);
            param.Add("dialogHostName", dialogHostName);
            var dialogResult = await dialogHost.ShowDialog("MsgView", param, dialogHostName);
            return dialogResult;
        }

        /// <summary>
        /// 推送等待消息
        /// </summary>
        /// <param name="aggregator"></param>
        /// <param name="model"></param>
        public static void UpdateLoading(this IEventAggregator aggregator, UpdateModel model)
        {
            aggregator.GetEvent<UpdateLoadingEvent>().Publish(model);
        }

        /// <summary>
        /// 注册等待消息
        /// </summary>
        /// <param name="aggregator"></param>
        /// <param name="action"></param>
        public static void Register(this IEventAggregator aggregator, Action<UpdateModel> action)
        {
            aggregator.GetEvent<UpdateLoadingEvent>().Subscribe(action);
        }

        /// <summary>
        /// 注册提示消息 
        /// </summary>
        /// <param name="aggregator"></param>
        /// <param name="action"></param>
        public static void RegisterMessage(this IEventAggregator aggregator,
            Action<MessageModel> action, string filterName = "Main")
        {
            aggregator.GetEvent<MessageEvent>().Subscribe(action,
                ThreadOption.PublisherThread, true, (m) =>
                {
                    return m.Filter.Equals(filterName);
                });
        }

        /// <summary>
        /// 发送提示消息
        /// </summary>
        /// <param name="aggregator"></param>
        /// <param name="message"></param>
        public static void SendMessage(this IEventAggregator aggregator, string message, string filterName = "Main")
        {
            aggregator.GetEvent<MessageEvent>().Publish(new MessageModel()
            {
                Filter = filterName,
                Message = message,
            });
        }
    }
}
using BlankApp1.Extensions;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BlankApp1.ViewModels
{
    public class NavigationViewModel : BindableBase, INavigationAware
    {
        public readonly IContainerProvider containerProvider;

        public readonly IEventAggregator aggregator;

        public NavigationViewModel(IContainerProvider containerProvider) {
            this.containerProvider = containerProvider;
            aggregator = containerProvider.Resolve<IEventAggregator>();
        }

        /// <summary>
        /// 是否重用窗口
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public virtual bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        public virtual void OnNavigatedFrom(NavigationContext navigationContext)
        {
           
        }

        public virtual void OnNavigatedTo(NavigationContext navigationContext)
        {
            
        }

        public void UpdateLoading(bool IsOpen)
        {
            aggregator.UpdateLoading(new Common.Animations.UpdateModel()
            {
                IsOpen = IsOpen
            });
        }
    }
}

在主窗口註冊

图片.png

    public partial class MainWindow : Window
    {
        public MainWindow(IEventAggregator aggregator)
        {
            InitializeComponent();

            //註冊
            aggregator.Register(arg => {

                DialogHost.IsOpen = arg.IsOpen;

                if (DialogHost.IsOpen) {
                    //後面是要顯示的動畫
                    DialogHost.DialogContent = new LoadingAnimation01();

                }
            });
         

            MenuBar.SelectionChanged += (s, e) =>
            {
                DrawerHost.IsLeftDrawerOpen = false;
            };

            btnMin.Click += (s, e) =>
            {
                this.WindowState = WindowState.Minimized;
            };


            btnMax.Click += (s, e) =>
            {
                if (this.WindowState == WindowState.Maximized)
                {
                    this.WindowState = WindowState.Normal;
                }
                else 
                {
                    this.WindowState = WindowState.Maximized; 
                }
                 
            };

            btnPower.Click += (s, e) =>
            {
                this.Close();
            };

            ColorZone.MouseMove += (s, e) => { 
                
                if(e.LeftButton == MouseButtonState.Pressed)
                    this.DragMove();
            };
        }
    }

兩個動畫,LoadAnimation和LoadingAnimation01

<UserControl
    x:Class="BlankApp1.Views.Extention.LoadingAnimation"
    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:local="clr-namespace:BlankApp1.Views.Extention"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">
    <StackPanel
        Width="150"
        Height="150"
        HorizontalAlignment="Center"
        VerticalAlignment="Center">
        <materialDesign:Card
            Width="90"
            Height="90"
            Padding="6"
            UniformCornerRadius="25">
            <ProgressBar
                Width="50"
                Height="50"
                IsIndeterminate="True"
                Style="{StaticResource MaterialDesignCircularProgressBar}"
                Value="40" />
        </materialDesign:Card>
    </StackPanel>
</UserControl>
<UserControl x:Class="BlankApp1.Views.Extention.LoadingAnimation01"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:BlankApp1.Views.Extention"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <Style x:Key="FlashStyle"
               TargetType="{x:Type FrameworkElement}">
            <Style.Triggers>
                <EventTrigger RoutedEvent="Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(FrameworkElement.Opacity)"
                                             BeginTime="00:00:00"
                                             From="1"
                                             To="0"
                                             Duration="00:00:01.5"
                                             AutoReverse="True"
                                             RepeatBehavior="Forever" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Style.Triggers>
        </Style>
        <Storyboard x:Key="StoryLeftToRight"
                    RepeatBehavior="Forever"
                    Duration="00:00:01.5">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                           Storyboard.TargetName="e1"
                                           Storyboard.TargetProperty="(FrameworkElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00.0"
                                      Value="1" />
                <SplineDoubleKeyFrame KeyTime="00:00:00.5"
                                      Value="0" />
                <SplineDoubleKeyFrame KeyTime="00:00:01.0"
                                      Value="0" />
                <SplineDoubleKeyFrame KeyTime="00:00:01.5"
                                      Value="0" />
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                           Storyboard.TargetName="e2"
                                           Storyboard.TargetProperty="(FrameworkElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00.0"
                                      Value="0" />
                <SplineDoubleKeyFrame KeyTime="00:00:00.5"
                                      Value="1" />
                <SplineDoubleKeyFrame KeyTime="00:00:01.0"
                                      Value="0" />
                <SplineDoubleKeyFrame KeyTime="00:00:01.5"
                                      Value="0" />
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                           Storyboard.TargetName="e3"
                                           Storyboard.TargetProperty="(FrameworkElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00.0"
                                      Value="0" />
                <SplineDoubleKeyFrame KeyTime="00:00:00.5"
                                      Value="0" />
                <SplineDoubleKeyFrame KeyTime="00:00:01.0"
                                      Value="1" />
                <SplineDoubleKeyFrame KeyTime="00:00:01.5"
                                      Value="0" />
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
                                           Storyboard.TargetName="e4"
                                           Storyboard.TargetProperty="(FrameworkElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00.0"
                                      Value="0" />
                <SplineDoubleKeyFrame KeyTime="00:00:00.5"
                                      Value="0" />
                <SplineDoubleKeyFrame KeyTime="00:00:01.0"
                                      Value="0" />
                <SplineDoubleKeyFrame KeyTime="00:00:01.5"
                                      Value="1" />
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </UserControl.Resources>

    <Grid Background="DeepSkyBlue">
        <StackPanel Orientation="Horizontal"
                    Margin="20"
                    VerticalAlignment="Bottom"
                    HorizontalAlignment="Right">
            <TextBlock Text="Loading "
                       Style="{StaticResource FlashStyle}"
                       Foreground="White"
                       FontSize="20" />
            <StackPanel Orientation="Horizontal">
                <StackPanel.Triggers>
                    <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                        <BeginStoryboard Storyboard="{StaticResource StoryLeftToRight}" />
                    </EventTrigger>
                </StackPanel.Triggers>
                <Ellipse Name="e1"
                         Width="5"
                         Height="5"
                         Margin="5,0,0,0"
                         HorizontalAlignment="Left"
                         Fill="White" />
                <Ellipse Name="e2"
                         Width="5"
                         Height="5"
                         Margin="5,0,0,0"
                         HorizontalAlignment="Left"
                         Fill="White" />
                <Ellipse Name="e3"
                         Width="5"
                         Height="5"
                         Margin="5,0,0,0"
                         HorizontalAlignment="Left"
                         Fill="White" />
                <Ellipse Name="e4"
                         Width="5"
                         Height="5"
                         Margin="5,0,0,0"
                         HorizontalAlignment="Left"
                         Fill="White" />
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>

最後修改Viewmodel,傳一個容器

namespace BlankApp1.ViewModels.Config
{
    public class WeatherViewModel : NavigationViewModel
    {
        private readonly IWeatherService _weatherService;

        private ObservableCollection<MainDto> mainList;

        public ObservableCollection<MainDto> MainList
        {
            get { return mainList; }
            set { mainList = value; }
        }

        private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        public WeatherViewModel(IWeatherService weatherService, IContainerProvider provider) : base(provider)
        {
            this._weatherService = weatherService;
            MainList = new ObservableCollection<MainDto>();
            //queryWeathers();
        }

        public async void QueryWeathers()
        {

            UpdateLoading(true);

            var currentWeather = await _weatherService.GetWeatherAsync(new WeatherParameter() { Query = "DongGuan" });

            //獲取屬性
            var result = currentWeather.GetType().GetProperty("List").GetValue(currentWeather, null);
            ObservableCollection<ListDto> allWeather = (ObservableCollection<ListDto>)result;
            foreach (var item in allWeather)
            {
                await Task.Delay(20);
                System.Diagnostics.Trace.WriteLine("------睡了一覺:0.02s");

                var weatherParameter = item.GetType().GetProperty("Main").GetValue(item, null);
                System.Diagnostics.Trace.WriteLine("---------查看結果:" + weatherParameter.GetType().GetProperty("Temp").GetValue(weatherParameter, null));

                MainList.Add((MainDto)weatherParameter);
            }

            UpdateLoading(false);

        }

        public override void OnNavigatedTo(NavigationContext navigationContext)
        {
            base.OnNavigatedTo(navigationContext);
            QueryWeathers();
        }
    }
}