wpf里面我想用wpfanimatedgif组件显示一个gif,但是因为要等到OnClick的方法执行完才会显示,所以我采用异步的方式去解决,但是貌似添加为异步之后,那个gif就不现实了,但是用同步的方法又打不到效果。
你试试这样写
private async void btnOn_Click(object sender, RoutedEventArgs e)
{
IISStateWaiting.Visibility = Visibility.Visible;
IISStateFailure.Visibility = Visibility.Hidden;
await Task.Run(()=>{}); // 耗时操作
IISStateWaiting.Visibility = Visibility.Hidden;
IISStateFailure.Visibility = Visibility.Visible;
}
应该不可以,因为wpf里面必须等到btnOn_Click整个方法执行完才会有效, await就阻塞了btnOn_Click这个方法
@灬丶: await 的时候就直接返回了,等你代码执行完毕之后再回来继续
@拓拓: 但是Task.Factory.StartNew也差不多的吧,并且.net4.0没有async await
首先应该避免在OnClick事件处理函数中去做任何耗时操作,这是UI线程,UI线程的时间片是很昂贵的,尽可能去做渲染的工作。在UI线程执行耗时操作会严重影响界面的渲染,导致无响应,你说的gif应该是指的忙指示器,肯定也没法渲染。
这样的场景在我们做过的系统中非常普遍,于是封装了一些好用的扩展方法,最常用的是异步线程执行耗时操作并显示忙指示器,异步执行完毕再切换回UI线程执行界面刷新。
using System;
using System.Threading.Tasks;
namespace Frontier.Wif.Utilities.Extensions
{
/// <summary>
/// Defines the <see cref="TaskExtensions" />
/// </summary>
public static class TaskExtensions
{
#region Methods
/// <summary>
/// 延时异步执行方法。
/// </summary>
/// <param name="action">待执行方法</param>
/// <param name="delayTime">延时时间(毫秒)</param>
public static void DelayRun(this Action action, int delayTime)
{
Task.Delay(delayTime).ContinueWith(unusedTask => action());
}
/// <summary>
/// The Run
/// </summary>
/// <param name="workAction">The action<see cref="Action"/></param>
/// <param name="completedAction">The completedAction<see cref="Action"/></param>
/// <param name="runCompletedActionInUIThread">The runCompletedActionInUIThread<see cref="bool"/></param>
/// <returns>The <see cref="Task"/></returns>
public static Task RunAsync(this Action workAction, Action completedAction,
bool runCompletedActionInUIThread = true)
{
var taskScheduler = runCompletedActionInUIThread
? TaskScheduler.FromCurrentSynchronizationContext()
: TaskScheduler.Current;
return Task.Run(workAction).ContinueWith(unusedTask => completedAction(), taskScheduler);
}
/// <summary>
/// The Run
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="workAction">The action<see cref="Action"/></param>
/// <param name="completedFunction">The completedFunction<see cref="Func{TResult}"/></param>
/// <param name="runCompletedActionInUIThread">The runCompletedActionInUIThread<see cref="bool"/></param>
/// <returns>The <see cref="Task{TResult}"/></returns>
public static Task<TResult> RunAsync<TResult>(this Action workAction, Func<TResult> completedFunction,
bool runCompletedActionInUIThread = true)
{
var taskScheduler = runCompletedActionInUIThread
? TaskScheduler.FromCurrentSynchronizationContext()
: TaskScheduler.Current;
return Task.Run(workAction).ContinueWith(unusedTask => completedFunction(), taskScheduler);
}
/// <summary>
/// The Run
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="workFunction">The function<see cref="Func{TResult}"/></param>
/// <param name="completedAction">The completedAction<see cref="Action"/></param>
/// <param name="runCompletedActionInUIThread">The runCompletedActionInUIThread<see cref="bool"/></param>
/// <returns>The <see cref="Task{TResult}"/></returns>
public static Task<TResult> RunAsync<TResult>(this Func<TResult> workFunction, Action<TResult> completedAction,
bool runCompletedActionInUIThread = true)
{
var taskScheduler = runCompletedActionInUIThread
? TaskScheduler.FromCurrentSynchronizationContext()
: TaskScheduler.Current;
var task = Task.Run(workFunction);
task.ContinueWith(unusedTask => completedAction(task.Result), taskScheduler);
return task;
}
/// <summary>
/// The Run
/// </summary>
/// <typeparam name="TWorkResult"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="workFunction">The workFunction<see cref="Func{TWorkResult}"/></param>
/// <param name="completedAction">The completedAction<see cref="Func{TWorkResult, TResult}"/></param>
/// <param name="runCompletedActionInUIThread">The runCompletedActionInUIThread<see cref="bool"/></param>
/// <returns>The <see cref="Task{TResult}"/></returns>
public static Task<TResult> RunAsync<TWorkResult, TResult>(this Func<TWorkResult> workFunction,
Func<TWorkResult, TResult> completedAction,
bool runCompletedActionInUIThread = true)
{
var taskScheduler = runCompletedActionInUIThread
? TaskScheduler.FromCurrentSynchronizationContext()
: TaskScheduler.Current;
return Task.Run(workFunction).ContinueWith(workTask => completedAction(workTask.Result), taskScheduler);
}
/// <summary>
/// The Run
/// </summary>
/// <param name="workTask">The workTask<see cref="Task"/></param>
/// <param name="completedAction">The completedAction<see cref="Action"/></param>
/// <param name="runCompletedActionInUIThread">The runCompletedActionInUIThread<see cref="bool"/></param>
/// <returns>The <see cref="Task"/></returns>
public static Task RunAsync(this Task workTask, Action completedAction,
bool runCompletedActionInUIThread = true)
{
var taskScheduler = runCompletedActionInUIThread
? TaskScheduler.FromCurrentSynchronizationContext()
: TaskScheduler.Current;
if (workTask.Status == TaskStatus.Created)
workTask.Start();
return workTask.ContinueWith(unusedTask => completedAction(), taskScheduler);
}
#endregion
}
}
代码来自我的一个开源项目wif ,里边有大量的扩展。
谢谢了
_mainViewModel.BusyContent = "体积计算中...";
_mainViewModel.IsIndeterminate = true;
_mainViewModel.IsBusy = true;
TaskExtensions.RunAsync(() =>
{
//TODO 耗时操作,如体积计算
}, () =>
{
_mainViewModel.IsBusy = false;
});
调用方式
@楚人Leo: 好的我,我试下
@楚人Leo: 耗时的操作不应该
放在ContinueWith里面吗?
@灬丶:
Task.Run(workAction).ContinueWith(unusedTask => completedAction(), taskScheduler);
Task.Run和ContinueWith默认都是从线程池取一个线程执行操作,只是这里ContinueWith是通过taskScheduler切换到UI线程,所以ContinueWith实际上已经是UI线程了。
TaskScheduler.FromCurrentSynchronizationContext()
通过这行代码拿到UI线程同步上下文。
@楚人Leo: 嗯嗯,谢了